YACC 语法规则结束

End of grammar rule in YACC

我是 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", );}
  ;

E : STR                 {$$ = ;}
  ;

%%

int yyerror(char *msg) {
    printf("%s\n", msg);
    return (0);
}

int main() {
    yyparse();
    return (0);
}

对我来说真的很奇怪的是,如果我输入 "hithere","hithere" 会打印回我的终端,所以这对我来说是一个强有力的指示 S : E; 实际上已经被识别并且 printf() 被执行了。

它正在等待更多输入,以便减少产量 S : E ;。根据您的系统,您需要键入 ctrl/d 或 ctrl/z。

Bison/yacc(以及许多(虽然不是全部)派生词)实际上通过添加一个新的开始产生式构建了一个 "augmented" 语法,这实际上是:

$start: S END

其中 S 是您的开始符号(如果您未指定,则为语法中的第一个非终结符),而 END 是表示输入结束的标记。 (这是一个真正的标记,其值为 0。(f)lex 扫描器 return 0 当它们到达文件结尾时,因此对于解析器来说,它看起来像是被赋予了一个 END 标记.)

因此解析器在看到 END 标记之前不会 return,这意味着扫描器已经看到文件结尾。如果您的输入来自终端,则需要发送 EOF,通常是通过键入 EOF 字符:在大多数类 Unix 系统上为 control-D,或在 Windows/DOS.

上为 control-Z

与许多解析器生成器不同,如果先行符号对于确定必须执行归约不是必需的,bison 将执行归约而不读取先行符号。在你的语法的情况下, S: E 生产是可能的,因为没有可能的转变;归约是正确的(如果下一个标记是 END)或者输入在语法上无效(如果下一个标记是其他任何东西)。因此打印了字符串的语义值。对于稍微复杂一点的语法,这不会发生(直到 EOF 被识别)。