如何使用Jison生成一个处理语法歧义的解析器?

时间:2013-12-09 16:08:49

标签: javascript node.js parsing bnf jison

我正在尝试通过Jison为JavaScript ChucK生成一个JavaScript解析器,并且已经开始了一个良好的开端,除了生成的解析器无法处理的语言含糊不清。最初的ChucK编译器是由Bison生成的,必须能以某种方式解决这些歧义。

出于这个问题的目的,我已经将问题简化为解释性语法,该语法只呈现一个模糊性。作为参考,我已经提供了gist所有涉及的文件(包括生成的parser)。项目结构如下:

语法本身如下:

grammar = {
    Program: [
        ['ProgramSection', '$$ = new yy.Program($1);']
    ],
    ProgramSection: [
        ['Expression SEMICOLON', '$$ = new yy.ExpressionStatement($1);']
    ],
    Expression: [
        ['DeclExpression', '$$ = $1;'],
        ['Expression OP DeclExpression', '$$ = new yy.ExpFromBinary($1, $2, $3);']
    ],
    DeclExpression: [
        ['TypeDecl VarDeclList', '$$ = new yy.DeclExp($1, $2, 0);'],
        ['PrimaryExpression', '$$ = $1;']
    ],
    VarDeclList: [
        ['VarDecl', '$$ = new yy.VarDeclList($1);']
    ],
    VarDecl: [
        ['ID', '$$ = new yy.VarDecl($1);']
    ],
    TypeDecl: [
        ['ID', '$$ = new yy.TypeDecl(new yy.IdList($1), 0);']
    ],
    PrimaryExpression: [
        ['ID', '$$ = new yy.ExpFromId($1);']
    ]
};

不明确的是,非终端DeclExpression可以匹配TypeDecl VarDeclListPrimaryExpression。这使得Jison发出以下警告:

States with conflicts:
State 7
  TypeDecl -> ID . #lookaheads= ID SEMICOLON OP
  PrimaryExpression -> ID . #lookaheads= ID SEMICOLON OP

生成的解析器无法解析测试代码(Type var => out;),如下所示:

Error: Parse error on line 1: Unexpected 'SEMICOLON'

根据我的理解,它是=>运算符之后解析器尝试与规则TypeDecl VarDeclList匹配的部分。

那么,我怎样才能生成一个能够处理这种歧义的解析器呢?

2 个答案:

答案 0 :(得分:1)

您的语法不能与LALR(1)解析器一起使用的原因是因为DeclExpressionTypeDecl上的PrimaryExpression状态的LALR(1)解析器不明确} 状态。

让我试着解释一下。如错误消息所述,解析器检测到TypeDeclPrimaryExpression上的冲突。两者都有ID作为标记,但由于LALR(1)解析器只能在前面看一个标记,这意味着解析器在DeclExpression状态时不知道该做什么。另一方面,SLR有一种动态的外观,可以牺牲一些记忆来解决冲突。

如果你想让它在LALR(1)解析器上工作,只需将你的DeclExpression规则重构为ID VarDeclList | ID,这样解析器就不必看起来像一个头为了找到正确的规则。

答案 1 :(得分:0)

我发现通过选择'slr'(SLR)或'lr'(LR1)解析器类型,我可以为这个(简化的)语法生成一个函数解析器:

// Generate SLR parser, since default LALR has conflicts
exports.generate = new Parser(parserConfig, {type: "slr"}).generate;

我仍然想知道为什么默认值(LALR(1))不起作用,因为这应该是Bison生成的。