0

我正在尝试使用Jison定义一种语言,使用很少的标点符号进行分隔 - 就像CoffeeScript但没有缩进。这就是我想要实现的目标:

# Definition
object1, object2
    property1 = value1,
    property2 = value2

# Definition
object3 property = value

# Statement
object1 + object2 + object3

这定义了三个具有一些属性的对象并添加了它们。请注意,第一个定义使用名称列表指定了两个对象,第二个定义表明空格不应该很重要。

尽管名称列表和属性列表之间缺少开始和结束符号,但我觉得语法并不模棱两可。语法规定每个名称列表后跟一个属性列表。如果我编写一个仅指定定义的语法,这一切似乎都可以正常工作,包括以下产品:

definition
    : name_list property_list
    ;

name_list
    : name
    | name_list ',' name
    ;

property_list
    : property
    | property_list ',' property
    ;

property
    : name '=' name
    ;

现在,我以一种相当正常的方式为语法的表达式部分添加规则,据我所知:

expr
    : expr '+' expr
    | expr '/' expr
    | name
    ;

Jison 抱怨说,对于处于某种编号状态的一堆不同的前瞻标记,“可能有多种操作”。减少选项通常如下所示:

- reduce by rule: name_list -> name
- reduce by rule: expr -> name

我相信语法是明确的,但我怎样才能说服吉森呢?似乎它可能需要向前看两个标记而不是一个,但这是一个盲目的猜测,Jison 文档指出它不(还?)支持 LL( k ) 语法。

4

1 回答 1

1

您没有显示整个语法,但看起来您的问题是它无法区分expr简单名称和名称列表中具有单个名称的声明的开头之间的区别。考虑输入

A B = C

A B C = D

第一种情况是A具有一个属性的单个定义,而第二种情况是一个表达式A,后跟一个 for 的定义B

问题是解析器需要在看到A并查看前瞻之后在这些情况之间做出决定B,但它不能 - 它需要更多前瞻(查看 之后的内容B

您可以通过更改语言或(有效地)获得额外的前瞻性来避免这种情况。

  1. 改变语言。可能只有一个名称的语句没有任何意义。因此,您可以更改语言以具有statement不允许简单名称的单独规则:

    statement: expr '+' expr | expr '/' expr ;
    expr: statement | name ;
    

    现在它可以区分 astatement和 adeclaration而无需额外的前瞻,因为 astatement必须包含一个运算符。

  2. 更换工具。您可以使用 bison 的%glr-parser选项或btyacc之类的工具来处理非 LALR(1) 语法。但是,我完全不确定 Jison 支持什么。

  3. 在词法分析器中模拟额外的前瞻。你可以让你的词法分析器为你做额外的预测。您可以有一个匹配的词法分析器模式[a-zA-Z]+[ \t\n]*=(即,一个名称后跟一个 = 符号)并让它返回一个特殊propname标记而不是name. 然后你的property规则变成:

    property: propname name ;
    
于 2013-02-26T20:01:34.620 回答