我正在尝试使用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呢?看起来它可能需要提前查找两个标记而不是一个,但这是盲目的猜测,并且json文档指出它不支持LL(k)语法。
您没有显示整个语法,但看起来您的问题是它无法区分简单名称的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
选项或可以处理非lalr(1)语法的btyacc之类的工具。但是,我不确定Jison支持什么。在词法分析器中模拟额外的前瞻性。您可以让lexer为您做额外的提前查找。您可以有一个匹配
[a-zA-Z]+[ tn]*=
的词法分析器模式(即,名称后跟一个=号),并返回一个特殊的propname
令牌,而不是name
。然后你的property
规则变成:property: propname name ;