Проблемы обработки ошибок с ANTLR3 - PullRequest
1 голос
/ 11 марта 2012

Я попытался сообщить об ошибке следующим образом.

@members{
    public String getErrorMessage(RecognitionException e,String[] tokenNames)
    {
        List stack=getRuleInvocationStack(e,this.getClass().getName());
        String msg=null;
        if(e instanceof NoViableAltException){
            <some code>
        }
        else{
            msg=super.getErrorMessage(e,tokenNames);
        }
        String[] inputLines = e.input.toString().split("\r\n");
        String line = "";
        if(e.token.getCharPositionInLine()==0)
            line =  "at \"" + inputLines[e.token.getLine() - 2];
        else if(e.token.getCharPositionInLine()>0)
            line =  "at \"" + inputLines[e.token.getLine() - 1];
        return ": " + msg.split("at")[0] + line + "\" => [" + stack.get(stack.size() - 1) + "]";
    }

    public String getTokenErrorDisplay(Token t){
        return t.toString();
    }
}

И теперь ошибки отображаются следующим образом.

line 6:7 : missing CLOSSB at "int a[6;" => [var_declaration]
line 8:0 : missing SEMICOL at "int p" => [var_declaration]
line 8:5 : missing CLOSB at "get(2;" => [call]

У меня 2 вопроса.

1)Есть ли правильный способ сделать то же самое, что я сделал?

2) Я хочу заменить CLOSSB, SEMICOL, CLOSB и т. Д. Их реальными символами.Как я могу сделать это, используя карту в файле .g?

Спасибо.

Ответы [ 2 ]

2 голосов
/ 11 марта 2012

1) Есть ли правильный способ сделать то же самое, что я сделал?

Я не знаю, существует ли определенный правильный способ показа ошибок.Мое представление об ошибках - это небольшой тест.Если пользователь может выяснить, как исправить ошибку, основываясь на том, что вы ему дали, то это хорошо.Если сообщение об ошибке выводит пользователя из строя, то сообщение требует дополнительной работы.Основываясь на примерах, приведенных в вопросе, символы были только символьными константами.

Мой любимый способ видеть ошибки - это линия со стрелкой, указывающей на местоположение.

т.е.

Ожидается закрывающая скобка в строке 6.

int a[6;
       ^

2) Я хочу заменить CLOSSB, SEMICOL, CLOSB и т. Д. Их реальными символами.Как я могу сделать это, используя карту в файле .g?

Вам нужно будет прочитать отдельно сгенерированный файл токена, а затем создать карту, то есть структуру данных словаря, чтобы перевести имя токена в символ токена.(s).

РЕДАКТИРОВАТЬ

Сначала мы должны уточнить, что означает символ.Если вы ограничиваете определение символа только токенами, которые определены в файле токенов с помощью символа или строки, то это можно сделать, т. Е. «!» = 13 или «public» = 92, если, однако, вы решили использовать определениеЕсли символом является любой текст, связанный с токеном, то это не то, чем я занимался или планирую адресовать.

Когда ANTLR генерирует свою карту токенов, он использует три разных источника:

  1. Символьные или строковые константы в лексере

  2. Символьные или строковые константы в анализаторе.

  3. Внутренние токены, такие как Invalid, Down, Up

Поскольку токены в лексере не являются полным набором, следует использовать токеныфайл в качестве отправной точки.Если вы посмотрите на файл токенов, то заметите, что самое низкое значение - 4. Если вы посмотрите на файл TokenTypes (это имя версии C #), вы найдете оставшиеся определенные токены.Если вы найдете имена, подобные T__, в файле токенов, это имена ANTLR, сгенерированные для литералов char / string в синтаксическом анализаторе.

Если вы используете строковые и / или символьные литералы в правилах синтаксического анализатора, тогда ANTLR долженсоздайте новый набор правил лексера, который включает все строковые и / или символьные литералы в правилах синтаксического анализатора.Помните, что анализатор может видеть только токены, а не необработанный текст.Поэтому строковые и / или символьные литералы не могут быть переданы в синтаксический анализатор.

Чтобы увидеть новый набор правил лексера, используйте org.antlr.Tool –Xsavelexer, а затем откройте созданный файл грамматики.Название может быть как .g.Если в правилах вашего синтаксического анализатора есть строковые и / или символьные литералы, вы увидите правила лексера с именем, начинающимся с T .

Теперь, когда вы знаете все токены и их значения, вы можете создать таблицу сопоставления из информации, приведенной в ошибке, со строкой, которую вы хотите вывести вместо символа.

Пример кода http://markmail.org/message/2vtaukxw5kbdnhdv#query:+page:1+mid:2vtaukxw5kbdnhdv+state:results.

Однако отображение токенов может измениться для таких вещей, как изменение правил в лексере или изменение литералов char / string всинтаксический анализатор.Так что, если сообщение внезапно выдает неправильную строку для символа, вам придется обновить таблицу сопоставления вручную.

Хотя это не идеальное решение, это возможное решение в зависимости от того, как вы определяетесимвол.

Примечание. В прошлый раз, когда я смотрел, ANTLR 4.x автоматически создавал таблицу для доступа в парсере, потому что это было такой проблемой для многих с ANTLR 3.x.

1 голос
/ 11 марта 2012

Бхатия писал:

* 1) Есть ли правильный способ сделать то же самое, что я сделал?

Нет единого способа сделать это. Обратите внимание, что правильная обработка ошибок и отчетность сложно. Теренс Парр проводит целую главу по этому вопросу в Подробном справочнике ANTLR (глава 10). Я рекомендую вам взять копию и прочитать ее.

Бхатия писал:

2) Я хочу заменить CLOSSB, SEMICOL, CLOSB и т. Д. Их реальными символами. Как я могу сделать это, используя карту в файле .g?

Ты не можешь. Для SEMICOL это может показаться простым, но как бы вы получили эту информацию для токена, подобного FOO:

FOO : (X | Y)+;

fragment X : '4'..'6';
fragment Y : 'a' | 'bc' | . ;
...