2016-01-20 111 views
0

我正在開發給定語言的語法。 我相信我所提出的語法應該可行 - 但Antlr4有不同的意見。鑑於這些錯誤,它看起來像缺少回溯。但Antlr4應該解析沒有...Antlr4解析器失敗 - 需要回溯?

每個例子應該只有一個解決方案。解析過程中有些含糊不清,但除了一個選項外,其他所有選項都應該是死衚衕。所以我期待解析器回去嘗試下一種可能的方法。但它只是報告一個語法錯誤。

語法快速彙總: 有些元素被'#'分隔。在一個元素之後,可以有一個可選的跳轉,這個跳轉由一個'='表示。如果元素本身包含'#'或'=',則通過複製它們來轉義它們。 爲避免歧義,元素不允許以'#'結尾。所以'###'總是第一個分隔符,然後是下一個元素的轉義第一個字符。 '####'不是分隔符,只有兩個名字裏面的'#'。

的語法:

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: '='; 

測試,以分析器錯誤的評論

@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()); 
} 

由於pathelement不能以哈希結束,第一三重散列應該關閉toplevelelement和啓動subprojectelement,以a開頭##

@Test 
public void testDoubleHash() throws Exception { 
    ConfigpathContext c = parse("#BU/proj##bla#d==u##bla"); 
    // line 1:15 mismatched input '==' expecting '=' 

    Assert.assertEquals("#BU/proj##bla", c.toplevelement().getText()); 
    Assert.assertEquals("#d==u##bla", c.subprojectelement().get(0).getText()); 
} 

@Test 
public void testJumps() throws Exception { 
    ConfigpathContext c = parse("#BU/pro##dla#du##d==la#d=dest"); 
    // line 1:14 missing '=' at 'u' 

    Assert.assertEquals("#BU/pro##dla", c.toplevelement().getText()); 
    Assert.assertEquals(1, c.subprojectelement().size()); 
    Assert.assertEquals("#du##d==la", c.subprojectelement().get(0).path().getText()); 
    Assert.assertEquals("dest", c.subprojectelement().get(0).jump().jumpdestination().getText()); 
} 


private ConfigpathContext parse(String src) { 
    ConfigPathParser parser = new ConfigPathParser(new CommonTokenStream(new ConfigPathLexer(new ANTLRInputStream(src)))); 
    parser.addErrorListener(new BaseErrorListener() { 
     @Override 
     public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) { 
      throw new RuntimeException("line " + line + ":" + charPositionInLine + " " + msg); 
     } 
    }); 
    return parser.configpath(); 
} 

有什麼方法可以改變接受測試的語法? 還是Antlr4只是無法解析這樣的語法?帶回溯的Antlr3會找到解決方案嗎?

+0

你的語法是錯誤的 - 假設分析器應該接受你的例子。只有一些提示 - 解析器和詞法分析器檢測到第一條規則,因此您需要確保沒有歧義。如果你要使用antlrworks這樣的東西,你會看到什麼規則被識別等等 – cantSleepNow

回答

0

語法錯了 - 感謝cantSleepNow的陳述。

雖然我沒有理解問題的每一個細節,但它似乎與Lexer中的含糊之處有關。解析器能夠通過替代回溯來解決歧義,但Lexer不能。

因此,這裏的工作語法:

grammar ConfigPath; 

configpath: toplevelement subprojectelement* EOF; 

subprojectelement: '#' path jump?; 

toplevelement:  '#' path jump?; 

jump: jumpcommand '=' jumpdestination; 

jumpdestination : string; 

jumpcommand: HASH D 'devpath'?; 

path: pathelement ('/' pathelement)*;    
pathelement: escapedCharacterHash* escapedCharacter ; 

escapedCharacterHash: escapedCharacter | HASH HASH; 
escapedCharacter: string | EQ EQ; 
string : (NONHASHCHAR | D)+; 
NONHASHCHAR: ~('#' | '/' | '=' | 'd'); 
D: 'd'; 
HASH: '#'; 
EQ: '=';