我正在编写一个flex / yacc程序,它应该使用cygwin读取一些令牌和简单的语法。 我猜测我的BNF语法有问题,但我似乎无法找到问题所在。下面是一些代码
%start statement_list
%%
statement_list: statement
|statement_list statement
;
statement: condition|simple|loop|call_func|decl_array|decl_constant|decl_var;
call_func: IDENTIFIER'('ID_LIST')' {printf("callfunc\n");} ;
ID_LIST: IDENTIFIER
|ID_LIST','IDENTIFIER
;
simple: IDENTIFIER'['NUMBER']' ASSIGN expr
|PRINT STRING
|PRINTLN STRING
|RETURN expr
;
bool_expr: expr E_EQUAL expr
|expr NOT_EQUAL expr
|expr SMALLER expr
|expr E_SMALLER expr
|expr E_LARGER expr
|expr LARGER expr
|expr E_EQUAL bool
|expr NOT_EQUAL bool
;
expr: expr ADD expr {$$ = $1+$3;}
| expr MULT expr {$$ = $1-$3;}
| expr MINUS expr {$$ = $1*$3;}
| expr DIVIDE expr {if($3 == 0) yyerror("divide by zero");
else $$ = $1 / $3;}
|expr ASSIGN expr
| NUMBER
| IDENTIFIER
;
bool: TRUE
|FALSE
;
decl_constant: LET IDENTIFIER ASSIGN expr
|LET IDENTIFIER COLON "bool" ASSIGN bool
|LET IDENTIFIER COLON "Int" ASSIGN NUMBER
|LET IDENTIFIER COLON "String" ASSIGN STRING
;
decl_var: VAR IDENTIFIER
|VAR IDENTIFIER ASSIGN NUMBER
|VAR IDENTIFIER ASSIGN STRING
|VAR IDENTIFIER ASSIGN bool
|VAR IDENTIFIER COLON "Bool" ASSIGN bool
|VAR IDENTIFIER COLON "Int" ASSIGN NUMBER
|VAR IDENTIFIER COLON "String" ASSIGN STRING
;
decl_array: VAR IDENTIFIER COLON "Int" '[' NUMBER ']'
|VAR IDENTIFIER COLON "Bool" '[' NUMBER ']'
|VAR IDENTIFIER COLON "String" '[' NUMBER ']'
;
condition: IF '(' bool_expr ')' statement ELSE statement;
loop: WHILE '(' bool_expr ')' statement;
我已尝试将声明更改为
statement:';';
,阅读一个简单的令牌来测试它是否有效,但似乎我的代码拒绝输入该部分语法。
当我编译它时,它告诉我有18个移位/减少冲突。我应该尝试找到并解决所有问题吗?
编辑:我使用Chris Dodd的答案编辑了我的代码,尝试通过查看输出文件来解决每个冲突。最后几个冲突似乎位于下面的代码中。expr: expr ADD expr {$$ = $1+$3;}
| expr MULT expr {$$ = $1-$3;}
| expr MINUS expr {$$ = $1*$3;}
| expr DIVIDE expr {if($3 == 0) yyerror("divide by zero");
else $$ = $1 / $3;}
|expr ASSIGN expr
| NUMBER
| IDENTIFIER
;
这是输出文件的一部分,告诉我什么是错的。
state 60
28 expr: expr . ADD expr
29 | expr . MULT expr
30 | expr . MINUS expr
31 | expr . DIVIDE expr
32 | expr . ASSIGN expr
32 | expr ASSIGN expr .
ASSIGN shift, and go to state 36
ADD shift, and go to state 37
MINUS shift, and go to state 38
MULT shift, and go to state 39
DIVIDE shift, and go to state 40
ASSIGN [reduce using rule 32 (expr)]
ADD [reduce using rule 32 (expr)]
MINUS [reduce using rule 32 (expr)]
MULT [reduce using rule 32 (expr)]
DIVIDE [reduce using rule 32 (expr)]
$default reduce using rule 32 (expr)
我不明白,为什么在阅读ADD,MULT,DIVIDE或其他令牌时会选择规则32?这部分语法有什么问题?
另外,即使语法的上述部分是错误的,我的编译器是否应该能够正确读取其他语法?例如,
let a = 5
应该是可读的,但程序返回语法错误?
答案 0 :(得分:1)
你的语法看起来很合理,虽然它在表达式中确实存在歧义,其中大多数都可以通过优先级来解决。你一定要查看 ALL 报告的冲突并理解它们发生的原因,并且最好改变语法来摆脱它们。
至于您的具体问题,如果您将其更改为statement: ';' ;
,则应接受该问题。您没有显示任何lexing代码,因此可能存在问题。使用-DYYDEBUG=1
编译解析器以启用yacc / bison生成的调试代码,并在调用yydebug
之前将全局变量yyparse
设置为1可能会有所帮助,这将转储跟踪解析器对stderr所做的一切。