为什么这个语法不解析 return 语句?

Why doesn't this grammar parse the return statement?

我正在尝试编写可以解析以下 3 个输入的语法

-- testfile --
class hi implements ho:
    var x:int;
end;

-- testfile2 --
interface xs:
  myFunc(int,int):int
end;

-- testfile3 --
class hi implements ho:
    method myMethod(x:int)
      return y;
    end
end;

这是lexer.l:

%{
#include <stdio.h>
#include <stdlib.h>
#include "parser.tab.h"
#include <string.h>

int line_number = 0;
void lexerror(char *message);
%}

newline         (\n|\r\n)
whitespace      [\t \n\r]*
digit           [0-9]
alphaChar       [a-zA-Z]
alphaNumChar    ({digit}|{alphaChar})
hexDigit        ({digit}|[A-Fa-f])
decNum          {digit}+
hexNum          {digit}{hexDigit}*H
identifier      {alphaChar}{alphaNumChar}*
number          ({hexNum}|{decNum})
comment         "/*"[.\r\n]*"*/"
anything        .
%s InComment
%option noyywrap
%%
<INITIAL>{
interface       return INTERFACE;
end             return END;
class           return CLASS;
implements      return IMPLEMENTS;
var             return VAR;
method          return METHOD;
int             return INT;
return          return RETURN;
if              return IF;
then            return THEN;
else            return ELSE;
while           return WHILE;
do              return DO;
not             return NOT;
and             return AND;
new             return NEW;
this            return THIS;
null            return _NULL;
":"             return COL;
";"             return SCOL;
"("             return BRACL;
")"             return BRACR;
"."             return DOT;
","             return COMMA;
"="             return ASSIGNMENT;
"+"             return PLUS;
"-"             return MINUS;
"*"             return ASTERISK;
"<"             return LT;


{decNum}        {
                    yylval = atoi(yytext);
                    return DEC; 
                }
{hexNum}        {
                    const int len = strlen(yytext)-1;
                    char* substr = (char*) malloc(sizeof(char) * len);
                    strncpy(substr,yytext,len);
                    yylval = (int)strtol
                            ( substr
                            , NULL
                            , 16);
                    free (substr);
                    return HEX;
                }
{identifier}    {
                    yylval= (char *) malloc(sizeof(char)*strlen(yytext));
                    strcpy(yylval, yytext);
                    return ID; 
                }
{whitespace}    {}
"/*"        BEGIN InComment;
}
{newline}       line_number++;
<InComment>{
"*/"            BEGIN INITIAL;
{anything}      {}
}
.               lexerror("Illegal input");

%%

void lexerror(char *message)
{
   fprintf(stderr,"Error: \"%s\" in line %d. = %s\n",
           message,line_number,yytext);
   exit(1);
}

这是 parser.y:

%{
# include <stdio.h>

int yylex(void);
void yyerror(char *);
extern int line_number;
%}

%start Program

%token INTERFACE END CLASS IMPLEMENTS VAR METHOD INT RETURN IF THEN ELSE
%token WHILE DO NOT AND NEW THIS _NULL EOC SCOL COL BRACL BRACR DOT COMMA 
%token ASSIGNMENT PLUS ASTERISK MINUS LT EQ DEC HEX ID NEWLINE


%% 
Program: INTERFACE Interface SCOL      { printf("interface\n"); }
       | CLASS Class SCOL          { printf("class\n");} 
       | error { printf("error on: %s\n", $$); }
       ;  
 
Interface: ID COL 
             AbstractMethod  
           END
         ;  


AbstractMethod: ID BRACL Types BRACR COL Type
              ;

Types : Type COMMA Types
      | Type 
      ;

Class: ID 
       IMPLEMENTS ID COL
         Member SCOL 
       END  
     ;  
 
Member: VAR ID COL Type  
      | METHOD ID BRACL Pars BRACR Stats END
      ;  
 
Type: INT  
    | ID 
    ;  
 
Pars: Par COMMA Pars
    | Par
    ;  
 
Par: ID COL Type 
   ;  
 
Stats: Stat SCOL Stat
     | Stat
     ;  
 
Stat: RETURN Expr  
    | IF Expr THEN Stats MaybeElse END  
    | WHILE Expr DO Stats END  
    | VAR ID COL Type COL ASSIGNMENT Expr
    | ID COL ASSIGNMENT Expr 
    | Expr        
    ;  

MaybeElse : 
          | ELSE Stats
          ;

Expr: NOT Term  
    | NEW ID 
    | Term PLUS Term 
    | Term ASTERISK Term
    | Term AND Term
    | Term ArithOp Term  
    | Term
    ;  

ArithOp: MINUS
       | LT
       | ASSIGNMENT
       ;

Term: BRACL Expr BRACR
    | Num
    | THIS  
    | ID 
    | Term DOT ID BRACL Exprs BRACR
    | error { printf("error in term: %s\n", $$); }
    ;

Num : HEX
    | INT
    ;

Exprs : Expr COMMA Exprs
      | Expr
      ;

%%
void yyerror(char *s) {
    fprintf(stderr, "Parse Error on line %i: %s\n", line_number, s);
}

int main(void){
    yyparse();
}

前两个输入按预期识别,

但是,第三个失败并显示错误 error on: y,我不知道为什么。

在我看来,这应该是一个 Class 和一个 Member METHOD 包含一个 Stat(ement) RETURN 和一个 Expr TermID.

我尝试评论并删除所有不必要的位,但结果仍然相同。 我还查看了解析器以验证我的标识符是否正确解析,但正如我所见,它们应该正确解析。

为什么return y中的y在这里不被识别? 是否存在我不知道的语法冲突?

(请注意,我不希望您修复完整的语法;我只是在询问这不起作用的原因。我确信那里还有其他错误,但我真的很难修复这个.)

这也是我的 makefile:

CC    = gcc
LEX   = flex 
YAC   = bison

scanner: parser.y lexer.l
    $(YAC) -d -Wcounterexamples parser.y
    $(LEX) lexer.l
    $(CC)  parser.tab.c parser.tab.h lex.yy.c -o parser

clean:
    rm -f *.tab.h *.tab.c *.gch *.yy.c
    rm ./parser

测试:

cat testfile3 | ./parser

首先你的语法有一个错误:

Stats: Stat SCOL Stat
     | Stat
     ;  

必须

Stats: Stat SCOL Stats
     | Stat
     ;  
 

('s' 添加在行尾)

其次,您在 testfile3 中的定义不符合您的语法,必须是

class hi implements ho:
    method myMethod(x:int)
      return y
    end;
end;

所以 ';' return y 之后必须移到第一个 end

之后

(而return x似乎更符合逻辑,但这是另外一门学科,您不检查ID的有效性)


其中一个 class 只能有一个成员,这是非常有限/限制性的