2016-01-20 1 views
0

Я разрабатываю грамматику для данного языка. Я считаю, что грамматика, которую я придумал, должна работать, но Antlr4 имеет другое мнение. Учитывая ошибки, он выглядит как пропавший backtracking. Но Antlr4 должен анализировать без этого ...Парсер Antlr4 терпит неудачу - требуется откат?

Каждый из примеров должен иметь ровно одно решение. Во время разбора есть двусмысленности, однако все, кроме одного, могут оказаться тупиками. Поэтому я ожидаю, что парсер вернется и попробует следующий подход. Но он просто сообщает о синтаксической ошибке.

Краткое описание грамматика: Есть элементы, разделенные символом '#'. После элемента может быть необязательный прыжок, который обозначается одним «=». Если сам элемент содержит '#' или '=', они экранируются путем их дублирования. Чтобы избежать двусмысленности, для элемента не допускается «#». Таким образом, '###' всегда является первым разделителем, а затем экранированным первым символом следующего элемента. A '####' не является разделителем, а всего лишь два escape-файла '#' внутри имени.

грамматик:

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 и начать подпроект, который начинается с: ##

@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. Парсер может разрешать двусмысленности через свою альтернативу возврату, но Лексер не может.

Так вот работает грамматика:

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

 Смежные вопросы

  • Нет связанных вопросов^_^