YACC中的语法规则结束

时间:2016-04-18 22:18:18

标签: c yacc lex

我是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()已执行。

2 个答案:

答案 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被识别出来)。