我已经在jison中编写了一个非常简单的解析器,但是这个语法中似乎存在S / R冲突:
/* lexical grammar */
%lex
%%
\s+ /* skip whitespace */
":" return ':'
"." return '.'
[a-zA-Z_][a-zA-Z0-9_]* return 'IDENTIFIER'
<<EOF>> return 'EOF'
. return 'INVALID'
/lex
/* operator associations and precedence */
%start expressions
%% /* language grammar */
expressions
: statements EOF
{return $1;}
;
statements: statements statement {$$ = [$1].concat($2);} | statement {$$ =
[$1];};
statement:
IDENTIFIER ":" grammar_and {[$$ = ["grammar_rule",$1,$3]]};
grammar_and:
grammar_and IDENTIFIER {$$= [$1,$2]} | IDENTIFIER;
它旨在解析像这样的文档,其中包含4个语句:
first: this is a sentence
second: this is another sentence
something: more words here another: more words here
但它没有像我预期的那样工作:
Conflicts encountered:
Resolve S/R conflict (shift by default.)
(1,10, 2,4) -> 1,10
是否可以在不修改正在解析的语言的语法的情况下解决此冲突?
答案 0 :(得分:1)
所写的语法(实际上,该语言的任何合理语法)是LR(2),因为无法知道IDENTIFIER
是grammar_and
的延续还是开始新的statement
,直到检查到以下标记。在第二种情况下,有必要减少statement
,并且不能使用单个令牌预测来做出决定。
这是一个经典的LR(2)语法 - 事实上,它是野牛制作的自然语法 - 并且有很多方法可以解决它。
语言本身是LR(1)。实际上,没有诸如LR(2)语言之类的东西,因为可以从任何LR(k)语法机械地产生LR(1)语法。 How do I rewrite a context free grammar so that it is LR(1)?的答案中提供了如何使用基本相同的语法执行此操作的示例。
一个更简单的解决方案,类似于大多数yacc-alikes所使用的解决方案,是在词法扫描器中添加额外的前瞻(或者在扫描器和解析器之间使用垫片)。 flex&bison shift/reduce conflict的答案中提供了执行此操作的C代码示例。 (问题不完全相同,但我认为解决方案可以进行调整。)