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