为什么我的 "equation" 语法会破坏解析器?
Why does my "equation" grammar break the parser?
目前,我的解析器文件如下所示:
%{
#include <stdio.h>
#include <math.h>
int yylex();
void yyerror (const char *s);
%}
%union {
long num;
char* str;
}
%start line
%token print
%token exit_cmd
%token <str> identifier
%token <str> string
%token <num> number
%%
line: assignment {;}
| exit_stmt {;}
| print_stmt {;}
| line assignment {;}
| line exit_stmt {;}
| line print_stmt {;}
;
assignment: identifier '=' number {printf("Assigning var %s to value %d\n", , );}
| identifier '=' string {printf("Assigning var %s to value %s\n", , );}
;
exit_stmt: exit_cmd {exit(0);}
;
print_stmt: print print_expr {;}
;
print_expr: string {printf("%s\n", );}
| number {printf("%d\n", );}
;
%%
int main(void)
{
return yyparse();
}
void yyerror (const char *s) {fprintf(stderr, "%s\n", s);}
给出输入:myvar = 3
给出输出 Assigning var myvar = 3 to value 3
,正如预期的那样。但是,修改代码以包含 equation
语法规则会破坏此类分配。
方程语法:
equation: number '+' number {$$ = + ;}
| number '-' number {$$ = - ;}
| number '*' number {$$ = * ;}
| number '/' number {$$ = / ;}
| number '^' number {$$ = pow(, );}
| equation '+' number {$$ = + ;}
| equation '-' number {$$ = - ;}
| equation '*' number {$$ = * ;}
| equation '/' number {$$ = / ;}
| equation '^' number {$$ = pow(, );}
;
相应地修改赋值语法:
assignment: identifier '=' number {printf("Assigning var %s to value %d\n", , );}
| identifier '=' equation {printf("Assigning var %s to value %d\n", , );}
| identifier '=' string {printf("Assigning var %s to value %s\n", , );}
;
并在解析器的第一部分中为 equation
规则指定类型 num
:
%type <num> equation
提供相同的输入:var = 3
冻结程序。
我知道这是一个很长的问题,但是有人可以解释一下这里发生了什么吗?
此外,here's the lexer如果你想看一看。
它没有 "freeze the program"。该程序正在等待更多输入。
在您的第一个语法中,var = 3
是一个完整的语句,无法扩展。但是在你的第二个语法中,它可能是 var = 3 + 4
的开头,例如。所以解析器需要在 3
之后读取另一个标记。如果您希望输入行以换行符结束,您将需要修改您的扫描器以发送换行符作为标记,然后修改您的语法以期望在每个语句末尾都有一个换行符标记。如果您打算允许语句分布在多行中,您在输入时需要意识到这一点。
你的语法有几个问题,还有你的解析器。 (例如,Flex 不实现非贪婪重复。)请查看 bison 和 flex 手册中的示例
目前,我的解析器文件如下所示:
%{
#include <stdio.h>
#include <math.h>
int yylex();
void yyerror (const char *s);
%}
%union {
long num;
char* str;
}
%start line
%token print
%token exit_cmd
%token <str> identifier
%token <str> string
%token <num> number
%%
line: assignment {;}
| exit_stmt {;}
| print_stmt {;}
| line assignment {;}
| line exit_stmt {;}
| line print_stmt {;}
;
assignment: identifier '=' number {printf("Assigning var %s to value %d\n", , );}
| identifier '=' string {printf("Assigning var %s to value %s\n", , );}
;
exit_stmt: exit_cmd {exit(0);}
;
print_stmt: print print_expr {;}
;
print_expr: string {printf("%s\n", );}
| number {printf("%d\n", );}
;
%%
int main(void)
{
return yyparse();
}
void yyerror (const char *s) {fprintf(stderr, "%s\n", s);}
给出输入:myvar = 3
给出输出 Assigning var myvar = 3 to value 3
,正如预期的那样。但是,修改代码以包含 equation
语法规则会破坏此类分配。
方程语法:
equation: number '+' number {$$ = + ;}
| number '-' number {$$ = - ;}
| number '*' number {$$ = * ;}
| number '/' number {$$ = / ;}
| number '^' number {$$ = pow(, );}
| equation '+' number {$$ = + ;}
| equation '-' number {$$ = - ;}
| equation '*' number {$$ = * ;}
| equation '/' number {$$ = / ;}
| equation '^' number {$$ = pow(, );}
;
相应地修改赋值语法:
assignment: identifier '=' number {printf("Assigning var %s to value %d\n", , );}
| identifier '=' equation {printf("Assigning var %s to value %d\n", , );}
| identifier '=' string {printf("Assigning var %s to value %s\n", , );}
;
并在解析器的第一部分中为 equation
规则指定类型 num
:
%type <num> equation
提供相同的输入:var = 3
冻结程序。
我知道这是一个很长的问题,但是有人可以解释一下这里发生了什么吗?
此外,here's the lexer如果你想看一看。
它没有 "freeze the program"。该程序正在等待更多输入。
在您的第一个语法中,var = 3
是一个完整的语句,无法扩展。但是在你的第二个语法中,它可能是 var = 3 + 4
的开头,例如。所以解析器需要在 3
之后读取另一个标记。如果您希望输入行以换行符结束,您将需要修改您的扫描器以发送换行符作为标记,然后修改您的语法以期望在每个语句末尾都有一个换行符标记。如果您打算允许语句分布在多行中,您在输入时需要意识到这一点。
你的语法有几个问题,还有你的解析器。 (例如,Flex 不实现非贪婪重复。)请查看 bison 和 flex 手册中的示例