Antlr4解析器失败 - 需要回溯吗?

时间:2016-01-20 16:42:14

标签: java antlr4 ebnf

我正在为给定的语言开发语法。 我相信我提出的语法应该有用 - 但是Antlr4有不同意见。鉴于错误,它似乎缺少回溯。但是Antlr4应该在没有它的情况下进行解析......

每个示例都应该只有一个解决方案。在解析过程中存在歧义,但除了一个选项之外的所有选项都应该是死路一条。所以我希望解析器返回并尝试下一个可能的方法。但它只报告语法错误。

语法快速摘要: 有些元素由'#'分隔。在一个元素之后,可能会有一个可选的跳转,由一个'='表示。如果元素本身包含'#'或'=',则通过复制它们来转义它们。 为避免歧义,不允许元素以“#”结尾。因此'###'始终是分隔符,然后是下一个元素的转义第一个字符。 '####'不是分隔符,只是在名称中有两个转义'#'。

语法:

private void filterWorker_CompleteWork(object sender, RunWorkerCompletedEventArgs e)
    {
        PanelLoading = false;
        if (e.Error == null)
        {
            if (e.Cancelled) return;
            var products = (e.Result) as List<ProductDTO>;
            Products = products;
        }
        else
        {
            LogHelper.Log(e.Error);
        }
    }

测试,解析器错误为注释

grammar ConfigPath;
configpath: toplevelement subprojectelement* EOF;
subprojectelement:  '#' path jump?;
toplevelement:      '#' path jump?;
jump:   jumpcommand '=' jumpdestination;
jumpcommand: '#d' | '#devpath';
jumpdestination: NONHASHCHAR+;              
path: pathelement ( '/' pathelement)*;             
pathelement: escapedCharacterHash* escapedCharacter ;
escapedCharacterHash: escapedCharacter | '##';
escapedCharacter: NONHASHCHAR | '==';
NONHASHCHAR: ~('#' | '/' | '=' );
HASH: '#';
EQ: '=';

由于pathelement不能以散列结束,因此三重散列中的第一个应该关闭toplevelelement并启动子项目元素,该子项目以##

开头
@Test
public void testTripleHash() throws Exception {
    ConfigpathContext c = parse("#BU/ConfigPath###sub"); 
    // line 1:16 extraneous input '#' expecting {'##', '==', NONHASHCHAR}

    Assert.assertEquals( "#BU/ConfigPath", c.toplevelement().getText() );
    Assert.assertEquals( "###sub", c.subprojectelement().get(0).path().getText() );
}

有没有办法改变语法来接受测试? 或者Antlr4是不是能够解析这样的语法?具有回溯功能的Antlr3会找到解决方案吗?

1 个答案:

答案 0 :(得分:0)

语法错了 - 感谢cantSleepNow说明了这一点。

虽然我还没有理解问题的每一个细节,但它似乎与Lexer中的含糊不清有关。解析器能够通过替代回溯来解决歧义,但Lexer无法解决。

所以这是工作语法:

import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd

tips = sns.load_dataset("tips")

sns.stripplot(x="day", y="total_bill", hue="smoker",
data=tips, jitter=True,
palette="Set2", split=True,linewidth=1,edgecolor='gray')

# Get the ax object to use later.
ax = sns.boxplot(x="day", y="total_bill", hue="smoker",
data=tips,palette="Set2",fliersize=0)

# Get the handles and labels. For this example it'll be 2 tuples
# of length 4 each.
handles, labels = ax.get_legend_handles_labels()

# When creating the legend, only use the first two elements
# to effectively remove the last two.
l = plt.legend(handles[0:2], labels[0:2], bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.)