我正在尝试使用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 )语法。
答案 0 :(得分:1)
你没有显示整个语法,但看起来你的问题是它无法分辨出一个简单名称的expr
和一个具有单一名称的声明的开头之间的区别在名单中。考虑输入
A B = C
和
A B C = D
第一种情况是具有一个属性的A
的单一定义,而第二种情况是A
的表达式,后跟B
的定义。
问题在于解析器需要在看到A
并查看B
的前瞻之后决定这些情况,但它不能 - 它需要更多的前瞻(看看是什么)在B
)之后
通过改变语言或获得(有效)额外的预测,你可以做很多事情来避免这种情况。
更改语言。可能是一个只是单个名称的语句没有任何意义。因此,您可以将语言更改为具有不允许使用简单名称的单独statement
规则:
statement: expr '+' expr | expr '/' expr ;
expr: statement | name ;
现在它可以区分statement
和declaration
而无需额外的预测,因为statement
必须包含运算符。
更改工具。您可以使用bison的%glr-parser
选项或类似btyacc的工具来处理非LALR(1)语法。但是,我完全不确定Jison支持的是什么。
在词法分析器中模拟额外的前瞻。你可以让你的词法分析器为你做额外的预测。您可以使用匹配[a-zA-Z]+[ \t\n]*=
的词法分析器模式(即名称后跟=符号),并返回一个特殊的propname
令牌而不是name
。然后,您的property
规则变为:
property: propname name ;