Lex&YACC 编译错误:在 '.' 之前应为 ')'令牌
Posted
技术标签:
【中文标题】Lex&YACC 编译错误:在 \'.\' 之前应为 \')\'令牌【英文标题】:Lex&YACC compile error: expected ')' before '.' tokenLex&YACC 编译错误:在 '.' 之前应为 ')'令牌 【发布时间】:2019-01-12 13:11:08 【问题描述】:我必须为一种迷你语言编写一个解析器,但我遇到了一些问题。这是 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 文件。
【问题讨论】:
【参考方案1】:来自
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];
;
当然这些变量是局部的,所以没有真正的兴趣
【讨论】:
是的,我错误地理解了yacc
的工作原理。我想创建一个变量,但发现这并不容易,我需要中间函数来创建变量。【参考方案2】:
您已经知道 YACC 系列解析器生成器通过生成 C 代码来工作,然后您对其进行编译。可能不清楚的是,当涉及到语义动作时,它们基本上用作模板引擎。如果那是您提供的操作模板对应的内容,他们非常愿意生成垃圾代码。在您尝试编译生成的代码之前,您可能不会发现他们已经这样做了。
此外,您的编译器和解析器生成器正在合作,向您展示导致您的案例的最终 C 语法错误的 YACC 代码行。这对于确定您需要在何处应用修复非常有帮助,但它并不能很好地解释问题的性质。然而,这是它所能做的最好的事情,因为编译器只知道为什么 C 代码是错误的,而不知道为什么派生它的 YACC 代码是错误的。
那么为什么 YACC 代码是错误的呢?有几个原因,但首先是因为旨在设置产生式语义值的语义操作必须通过分配特殊符号 $$
来实现。以类型名称开头的 C 语句(例如由您的特定操作产生的)是一个声明。即使它碰巧是一个有效的(这里肯定不是这种情况),它也不会设置语义值。相反,你想要的东西更像
$$ = $2;
和
$$ = $5[$3];
但是您的数据类型有问题。第一个动作中的$2
和第二个动作中的$5
对应于相同类型的标记,以上两个动作不可能都与declaration
生产的(未声明的)类型兼容。作为一个疯狂的猜测,也许你试图通过将一个或两个都输入int
,ala $$ = (int) $2;
来清理它。尽管这可能会解决您的编译错误,但它会给您留下一个无法使用的结果,因为您需要知道原始类型,而且从指针转换为 int
可能本质上是有损的。
没有快速简便的解决方法。您需要重新考虑您的方法,更加关注数据类型以及如何保存和传达类型信息。
更新:
我突然想到,也许您根本没有尝试设置语义值,而是创建了一个生成 C 代码的解析器。如果是这种情况,那么您已经犯了帧错误。语义动作有助于生成的解析器本身的代码——即解析语言时使用的代码。如果您的意图是将自定义语言翻译成等效的 C 代码,则翻译后的代码需要由解析器输出,而不是解析器的部分。例如,您可以通过将所需语句打印到文件来实现这一点,但更常见的方法是让解析器构建一个抽象语法树,在解析完成后处理它。
【讨论】:
以上是关于Lex&YACC 编译错误:在 '.' 之前应为 ')'令牌的主要内容,如果未能解决你的问题,请参考以下文章