我必须为一种迷你语言编写一个解析器,但遇到一些问题。这是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 $2;}
| "in" '[' NO ']' IDENTIFIER {int $5[$3];}
;
cmpdstmt : "exec" stmtlist "stop" {;}
stmtlist : stmt {;}
| stmt stmtlist {;}
;
stmt : assignstmt {;}
| ifstmt {;}
| whilestmt {;}
;
assignstmt : IDENTIFIER '=' expression {$1 = $3;}
;
expression : expression '+' term {$$ = $1 + $3;}
| term '+' term {$$ = $1 + $3;}
;
term : DIGIT {$$ = $1;}
| IDENTIFIER {$$ = $1;}
;
ifstmt : "if" '(' condition ')' '{' stmt '}' {if($3){$6;}}
;
whilestmt : "wh" '(' condition ')' '{' stmt '}' {while($3){$6;}}
;
condition : expression "<" expression {$$ = ($1 < $3);}
| expression "<=" expression {$$ = ($1 <= $3);}
| expression "==" expression {$$ = ($1 == $3);}
| expression "!=" expression {$$ = ($1 != $3);}
| expression ">=" expression {$$ = ($1 >= $3);}
| expression ">" expression {$$ = ($1 > $3);}
;
%%
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 $2;}
^
lazy.y:22:19: error: expected ‘)’ before ‘.’ token
| "in" '[' NO ']' IDENTIFIER {int $5[$3];}
如果需要,我还将发布Lex文件。
答案 0 :(得分:0)
来自
declaration : "in" IDENTIFIER {int $2;} | "in" '[' NO ']' IDENTIFIER {int $5[$3];} ;
错误来自{int $2;}
和{int $5[$3];}
您对他们有什么期望?
那是合法的:
declaration : "in" IDENTIFIER {char * s = $2;}
| "in" '[' NO ']' IDENTIFIER {int i = $5[$3];}
;
当然,这些变量是局部变量,因此没有真正的间断
答案 1 :(得分:0)
您已经知道YACC解析器生成器系列通过生成C代码进行工作,然后将其编译。可能不清楚的是,当涉及语义动作时,它们基本上充当模板引擎。如果您所提供的动作模板与之对应,那么他们非常愿意产生垃圾代码。除非您尝试编译结果代码,否则您可能不会发现他们已经这样做了。
此外,您的编译器和解析器生成器正在协同合作,向您显示YACC代码行,这些代码负责最终导致您所遇到的C语法错误。这对于确定位置您需要应用修复程序很有帮助,但是并不能很好地解释问题的性质。但是,这是尽力而为的,因为编译器只知道为什么C代码是错误的,而不是为什么派生它的YACC代码是错误的。
那么YACC代码为什么出错?有几个原因,但首先也是最主要的原因是,旨在通过设置特殊符号$$
来设置产品语义的语义动作必须这样做。相反,以类型名称开头的C语句(例如由您的特定操作生成的)是声明。即使碰巧是一个有效值(在这里肯定不是这种情况),它也不会设置语义值。相反,您想要更类似的东西
{ $$ = $2; }
和
{ $$ = $5[$3]; }
但是您对数据类型有疑问。如果第一个操作中的$2
和第二个操作中的$5
与相同类型的令牌相对应,则上述两个操作都无法与您的{{ 1}}生产。作为一个大胆的猜测,也许您试图通过强制转换一个或两个以键入declaration
,ala int
来清理它。尽管这可以解决您的编译错误,但由于您需要了解原始类型,并且还因为从指针转换为$$ = (int) $2;
可能会固有地有损,因此您将无法使用。 / p>
没有快速简便的修复方法。您需要重新考虑您的方法,更加注意数据类型以及如何保存和传达类型信息。
更新:
在我看来,也许您根本没有尝试设置语义值,而是创建了一个生成C代码的解析器。如果真是这样,那么您就犯了帧错误。语义动作有助于生成的解析器本身的代码,即解析语言时使用的代码。如果您打算将自定义语言翻译成等效的C代码,则解析器需要将翻译的代码输出输出,而不是解析器的 part 。例如,您可以通过将所需的语句打印到文件中来实现这一点,但是更常见的方法是让解析器构建一个抽象的语法树,在解析完成后进行处理。