ANTLR - разрешить любой символ между ключевыми словами
Я хотел бы определить грамматику для простого языка.
Язык допускает какие-то задания.
пример
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" вещь!
Вы правы, грамматика, которую я постет выше, была неправильной, потому что я спешил.
Лучше попробовать это впереди. Проблема все еще в том, что токенизатор распознает, например, ключевое слово в определении аля
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;};
РЕДАКТИРОВАТЬ II
Боже мой, совершенно очевидно, что вы делаете это так, как вы это объяснили. Не знаю, почему я не получил это сам! Большое спасибо Тим за ваше объяснение!
У меня остался только один вопрос: если я определю свои токены для лексера и мою грамматику для парсера. Это общий способ проверки семантики в синтаксическом анализаторе дерева или в самом синтаксическом анализаторе?
Например, давайте предположим, что у меня есть та же самая грамматика, что и вы.
keyworda : ab
keywordb : xy
keyworda : ab1
keywordb : xy1
...
Теперь я хочу проверить, определено ли ключевое слово b после каждого определения ключевого слова. Позже я хочу проверить, правильно ли указано значение. Предположим, у нас есть ключевое слово extends: "ключевое слово", и мне нужно проверить, определено ли "ключевое слово".
Я мог бы сделать это двумя способами: во-первых, измените ваше правило грамматики для парсера и добавьте Java-код для проверок прямо здесь. Во-вторых, грамматика остается неизменной, и я определяю грамматику синтаксического анализатора дерева, чтобы проверить эти условия.
Я действительно не знаю, какой путь лучше, а какие преимущества или недостатки...
Большое спасибо за вашу помощь
1 ответ
.
имеет другое значение внутри правил лексера и парсера. Внутри правил лексера, он соответствует любому персонажу из диапазона \u000
...\uFFFF
, И внутри правил парсера, .
соответствует любому токену.
Обратите внимание, что правила лексера начинаются с заглавной буквы, а правила синтаксического анализатора начинаются со строчной буквы. Вы также можете создавать токены (правила лексера) как литералы внутри правил парсера. Это означает, что ваша грамматика будет создавать только 4 различных токена (на самом деле 3, так как NEWLINE
скрыт"):
'keyworda'
':'
'keywordb'
NEWLINE
(который удаляется из потока токенов по умолчанию)
( EOF
это встроенный токен)
Итак, это делает ваш anychar
Правило соответствует либо 'keyworda'
, ':'
или же'keywordb'
и нелюбой персонаж, как вы могли ожидать.
Кроме того, кажется, вы отделяетеkey ':' value
-вступления через разрывы строк, но вы удаляете разрывы строк во время фазы lexing. Удаляя их, как вы должны знать, что конец value
и что начало key
является? Ваш поток токенов будет представлять собой непрерывный поток ключевых слов, любые символы и двоеточия, поэтому невозможно определить, является ли ключевое слово действительно ключевым словом или частью value
(право на ':'
). Для этого вам нужен токен разрыва строки.
Похоже, вы начали использовать ANTLR, даже не зная, что делаете: IMO, это не способ освоить этот конкретный инструмент. Я рекомендую получить копию The Definitive ANTLR Reference или прочитать / просмотреть некоторые руководства ANTLR, прежде чем продолжить.
Удачи!
РЕДАКТИРОВАТЬ
Вот краткая демонстрация того, как позволить ключевому слову также быть частью вашего "значения":
файл: Tg
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!'