我可以用我的语言写
a = 1
b = 2
if true { } else { }
if true { } **Here is the problem**
else {}我的语法不支持语句之间的换行符。else只能与if一起使用。当我在规则中添加optionalNL时
IfExpr:
IF rval optionalNL codeBlock optionalNL ELSE codeBlock
| IF rval optionalNL codeBlockelse之前的optionalNL导致3个reduce/reduce。原因是它可以减少使用IfExpr中的第二个规则,或者减少到exprLoop,其中它允许在表达式之间有许多换行符。
无论我做什么(我试着在optionalNL之前写%prec,或者其他),它总是减少到exprLoop,这会在bison上给我一个同步错误。我如何告诉bison在这一点上转移(到optionalNL else)而不是reduce?(to exprLoop导致else是一个错误)。
用于测试的示例文件
%%
program:
exprLoop;
exprLoop:
exprLoop2 expr
| exprLoop2
exprLoop2:
| exprLoop2 expr EOS
| exprLoop2 EOS
;
expr:
'i' Var optEOS '{' '}'
| 'i' Var optEOS '{' '}' optEOS 'e' '{' '}'
EOS: '\n' ;
Var: 'v';
optEOS: | optEOS EOS
%%
//this can be added to the lex file
[iev] { return *yytext; }y.output http://www.pastie.org/707448
备用.y和输出。你可以看到它向前看,看到一个\n,不知道是减少规则还是继续前进。我改变了规则的顺序以获得不同的结果。但它要么总是期望\n,要么总是期望其他值,因此一个规则总是被忽略。状态15
9 expr: 'i' Var optEOS '{' '}' . [$end, '\n']
10 | 'i' Var optEOS '{' '}' . 'e' '{' '}'
11 | 'i' Var optEOS '{' '}' . '\n' 'e' '{' '}'
'e' shift, and go to state 16
'\n' shift, and go to state 17
'\n' [reduce using rule 9 (expr)]
$default reduce using rule 9 (expr)感谢his answer的Kinopiko
我更改了他的代码,使其没有冲突,然后努力使其更灵活。这是我的档案
test.y
%{
#include <stdio.h>
%}
%%
program: expr { printf ("First expr\n"); }
| program expr { printf ("Another expr\n"); }
expr:
if optEOS { printf ("IF only\n"); }
| if optEOS else optEOS { printf ("IF/ELSE\n"); }
if: 'i' Var optEOS '{' optEOS '}'
else: 'e' optEOS '{' optEOS '}'
EOS: '\n'
Var: 'v'
optEOS:
| EOS optEOS { ;}//printf ("many EOS\n"); }
%%
int main(int argc, char **argv)
{
int i;
printf("starting\n");
if(argc < 2) {
printf("Reading from stdin\n");
yyparse();
return 0;
}
for(i = 1; i < argc; i++) {
FILE *f;
char fn[260];
sprintf(fn, "./%s", argv[i]);
f = fopen(fn, "r");
if(!f) {
perror(argv[i]);
return (1);
}
printf("Running '%s'\n", argv[i]);
yyrestart(f);
yyparse();
fclose(f);
printf("done\n");
}
return 0;
}test.y
%{
#include <stdio.h>
#include "y.tab.h"
%}
%option noyywrap
%%
[ \t] { }
\n { return *yytext; }
. { return *yytext; }
%%
int yyerror ()
{
printf ("syntax error\n");
exit (1);
}编译后自动运行的测试文件
i v { }
i v { }
e { }
i v { }
e { }
i v {
} e {
}
i v { }
i v { } i v { } e { }
i v
{ } i v { } e { } i v { } e {
} i v {
} e
{ }发布于 2009-11-21 10:39:48
根据'Lex & Yacc‘,reduce/reduce的默认解析是第一个定义的规则,所以正如您所说的,exprLoop获胜,所以我将假设它是首先定义的。
但是,改变顺序可能不会像您期望的那样解决问题。
进一步阅读(第237页)似乎你需要更多地向前看,这不是标准yacc/bison的选项。但野牛确实有一个GLR mode,这可能是有用的。
发布于 2009-11-21 11:39:25
您可以做的一件事是完全使用lex规则解析出换行符。这样,换行符在哪里就无关紧要了。这就是C/C++做的.换行符在很大程度上被忽略。
发布于 2009-11-23 03:54:03
问题是:
IfExpr:
IF rval optionalNL codeBlock optionalNL ELSE codeBlock
| IF rval optionalNL codeBlock在代码块之后需要两个标记的先行查找,才能看到换行符后面的'else‘。您可以通过在两个if规则中复制optionalNL来避免这种情况:
IfExpr:
IF rval optionalNL codeBlock optionalNL ELSE codeBlock
| IF rval optionalNL codeBlock optionalNL现在,在解析optionalNL之前,解析器不必在两个规则之间做出决定,让它在单令牌先行查找中看到ELSE (或它的缺失)。
这里的一个潜在缺点是,第二个if规则(但不是第一个)现在将吸收所有尾随的换行符,因此如果您的程序语法需要在每条语句之间换行,那么它不会在没有elses的if后面找到一个,并且它已经被使用了。
https://stackoverflow.com/questions/1763243
复制相似问题