Bison / Yacc语法中的无意连接

我正在尝试使用lex和yacc并遇到一个奇怪的问题,但我认为最好在详细说明问题之前向我们展示我的代码。 这是我的词法分析员:

%{ #include  #include  #include "y.tab.h" void yyerror(char *); %} %% [a-zA-Z]+ { yylval.strV = yytext; return ID; } [0-9]+ { yylval.intV = atoi(yytext); return INTEGER; } [\n] { return *yytext; } [ \t] ; . yyerror("invalid character"); %% int yywrap(void) { return 1; } 

这是我的解析器:

 %{ #include  int yydebug=1; void prompt(); void yyerror(char *); int yylex(void); %} %union { int intV; char *strV; } %token INTEGER ID %% program: program statement EOF { prompt(); } | program EOF { prompt(); } | { prompt(); } ; args: /* empty */ | args ID { printf(":%s ", $2); } ; statement: ID args { printf("%s", $1); } | INTEGER { printf("%d", $1); } ; EOF: '\n' %% void yyerror(char *s) { fprintf(stderr, "%s\n", s); } void prompt() { printf("> "); } int main(void) { yyparse(); return 0; } 

一种非常简单的语言,由不超过字符串和整数以及基本REPL组成。 现在,您将在解析器中注意到args是使用前导冒号输出的,目的是,当与语句规则的第一个模式结合使用时,与REPL的交互将如下所示:

 > aaa aa a :aa :a aaa> 

但是,互动是这样的:

 > aaa aa a :aa :a aaa aa aa > 

为什么令牌ID在以下规则中

 statement: ID args { printf("%s", $1); } | INTEGER { printf("%d", $1); } ; 

具有总输入字符串的语义值,包括换行符? 我的语法如何重新编写,以便我打算进行交互?

如果要使令牌字符串保持有效,则必须在读取它们时保留它们。 我将statement规则修改为:

 statement: ID { printf("<%s> ", $1); } args { printf("%s", $1); } | INTEGER { printf("%d", $1); } ; 

然后,根据您的输入,我得到输出:

 > aaa aa a  :aa :a aaa aa a > 

请注意,在读取初始ID时,令牌正是您所期望的。 但是,因为您没有保留令牌,所以在解析args之后返回打印时,字符串已被修改。

我认为args和语句产生之间存在关联性冲突。 这可以通过bison -v parser.output文件的(部分)输出得到证实:

 Nonterminals, with rules where they appear $accept (6) on left: 0 program (7) on left: 1 2 3, on right: 0 1 2 statement (8) on left: 4 5, on right: 1 args (9) on left: 6 7, on right: 4 7 EOF (10) on left: 8, on right: 1 2 

实际上,我很难弄清楚你的语法试图接受什么。 作为旁注,我可能会将您的EOF作品作为EOL令牌移动到词法分析器中; 这将使解析错误的重新同步更容易。

更好地解释你的意图会有所帮助。