我正在构建一个ANTLR4语法来解析来自数据源的字符串 - 类似的,如果不是和StringTemplate几乎相同,除非我不喜欢这种语法所以我自己编写了自己的语法(也只是为了娱乐和学习,因为这是我第一次体验w / ANTLR)。我的语法目前看起来像这样(这比我实际拥有的简化,但我已经证实它是一个很好的例子"并且展示了我所问的同样的问题):
grammar Combined1;
file:
.*? (repToken .*?)+
| .*?
;
foreach: '@foreach' WS* '(' WS* repvar WS* ')' WS* '{' content=file '}' ;
with: '@with' WS* '(' WS* repvar WS* ')' WS* '{' content=file '}' ;
// withx: '@withx' WS* '(' WS* repvar WS* ')' WS* '{' content=file '}' ;
repvar: '@' (
'$'
| '(' nestedIdentifier ')'
| nestedIdentifier
) ;
repToken:
foreach
| with
// | withx
| repvar
;
nestedIdentifier: Identifier ('.' Identifier)* ;
Identifier: [A-Za-z_] [A-Za-z0-9_]* ;
WS: [ \t\r\n] ;
Other: ( . ) ;
这个语法很好用,允许我执行替换,例如:
string template = "Test: @foreach(@list){@$}";
Process(template, new { list = new [] { "A", "B", "C" } });
,结果将是:
Test: ABC
(我如何处理树以获得此结果的机制相对简单但与问题无关,因此我没有提供该代码。)
我的问题是......如果我包括(取消注释)" withx"规则正好位于with:
规则 之下,我忘了在withx
中包含(取消注释)repToken
替代品,然后我的上面的示例中断,即使它与withx
完全无关。在我添加withx
作为repToken
的替代后,我的示例再次起作用。为什么?
以下是我所知道的:
withx
,我的词法分析器都是正确的
返回12个代币:Test
,:
,' '
,@foreach
,(
,@
,list
,
)
,{
,@
,item
。这并不令人惊讶,因为我只添加了一个
解析器规则,而不是触及词法分析器令牌(除了添加
一个隐含的令牌' @withx')。 withx
规则之前,我的
解析器正确地将@foreach之后的所有标记分组为子项
ForeachContext,产生一个包含4个子节点的FileContext(3
TerminalNodeImpl和RepTokenContext)。 withx
后
规则,我的解析器由于某种原因不能识别其余部分
令牌属于ForeachContext,产生FileContext
有10个孩子,其中没有一个是ForeachContext,但却有
所有TerminalNodeImpl都有2个与@list对应的RepTokenContext
和@ $。我完全不知道为什么添加一个与我的输入没有任何关系的解析器规则会导致我的解析器失败。救命啊!?
EDIT 3/17/2014: JavaMan要求在每个方案中使用解析树来阐明上述说明。我不知道如何生成他所做的解析树图形,但是这里有来自Visual Studio调试器的两个屏幕截图,说明了差异......请注意,在这些图像中我使用更长的名称 - 具体来说,ReplacementTokenContext是为repToken。
第一个是当我在备用列表中包含withx
时(注意树本质上是FileContext - > ReplacementTokenContext(节点索引3) - > ForeachContext):
第二个是当我不在备用列表中包含withx
时(注意树本质上是FileContext - > TerminalNodeImpl" @ foreach"(节点索引3):
答案 0 :(得分:0)
使用您的整个语法加上withx
规则和2行输入,我能够获得此解析树节点repToken
将@foreach输入文本分组到foreach
节点下:
对我来说,这似乎是一个正确的解析。这是你想要的吗?你的访客代码有问题吗?你得到了同样的解析树吗?如果你可以在这里发布你的解析树会更好。
顺便说一下,如何将所有空格发送到隐藏通道并从解析器规则中删除所有WS标记呢?
修改强>:
我只使用带有Java目标的ANTLR4 V4.1,因此无法确定它是否是C#目标或v4.2的错误。但是这两种语法在Java中都给了我相同的解析树。有一个名为TestRig的工具(至少在Java目标中)可以生成GUI或ASCII形式的解析树:
java org.antlr.v4.runtime.misc.TestRig Combine1 file -tree in.cpp > treeres.txt
通过使用你提到的2个语法版本和相同的输入文件运行上面的命令,我得到了解析树的相同ASCII表示:
(file string template = " Test : (repToken (foreach @foreach ( (repvar @ (nestedIdentifier list)) ) { (file (repToken (repvar @ $))) })) " ; \r \n Process ( template , new { list = new [ ] { " A " , " B " , " C " } } ) ;)
图形输出太大,所以我不在这里包含它们。因此,至少在Java中,使用或不使用withx
规则生成相同的解析树。
我建议您仔细检查TestRig工具或尝试使用Java目标进行验证。