ANTLR - разрешить любой символ между ключевыми словами - PullRequest
4 голосов
/ 02 сентября 2011

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

Язык допускает какие-то задания.

Пример

keyworda: this is the 1 keyword-A
keywordb: this is the second keywordb
...

Дело в том,что после ключевого слова и ':' любой символ должен быть возможен (ключевое слово тоже)

Я много чего перепробовал, но думаю, что я все еще не так в мышлении лексера и парсера ...

Моя последняя идея не удалась:

rule 
  :  'keyworda' ':' anychar* 'keywordb' ':' anychar* EOF 
  ;

anychar
  :  .
  ;

NEWLINE
  :  ('\r'? '\n') {$channel=HIDDEN;}
  ;

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

Прежде всего: спасибо за ваш ответ!

Я прочитал руководство и посмотрелучебные пособия Скотта Стэнчфилда.

Проблема в том, что я не понимаю "anychar" вещь!

Вы правы, грамматика, которую я постет выше, была неправильной, потому что я спешил.

Лучше попробовать, это впереди.Проблема по-прежнему заключается в том, что токенизатор распознает, например, ключевое слово, например, в определении ala

keyworda : this is keyworda.
keywordb : this is another key!
...

Грамматика:

rule
    :   KEYA ':' STRING_LITERAL* NEWLINE
        keybdefinition*
         EOF
    ;

keybdefinition
    :   KEYB ':' STRING_LITERAL* NEWLINE
    ;


KEYA: 'keyworda';
KEYB:'keywordb';
STRING_LITERAL: 'a'..'z' | 'A'..'Z' | '0'..'9' | ':' | '.' | '&' | '/' | '\\' | ';';

NEWLINE: '\r'? | '\n'; 
SPACE:  (' ' | '\t') {$channel=HIDDEN;};

EDIT II

Боже мой, это очевидносделать так, как ты это объяснил.Не знаю, почему я не получил это сам!Большое спасибо Тиму за ваше объяснение!

У меня остался еще один вопрос: если я определю свои токены для лексера и мою грамматику для парсера.Это обычный способ проверки семантики в синтаксическом анализаторе дерева или в самом синтаксическом анализаторе?

Например, давайте предположим, что у меня есть та же самая грамматика, определенная вами, что и вы.

keyworda : ab
keywordb : xy
keyworda : ab1
keywordb : xy1
...

СейчасЯ хочу проверить, если после каждого ключевого слова определено ключевое слово b.Позже я хочу проверить, правильно ли указано значение.Предположим, у нас есть ключевое слово extends: «значение ключа», и мне нужно проверить, определено ли «значение ключа».

Я мог бы сделать это двумя способами: во-первых, изменить правило грамматики для анализатораи добавьте Java-код для проверок прямо здесь.Во-вторых, грамматика остается неизменной, и я определяю грамматику синтаксического анализатора дерева для проверки этих условий.

Я не знаю, какой путь лучше, а какие преимущества или недостатки ...

Большое спасибо за вашу помощь

1 Ответ

16 голосов
/ 02 сентября 2011

. имеет другое значение в правилах лексера и парсера. В правилах лексера он соответствует любому символу из диапазона \u000 ... \uFFFF. А внутри правил парсера . соответствует любому токену.

Обратите внимание, что правила лексера начинаются с заглавной буквы, а правила синтаксического анализатора начинаются со строчной буквы. Вы также можете создавать токены (правила лексера) как литералы внутри правил синтаксического анализатора. Это означает, что ваша грамматика будет создавать только 4 различных токена (на самом деле 3, поскольку NEWLINE «скрыто»):

  • 'keyworda'
  • ':'
  • 'keywordb'
  • NEWLINE (который удаляется из потока токенов по умолчанию)

(EOF - встроенный токен)

Таким образом, ваше anychar правило соответствует либо 'keyworda', ':' или 'keywordb', а не любому символу , как вы могли ожидать.

Кроме того, кажется, что вы разделяете свои key ':' value -вступы на разрывы строк, но вы удаляете разрывы строк во время фазы lexing. Удаляя их, как вы узнаете, каков конец value и каков начало key? Ваш поток токенов будет представлять собой один непрерывный поток ключевых слов , любых символов и двоеточий , поэтому невозможно определить, является ли ключевое слово действительно ключевым словом, или часть value (справа от ':'). Для этого вам нужен токен разрыва строки.

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

Удачи!

EDIT

Вот небольшая демонстрация того, как сделать ключевое слово частью вашей "ценности":

файл: T.g

grammar T;

parse
  :  line+ EOF
  ;

line
  :  key COLON value eol 
     {System.out.printf("key='\%s', value='\%s'\n", $key.text, $value.text);}
  ;

value
  :  any_except_newline*
  ;

key
  :  KEYA
  |  KEYB
  ;

any_except_newline
  :  COLON
  |  KEYA
  |  KEYB
  |  WORD
  |  ANYCHAR
  ;

eol
  :  NEWLINE
  |  EOF
  ;

COLON   : ':';
KEYA    : 'keyworda';
KEYB    : 'keywordb';
WORD    : ('a'..'z' | 'A'..'Z')+;
NEWLINE : '\r'? '\n' | '\r';
SPACE   : (' ' | '\t') {$channel=HIDDEN;};
ANYCHAR : .; 

файл: Main.java

import org.antlr.runtime.*;

public class Main {
  public static void main(String[] args) throws Exception {
    String source = 
        "keyworda : this is keyworda.\n" + 
        "keywordb : this is another key!";
    TLexer lexer = new TLexer(new ANTLRStringStream(source));
    TParser parser = new TParser(new CommonTokenStream(lexer));
    parser.parse();
  }
}

Если вы сейчас запустите демонстрацию, выполнив:

java -cp antlr-3.3.jar org.antlr.Tool T.g
javac -cp antlr-3.3.jar *.java
java -cp .:antlr-3.3.jar Main

вы бы хотели, чтобы после печати на консоль:

key='keyworda', value='this is keyworda.'
key='keywordb', value='this is another key!'
...