我在一次传递(整个文件)解析时有一个正常的语法。
现在我希望将解析分解为组件。并在子规则上运行解析器。我遇到了一个问题,我假设其他解析子规则会看到以下规则:
thing : LABEL? THING THINGDATA thingClause?
//{System.out.println("G4 Lexer/parser thing encountered");}
;
...
thingClause : ',' ID ( ',' ID)?
;
当从解析为EOF的顶级开始规则解析上述规则时,一切正常。当解析为子规则(不解析为EOF)时,解析器在没有thing子句时会感到沮丧,因为它期望看到一个“,”字符或EOF字符。
第8行:0输入'%'不匹配期待{,','}
当我解析为EOF时,%被正确解析为另一个“thing”组件,因为顶级规则查找:
toprule : thing+
| endOfThingsTokens
;
并且在EOF之前发生了endOfThingsTokens ...所以我希望这就是顶级规则有效的原因。
为了解析子规则,我希望ANTLR4解析器接受或忽略%标记并说“OK我们没有看到thingClause”,然后重置令牌流,以便下一个对象可以被另一个实例解析解析器。
在这种特定情况下,我可以更改词法分析器以将换行符传递给解析器,我目前在词法分析器语法中跳过该解析器。这将需要许多其他更改来接受当前不需要的令牌流中的换行符。
基本上我需要一些方法来使规则具有“记录结束”令牌。但我想知道是否有某种方法可以用语义谓词规则来解决这个问题。
类似的东西:
thing : { if comma before %}? LABEL? THING THINGDATA thingClause?
| LABEL? THING THINGDATA
;
...
thingClause : ',' ID ( ',' ID)?
;
上面的谓词伪代码会隐藏可选的thingClause?如果它不满意,那么解析器在解析一个“东西”之后就会停止而不寻找特定的“事物结束”标记(即换行符)。
如果我解决了这个问题,我会发布答案。
答案 0 :(得分:1)
解析器将(有效地)在令牌流中向前看以确定是否可以满足当前规则。然后消耗相应的令牌。如果任何前瞻令牌仍然未被占用,则解析器会查找另一个规则来消耗这些令牌和其他前瞻令牌。
thingClause?
元素在未匹配时将导致解析器中未使用的令牌。因此你看到了错误。
解析器前瞻是数据相关的。这意味着对规则元素的评估可以很容易地将解析器读入比当前规则可能消耗的更多令牌。
虽然谓词可能有所帮助,但它不会使问题具有确定性。也就是说,即使解析器与非谓词alt匹配,它也可能在解析器中读取的标记多于该alt可以使用的标记。
避免这种非确定性的唯一方法是将<EOF>
令牌预先注入子规则边界的令牌流中。