我是yacc / lex的绝对初学者,我偶然发现了一些对我来说很简单的事情,但我无法理解。我有以下两条规则:S : E;
和E : STR;
(在词法分析器中,[a-z]+
映射到STR
)。我的猜测是,当我输入“hithere”输入时,输入被消耗,解析器应该退出,不是吗?
问题是,解析器仍在等待输入,所以不知道S : E
不会消耗(或者我猜)。如果我继续提供输入,则会引发语法错误(这是预期的)。
我的问题是,在哪种情况下解析器停止要求输入?也许更准确地说,为什么规则S : E;
不满足于我的具体例子?
我附上我的.l和我的.y文件:
test1.l
:
%{
#include <stdio.h>
#include <stdlib.h>
#include "y.tab.h"
%}
%option noyywrap
%%
[a-z]+ {yylval.str = yytext; return (STR);}
. { ; }
%%
test1.y
:
%{
#include <stdio.h>
#include <stdlib.h>
extern int yylex();
%}
%union {
char *str;
}
%token <str> STR
%type <str> E
%%
S : E {printf("%s\n", $1);}
;
E : STR {$$ = $1;}
;
%%
int yyerror(char *msg) {
printf("%s\n", msg);
return (0);
}
int main() {
yyparse();
return (0);
}
对我来说似乎很奇怪的是,如果我输入“hithere”,“hithere”会打印在我的终端上,所以这对我来说是一个强烈的指示S : E;
实际上已被识别并且printf()
已执行。
答案 0 :(得分:0)
它正在等待更多输入,因此可以减少生产S : E ;
。您需要输入ctrl / d或ctrl / z,具体取决于您的系统。
答案 1 :(得分:0)
Bison / yacc(以及许多(尽管不是全部)衍生物)实际构建了一个&#34;增强的&#34;语法通过添加一个有效的新的开始生产:
$start: S END
其中S
是您的开始符号(如果您未指定,则为语法中的第一个非终结符号),END
是表示输入结束的标记。 (这是一个真正的令牌,其值为0.(f)lex扫描器在获得文件结束时返回0,因此对于解析器,它看起来像是被赋予END
令牌。)
因此解析器不会返回,直到它看到END
令牌,这意味着扫描程序已经看到文件结束。如果您的输入来自终端,则需要发送EOF,通常是在大多数类似Unix的系统上输入EOF字符:control-D,或者在Windows / DOS上输入control-Z。
与许多解析器生成器不同,如果不需要先行符号来确定必须执行缩减,则bison将执行缩减而不读取前瞻符号。在你的语法的情况下,S: E
制作可能会产生这种情况,因为没有可能的转变;减少是正确的(如果下一个标记是END
)或输入在语法上没有效(如果下一个标记是其他任何东西)。因此打印字符串的语义值。对于更复杂的语法,这种情况不会发生(直到EOF被识别出来)。