我正在写一个类似PHP的解释器,但在移位/减少和减少/减少冲突方面有一些问题。 有人可以帮助我理解移位/减少和减少/减少冲突。
我必须编写和解释器,以运送/回送非值元素并评估以“魔术” @ 字符开头的表达式,例如 @if(cond)... @end; 。因此,必须回显“如果” ,而应该解释 @if(cond)
问题:scriptlang.y包含21个shift / reduce冲突和2个reduce / reduce冲突。
%union {
char* sval;
}
%token <sval> IDENTIFIER
%token <sval> RBRACKET
%token <sval> LBRACKET
%token <sval> KWSWITCH
%token <sval> KWIF
%token <sval> MAGICESC
%token MAGIC
%token ENDSTM
%type <sval> filechar
%start script
%%
script:
commands
;
commands:
/* empty */
| command
| commands command
;
command:
filechar {
analyser_echo($1,"filechar",analyser_canEcho);
}
| magic_command {}
;
filechar:
IDENTIFIER
| LBRACKET
| RBRACKET
| KWSWITCH
| KWIF
| MAGICESC
;
magic_command:
MAGIC valuation
| MAGIC alternative
;
valuation:
LBRACKET IDENTIFIER RBRACKET {
fprintf(yyout, "<val>");
}
;
alternative:
switch_alternative
| if_alternative
;
switch_alternative:
switch_block end_stm
;
switch_block:
switch_stm
| switch_stm commands
;
switch_stm:
KWSWITCH LBRACKET IDENTIFIER RBRACKET {}
;
if_alternative:
if_block end_stm
;
if_block:
if_stm
| if_stm commands
;
if_stm:
KWIF LBRACKET IDENTIFIER RBRACKET {}
;
end_stm:
ENDSTM
;
%%
flex文件内容:
"@@" {
yylval.sval = "@";
return MAGICESC;
}
"@" {
return MAGIC;
}
"(" {
yylval.sval = yytext;
return LBRACKET;
}
")" {
yylval.sval = yytext;
return RBRACKET;
}
"@end;" {
return ENDSTM;
}
"if" {
yylval.sval = yytext;
return KWIF;
}
"switch" {
yylval.sval = yytext;
return KWSWITCH;
}
[a-zA-Z][_a-zA-Z0-9]* {
yylval.sval = yytext;
return IDENTIFIER;
}
\n|. {
if(analyser_canEcho>0){
ECHO;
}
}
%%
答案 0 :(得分:1)
导致冲突的基本问题是您对commands
的处理。您的意图是将commands
定义为零个或多个command
,其内容如下:
commands: %empty
| commands command
如果您要坚持至少要有一条命令,那么您应该编写:
commands: command
| commands command
无法混合两种形式,因为解析器将不知道是一无所有(command
)还是由单个%empty
开始command
序列。您应该尝试准确地理解为什么这会导致歧义;您可以在该站点上找到许多类似问题的示例。例如,请参见this question。
产生21个移位/减少冲突。减少/减少冲突是产生好奇的结果:
switch_block: switch_stm commands
if_block: if_stm commands
if
和switch
语句是command
序列内的单个commands
元素; switch
或if
语句之后的内容将是command
中的下一个commands
。定义switch_block
使其包含以下命令是完全模棱两可的:实际上,是说下一个command
可能仍是switch_block
的一部分,或者可能是command
紧跟switch_block
。
上面,我专门解决了您提出的问题:语法分析表在语法上有冲突。语法和词汇规范还有其他各种问题,我强烈建议您研究有关野牛/屈挠的任何材料,和/或阅读bison和flex手册。
作为阅读手册或其他材料的指南,建议您至少注意两点:
语义值的处理。语法关键字永远不必具有自己的表示形式作为语义值;确实,语法关键字根本很少需要语义值。如果令牌确实需要其语义值作为其表示形式,则需要记住yytext
是指向您不拥有的私有数据缓冲区的指针,该缓冲区将被修改而不会发出警告。因此需要复制。
像PHP变体这样的嵌入式语言涉及两种不同的词法上下文。您有一个外部的,基本上未解释的上下文以及一个嵌入的上下文,该上下文包含在@
和@end;
之间。 (F)lex提供了开始条件来帮助处理此类嵌入。手册中有一些示例,并且在此站点上还有更多示例。