Lex&YACC compile error: expected ')' before '.' token
Lex&YACC compile error: expected ')' before '.' token
我必须为一种迷你语言编写解析器,但遇到了一些问题。这是 YACC 文件:
%{
#include <stdio.h>
int yylex();
void yyerror(char *s);
%}
%union {int num; char id; double d; char *s;}
%start program
%token <num> DIGIT
%token <s> IDENTIFIER
%token <num> NO
%type <num> term condition
%type <s> expression assignstmt stmt
%%
program : "##LAZY###" "vars" decllist cmpdstmt {;}
;
decllist : declaration {;}
| declaration decllist {;}
;
declaration : "in" IDENTIFIER {int ;}
| "in" '[' NO ']' IDENTIFIER {int [];}
;
cmpdstmt : "exec" stmtlist "stop" {;}
stmtlist : stmt {;}
| stmt stmtlist {;}
;
stmt : assignstmt {;}
| ifstmt {;}
| whilestmt {;}
;
assignstmt : IDENTIFIER '=' expression { = ;}
;
expression : expression '+' term {$$ = + ;}
| term '+' term {$$ = + ;}
;
term : DIGIT {$$ = ;}
| IDENTIFIER {$$ = ;}
;
ifstmt : "if" '(' condition ')' '{' stmt '}' {if(){;}}
;
whilestmt : "wh" '(' condition ')' '{' stmt '}' {while(){;}}
;
condition : expression "<" expression {$$ = ( < );}
| expression "<=" expression {$$ = ( <= );}
| expression "==" expression {$$ = ( == );}
| expression "!=" expression {$$ = ( != );}
| expression ">=" expression {$$ = ( >= );}
| expression ">" expression {$$ = ( > );}
;
%%
int main() {
printf("WORKING\n");
return yyparse();
}
void yyerror(char*s) { printf("%s\n", s); }
但是当我尝试使用 cc lex.yy.c y.tab.c 编译它时,我收到以下错误,我不知道如何修复它们或为什么会收到它们:
lazy.y: In function ‘yyparse’:
lazy.y:21:19: error: expected ‘)’ before ‘.’ token
declaration : "in" IDENTIFIER {int ;}
^
lazy.y:22:19: error: expected ‘)’ before ‘.’ token
| "in" '[' NO ']' IDENTIFIER {int [];}
如果需要,我也会 post Lex 文件。
来自
declaration : "in" IDENTIFIER {int ;}
| "in" '[' NO ']' IDENTIFIER {int [];}
;
错误来自 {int ;}
和 {int [];}
你对他们有什么期望?
这是合法的:
declaration : "in" IDENTIFIER {char * s = ;}
| "in" '[' NO ']' IDENTIFIER {int i = [];}
;
当然除了这些变量是局部的,所以没有真正的兴趣
您已经知道 YACC 系列的解析器生成器通过生成 C 代码来工作,然后您可以对其进行编译。可能不清楚的是,当涉及到语义动作时,它们基本上充当模板引擎。如果您提供的操作模板对应的是垃圾代码,他们非常愿意生成垃圾代码。在您尝试编译生成的代码之前,您可能不会发现他们已经这样做了。
此外,您的编译器和解析器生成器正在合作向您展示 YACC 代码行,这些代码行负责导致您的情况的最终 C 语法错误。这对于确定 何处 需要应用修复程序非常有帮助,但它并不能很好地解释问题的性质。然而,这大约是它能做的最好的事情,因为编译器只知道为什么 C 代码是错误的,不知道为什么派生它的 YACC 代码是错误的。
那么YACC代码为什么会出错呢?有几个原因,但首先是因为旨在设置产生式的语义值的语义动作必须通过分配给特殊符号 $$
来实现。以类型名称开头的 C 语句(例如由您的特定操作生成)是声明。即使它碰巧是有效的(这里肯定不是这种情况),它也不会设置语义值。相反,你想要更像
的东西
{ $$ = ; }
和
{ $$ = []; }
但是你的数据类型有问题。在第一个动作中 </code> 和第二个动作中的 <code>
对应于相同类型的标记,上面的两个动作不可能都与你的 [= 的(未声明的)类型兼容15=]生产。作为一个疯狂的猜测,也许你正试图通过将一个或两个强制转换为类型 int
,ala $$ = (int) ;
来清理它。虽然这可能会解决您的编译错误,但它会给您留下无法使用的结果,因为您需要知道原始类型,并且还因为从指针转换为 int
可能本质上是有损的。
没有快速简便的修复方法。您需要重新考虑您的方法,更加注意数据类型以及如何保存和传达类型信息。
更新:
我突然想到,也许您根本没有尝试设置语义值,而是创建了一个生成 C 代码的解析器。如果是这种情况,那么您就犯了帧错误。语义操作有助于生成解析器本身的代码——即解析语言时使用的代码。如果您打算将自定义语言翻译成等效的 C 代码,那么翻译后的代码需要由解析器 output,而不是 part解析器。例如,您可以通过将所需语句打印到文件来实现这一点,但更常见的方法是让解析器构建抽象语法树,在解析完成后对其进行处理。
我必须为一种迷你语言编写解析器,但遇到了一些问题。这是 YACC 文件:
%{
#include <stdio.h>
int yylex();
void yyerror(char *s);
%}
%union {int num; char id; double d; char *s;}
%start program
%token <num> DIGIT
%token <s> IDENTIFIER
%token <num> NO
%type <num> term condition
%type <s> expression assignstmt stmt
%%
program : "##LAZY###" "vars" decllist cmpdstmt {;}
;
decllist : declaration {;}
| declaration decllist {;}
;
declaration : "in" IDENTIFIER {int ;}
| "in" '[' NO ']' IDENTIFIER {int [];}
;
cmpdstmt : "exec" stmtlist "stop" {;}
stmtlist : stmt {;}
| stmt stmtlist {;}
;
stmt : assignstmt {;}
| ifstmt {;}
| whilestmt {;}
;
assignstmt : IDENTIFIER '=' expression { = ;}
;
expression : expression '+' term {$$ = + ;}
| term '+' term {$$ = + ;}
;
term : DIGIT {$$ = ;}
| IDENTIFIER {$$ = ;}
;
ifstmt : "if" '(' condition ')' '{' stmt '}' {if(){;}}
;
whilestmt : "wh" '(' condition ')' '{' stmt '}' {while(){;}}
;
condition : expression "<" expression {$$ = ( < );}
| expression "<=" expression {$$ = ( <= );}
| expression "==" expression {$$ = ( == );}
| expression "!=" expression {$$ = ( != );}
| expression ">=" expression {$$ = ( >= );}
| expression ">" expression {$$ = ( > );}
;
%%
int main() {
printf("WORKING\n");
return yyparse();
}
void yyerror(char*s) { printf("%s\n", s); }
但是当我尝试使用 cc lex.yy.c y.tab.c 编译它时,我收到以下错误,我不知道如何修复它们或为什么会收到它们:
lazy.y: In function ‘yyparse’:
lazy.y:21:19: error: expected ‘)’ before ‘.’ token
declaration : "in" IDENTIFIER {int ;}
^
lazy.y:22:19: error: expected ‘)’ before ‘.’ token
| "in" '[' NO ']' IDENTIFIER {int [];}
如果需要,我也会 post Lex 文件。
来自
declaration : "in" IDENTIFIER {int ;} | "in" '[' NO ']' IDENTIFIER {int [];} ;
错误来自 {int ;}
和 {int [];}
你对他们有什么期望?
这是合法的:
declaration : "in" IDENTIFIER {char * s = ;}
| "in" '[' NO ']' IDENTIFIER {int i = [];}
;
当然除了这些变量是局部的,所以没有真正的兴趣
您已经知道 YACC 系列的解析器生成器通过生成 C 代码来工作,然后您可以对其进行编译。可能不清楚的是,当涉及到语义动作时,它们基本上充当模板引擎。如果您提供的操作模板对应的是垃圾代码,他们非常愿意生成垃圾代码。在您尝试编译生成的代码之前,您可能不会发现他们已经这样做了。
此外,您的编译器和解析器生成器正在合作向您展示 YACC 代码行,这些代码行负责导致您的情况的最终 C 语法错误。这对于确定 何处 需要应用修复程序非常有帮助,但它并不能很好地解释问题的性质。然而,这大约是它能做的最好的事情,因为编译器只知道为什么 C 代码是错误的,不知道为什么派生它的 YACC 代码是错误的。
那么YACC代码为什么会出错呢?有几个原因,但首先是因为旨在设置产生式的语义值的语义动作必须通过分配给特殊符号 $$
来实现。以类型名称开头的 C 语句(例如由您的特定操作生成)是声明。即使它碰巧是有效的(这里肯定不是这种情况),它也不会设置语义值。相反,你想要更像
{ $$ = ; }
和
{ $$ = []; }
但是你的数据类型有问题。在第一个动作中 </code> 和第二个动作中的 <code>
对应于相同类型的标记,上面的两个动作不可能都与你的 [= 的(未声明的)类型兼容15=]生产。作为一个疯狂的猜测,也许你正试图通过将一个或两个强制转换为类型 int
,ala $$ = (int) ;
来清理它。虽然这可能会解决您的编译错误,但它会给您留下无法使用的结果,因为您需要知道原始类型,并且还因为从指针转换为 int
可能本质上是有损的。
没有快速简便的修复方法。您需要重新考虑您的方法,更加注意数据类型以及如何保存和传达类型信息。
更新:
我突然想到,也许您根本没有尝试设置语义值,而是创建了一个生成 C 代码的解析器。如果是这种情况,那么您就犯了帧错误。语义操作有助于生成解析器本身的代码——即解析语言时使用的代码。如果您打算将自定义语言翻译成等效的 C 代码,那么翻译后的代码需要由解析器 output,而不是 part解析器。例如,您可以通过将所需语句打印到文件来实现这一点,但更常见的方法是让解析器构建抽象语法树,在解析完成后对其进行处理。