2013-08-17 1 views
2

Я хочу написать лексер с несколькими режимами. Но режимы в основном похожи. Единственное различие заключается в том, что я ссылаюсь на один и тот же символ под другим именем. У меня это работает, проблема в том, что мне нужно скопировать весь лексер, чтобы изменить все имена, добавить типы и добавить одну строку для каждого режима.antlr4 правила обмена в режимах

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

Еще одна вещь, когда-то внутри '[' не было бы возможности вернуться к запятой с высоким приоритетом. Поэтому, когда грамматика переходит в раздел '{', '}', запятая возвращается к высокому приоритету.

Для этого у меня есть начальный режим по умолчанию плюс CONJUNCTION (высокий приоритет) и NON_CONJUNCTION (низкий приоритет). Я копирую все правила из режима по умолчанию и переименовываю их в C_ или NC_. Затем я верну их тип типа режима по умолчанию.

Я бы предпочел выполнить это, не справляясь, переименовывая и присваивая типы всем правилам из режима по умолчанию.

Вот мой лексер:

lexer grammar DabarLexer; 

OPEN_PAREN : '(' -> pushMode(NON_CONJUNCTION) ; 
CLOSE_PAREN : ')' -> popMode; 
OPEN_BRACKET : '[' -> pushMode(NON_CONJUNCTION) ; 
CLOSE_BRACKET : ']' -> popMode ; 
OPEN_CURLY : '{' -> pushMode(CONJUNCTION) ; 
CLOSE_CURLY : '}' -> popMode ; 
SPACE : ' ' ; 
HEAVY_COMMA : ','; 
ENDLINE : '\n' ; 
PERIOD : '.' ; 
SINGLE_QUOTE : '\'' ; 
DOUBLE_QUOTE : '"' ; 
INDENTION : '\t' -> skip; 

fragment SYMBOL : HEAVY_COMMA | OPEN_BRACKET | CLOSE_BRACKET | OPEN_PAREN | CLOSE_PAREN | OPEN_CURLY | CLOSE_CURLY | SPACE | ENDLINE | PERIOD | SINGLE_QUOTE | DOUBLE_QUOTE | INDENTION ; 
ESCAPE : '\\' SYMBOL ; 

fragment NON_SYMBOL : ~[(){}',; \n.\t"\[\]] ; 
IDENTIFIER : (NON_SYMBOL | ESCAPE)+ ; 
LITERAL : (SINGLE_QUOTE (NON_SYMBOL | ESCAPE)+ SINGLE_QUOTE) | DOUBLE_QUOTE (NON_SYMBOL | ESCAPE)+ DOUBLE_QUOTE ; 

mode CONJUNCTION ; 
C_HEAVY_COMMA : ',' -> type(HEAVY_COMMA); 

C_OPEN_PAREN : '(' -> type(OPEN_PAREN), pushMode(NON_CONJUNCTION) ; 
C_CLOSE_PAREN : ')' -> type(CLOSE_PAREN), popMode; 
C_OPEN_BRACKET : '[' -> type(OPEN_BRACKET), pushMode(NON_CONJUNCTION) ; 
C_CLOSE_BRACKET : ']' -> type(CLOSE_BRACKET), popMode ; 
C_OPEN_CURLY : '{' -> type(OPEN_CURLY), pushMode(CONJUNCTION) ; 
C_CLOSE_CURLY : '}' -> type(CLOSE_CURLY), popMode ; 
C_SPACE : ' ' -> type(SPACE); 
C_ENDLINE : '\n' -> type(ENDLINE); 
C_PERIOD : '.' -> type(PERIOD); 
C_SINGLE_QUOTE : '\'' -> type(SINGLE_QUOTE); 
C_DOUBLE_QUOTE : '"' -> type(DOUBLE_QUOTE); 
C_INDENTION : '\t' -> type(INDENTION),skip; 

fragment C_SYMBOL : (HEAVY_COMMA | C_OPEN_BRACKET | C_CLOSE_BRACKET | C_OPEN_PAREN | C_CLOSE_PAREN | C_OPEN_CURLY | C_CLOSE_CURLY | C_SPACE | C_ENDLINE | C_PERIOD | C_SINGLE_QUOTE | C_DOUBLE_QUOTE | C_INDENTION) ; 
C_ESCAPE : '\\' C_SYMBOL -> type(ESCAPE); 

fragment C_NON_SYMBOL : ~[(){}',; \n.\t"\[\]] ; 
C_IDENTIFIER : (C_NON_SYMBOL | C_ESCAPE)+ -> type(IDENTIFIER); 
C_LITERAL : ((C_SINGLE_QUOTE (C_NON_SYMBOL | C_ESCAPE)+ C_SINGLE_QUOTE) | C_DOUBLE_QUOTE (C_NON_SYMBOL | C_ESCAPE)+ C_DOUBLE_QUOTE) -> type(LITERAL); 



mode NON_CONJUNCTION ; 
LIGHT_COMMA : ',' ; 

NC_OPEN_PAREN : '(' -> type(OPEN_PAREN), pushMode(NON_CONJUNCTION) ; 
NC_CLOSE_PAREN : ')' -> type(CLOSE_PAREN), popMode; 
NC_OPEN_BRACKET : '[' -> type(OPEN_BRACKET), pushMode(NON_CONJUNCTION) ; 
NC_CLOSE_BRACKET : ']' -> type(CLOSE_BRACKET), popMode ; 
NC_OPEN_CURLY : '{' -> type(OPEN_CURLY), pushMode(CONJUNCTION) ; 
NC_CLOSE_CURLY : '}' -> type(CLOSE_CURLY), popMode ; 
NC_SPACE : ' ' -> type(SPACE); 
NC_ENDLINE : '\n' -> type(ENDLINE); 
NC_PERIOD : '.' -> type(PERIOD); 
NC_SINGLE_QUOTE : '\'' -> type(SINGLE_QUOTE); 
NC_DOUBLE_QUOTE : '"' -> type(DOUBLE_QUOTE); 
NC_INDENTION : '\t' -> type(INDENTION),skip; 

fragment NC_SYMBOL : (LIGHT_COMMA | NC_OPEN_BRACKET | NC_CLOSE_BRACKET | NC_OPEN_PAREN | NC_CLOSE_PAREN | NC_OPEN_CURLY | NC_CLOSE_CURLY | NC_SPACE | NC_ENDLINE | NC_PERIOD | NC_SINGLE_QUOTE | NC_DOUBLE_QUOTE | NC_INDENTION) ; 
NC_ESCAPE : '\\' NC_SYMBOL -> type(ESCAPE); 

fragment NC_NON_SYMBOL : ~[(){}',; \n.\t"\[\]] ; 
NC_IDENTIFIER : (NC_NON_SYMBOL | NC_ESCAPE)+ -> type(IDENTIFIER); 
NC_LITERAL : ((NC_SINGLE_QUOTE (NC_NON_SYMBOL | NC_ESCAPE)+ NC_SINGLE_QUOTE) | NC_DOUBLE_QUOTE (NC_NON_SYMBOL | NC_ESCAPE)+ NC_DOUBLE_QUOTE) -> type(LITERAL); 

ответ

3

Ваше текущее решение очень похоже на решение, которое я использую. Например, взгляните на TemplateComment mode грамматики, которую я использую для поддержки StringTemplate 4 в ANTLRWorks 2. Одна полезная вещь, которую я внедрил в ANTLR 4 некоторое время назад, это не будет создавать повторяющиеся типы токенов для правила в этой форме.

// No TemplateComment_NEWLINE token type is created here, because the 
// type(NEWLINE) action means this rule produces tokens of a specific type. 
TemplateComment_NEWLINE : NEWLINE -> type(NEWLINE), channel(HIDDEN); 
+0

Я рассмотрел вашу ссылку. Решения они такие же. Определенно использование этого типа позволяет ограничить объем дублирования. Он позволяет синтаксическому анализатору один тип, даже если парсер упоминает несколько. То же самое можно сказать и о парсере. У меня нет кредита, чтобы выбрать ваш ответ. – dodtsair