我一直在了解Javacc语法,以便在发现行的地方写解析器,就像这样
Options : { LOOKAHEAD=3; }
我想知道什么是LOOKAHEAD,并且有任何其他方法来声明前瞻吗?
LOOKAHED是为Javacc解析器生成的语法树中的语法验证而需要选择的路径上进行决策所需的令牌数量。
此配置是解决选择冲突所必需的,因为javacc不支持回溯。
因此,编写适合LOOKAHED = 1的语法很重要,这意味着通过查看一个标记,可以确定语法树中的流。这是一种编写语法的方式。
例如:
由于JavaCC是LL解析器,因此将重复生产规则的左令牌,因此在syntex树上将是分支。选择冲突出现在哪个分支上,如下所示,
void PhoneNumber() : {} {
(LocalNumber() | CountryNumber()) <EOF>
}
void LocalNumber() : {} {
AreaCode() "-" <FOUR_DIGITS>
}
void CountryNumber() : {} {
AreaCode() "-" <THREE_DIGIT> "-" <FOUR_DIGITS>
}
void AreaCode() : {} {
<THREE_DIGIT>
}
请注意,CountryNumber和LocalNumber都以终端<THREE_DIGIT>
开头,这是选择冲突,
这可以通过称为左因子分解的方法重写。
void PhoneNumber() : {} {
AreaCode() "-" (LocalNumber() | CountryNumber()) <EOF>
}
void LocalNumber() : {} {
<FOUR_DIGITS>
}
void CountryNumber() : {} {
<THREE_DIGIT> "-" <FOUR_DIGITS>
}
void AreaCode() : {} {
<THREE_DIGIT>
}
对于无法完成的情况,使用了Lookahead
前瞻性有五种类型,
多个令牌LOOKAHEAD
可以与通过LOOKAHEAD(k)方法传递的整数一起使用。
本地LOOKAHEAD¶
void PhoneNumber():{} {(LOOKAHEAD(3)LocalNumber()| CountryNumber())}
Global LOOKAHEAD
选项:{LOOKAHEAD = 3; }
句法LOOKAHEAD
语法先行规范使用语法构造作为选择解析器。
[在不使用多个令牌的情况下指定语法先行时,您真正指定的是在无限多个令牌的情况下进行语法先行。
例如:LOOKAHEAD(2147483647,LocalNumber())
void PhoneNumber() : {} { ( LOOKAHEAD(("A"|"B")+ AreaCode() "-" <FOUR_DIGITS>) LocalNumber() | CountryNumber() ) <EOF> }
多个令牌和语法LOOKAHEAD的组合
这样,只要能够在指定的选择范围内满足语法先行方式,我们就可以先行有限数量的标记。
void PhoneNumber() : {} {
(
LOOKAHEAD(10, ("A"|"B")+ AreaCode() "-" <FOUR_DIGITS>) LocalNumber()
| CountryNumber()
) <EOF>
}
语义LOOKAHEAD
语义先行涉及在选择点将Java代码嵌入语法中。
如果Java代码返回true,则选择当前扩展。
void PhoneNumber() : {} {
(
LOOKAHEAD({getToken(1).image.equals("123")})
KeysvilleNumber()
| FarmvilleNumber()
) <EOF>
}
嵌套的前瞻
嵌套先行发生在一个先行指令重叠另一个先行指令时。在JavaCC中,嵌套先行会被忽略,但嵌套语义先行不会被忽略。]
void Start() : {} { ( LOOKAHEAD(Fullname()) Fullname() | Douglas() ) <EOF> } void Fullname() : {} { ( LOOKAHEAD(Douglas() Munro()) Douglas() | Douglas() Albert() ) Munro() } void Douglas() : {} { "Douglas" } void Albert() : {} { "Albert" }} void Munro() : {} { "Munro" }}
所有示例均摘自Awesome书Tom Copeland用JavaCC生成解析器
希望这很有用,谢谢。