JavaCC自定义错误导致“扩展可以与空字符串匹配”。

时间:2018-05-03 16:50:11

标签: error-handling javacc

我希望让我的JavaCC解析器返回比默认值更具体的自定义错误消息。

我目前的基本结构是这样的:

Foo(): {} { (A() B())+ }
A():   {} { <TOKA1> | <TOKA2> }
B():   {} { <TOKB1> | <TOKB2> }

我一直在研究如何抛出自定义错误消息,标准方法似乎是这样的:

A():   {} { <TOKA1> | <TOKA2> 
          | {throw new ParseException("Expected A, found " + getToken(1).image + ".");} }

但是,在A和B上实现此操作会导致编译器产生错误:

Expansion within "(...)+" can be matched by empty string.

这是可以理解的,因为解析器“不知道”空选项将终止解析过程。它预测它可以匹配空字符串到无穷大。然而,我找不到或想到任何其他简单的方法来抛出这样的错误。达到我想要的结果的最佳方法是什么?

1 个答案:

答案 0 :(得分:1)

假设您的解析器在循环中进行了一次或多次跳转。当下一个令牌不是TOKA1或TOKA2时,你不希望解析器离开循环吗?

E.g。如果你的语法的其余部分是

void Start() : {} { Foo() C() <EOF> }

如果输入为

,您绝对不希望出现错误
 <TOKA1> <TOKB1> <TOKC> <EOF>

其中<TOKC>是可能位于C开头的一些标记。

所以我建议的是

 Foo(): {} { 
    AForSure()
    B() 
    (A() B())* }
 AForSure() : {} { A() | {throw new ParseException("Expected A, found " + getToken(1).image + ".");} }
 A():   {} { <TOKA1> | <TOKA2> }
 B():   {} { <TOKB1> | <TOKB2> | {throw new ParseException("Expected B, found " + getToken(1).image + ".");} }}

这可能无法为您提供所需的错误消息质量。例如。如果输入是

 <TOKA1> <TOKB1> <TOKB2> <EOF>

您可能会收到错误&#34;预期C,找到TOKB2&#34;。所以也许你想把这个错误改成&#34;预期的A或C,找到一个TOKB2&#34;。

另一种接近它的方法是使用递归而不是循环。假设你的列表总是在括号中,所以,例如,唯一使用Foo的是Bar和Bar看起来像这样

Bar() : {} { "(" Foo() ")" }

所以你只想在点击&#34;)&#34;时退出Foo循环。还有别的错误。您可以将语法重写为

 Bar() : {} { "(" A("A") B() MoreFoos() }

 MoreFoos() : {} {  ")" |  A("A or ')'") B() MoreFoos() }
 A(String expected):   {} { <TOKA1> | <TOKA2> 
    | {throw new ParseException("Expected "+expected+", found " + getToken(1).image + ".");} } }
 B():   {} { <TOKB1> | <TOKB2>
    | {throw new ParseException("Expected B, found " + getToken(1).image + ".");} }}