#whitespace #grammar #antlr4
#пробелы #грамматика #antlr4
Вопрос:
Я попытался реализовать грамматику, подобную LaTeX, которая позволила бы мне анализировать предложения такого типа :
title{Un pré é"'§è" VAR state draw( 200if{expression kjlkjé} ) bis tèr }
Как вы можете видеть, title{ } может содержать несколько типов элементов :
-
строка в utf8 без кавычек и с пробелом, которую я хотел бы сохранить в одном токене
-
вызов переменной как: variable_name
-
какое-нибудь ключевое слово , заключенное в круглые скобки, или другое с фигурными скобками : например draw( utf8 var if{ } … ) или if{idem}.
Эти элементы могут быть вложенными.
Я черпаю вдохновение из синтаксического анализатора XML, представленного в книге ANTLR 4, и пытаюсь использовать mode. Я сталкиваюсь с проблемой, касающейся распознавания закрывающих фигурных скобок закрывающих круглых скобок. Я также сталкиваюсь с проблемой с некоторыми пробелами, например с тем, который следует за variable_name (я получаю: посторонний ввод ‘ ‘).
Вот мой код lexer gramar :
lexer grammar OEFLexer;
// Default mode rules (the SEA)
SEA_WS : (' '|'t'|'r'? 'n') ;
TITLE : '\title';
OB : '{';
OP : '(';
BSLASH : '\' -> mode(CALLREFERENCE) ;
TEXT : ~[\({] ; // clump all text together
// ----------------- Everything Callreference ---------------------
mode CALLREFERENCE;
CLOSECALLVAR : ' ' -> mode(DEFAULT_MODE) ; // back to SEA mode
CB : '}' -> mode(DEFAULT_MODE) ; // back to SEA mode
CP : ')' -> mode(DEFAULT_MODE) ; // back to SEA mode
DRAW : 'draw' OP;
IF : 'if' OB;
ID : [a-zA-Z] ; // match/send ID in tag to parser
Вот моя грамматика синтаксического анализатора
parser grammar OEFParser;
options { tokenVocab=OEFLexer; }
document: TITLE OB ( callreference | string )* CB;
string : TEXT;
var : ID;
commandDraw : DRAW ( callreference | string )* CP ;
commandIf : IF ( callreference | string )* CB ;
callreference : BSLASH ID | BSLASH commandDraw CP | BSLASH commandIf CP;
Когда я попытался проанализировать код title, упомянутый в начале, я получаю :
line 1:25 extraneous input ' ' expecting {'', TEXT, '}'}
line 1:37 extraneous input ' ' expecting {'', TEXT, ')'}
line 1:45 mismatched input 'expression' expecting {'', TEXT, '}'}
line 1:75 extraneous input '<EOF>' expecting {'', TEXT, ')'}
С этим сгенерированным деревом, сгенерированным Grun
Спасибо за вашу помощь, чтобы помочь мне решить эту проблему. Крис
Ответ №1:
Проблема в пробеле после expression
:
title{Un pré é"'§è" VAR state draw( 200if{expression kjlkjé} ) bis tèr }
^
^
^
что приводит к возврату режима к DEFAULT_MODE
:
CLOSECALLVAR : ' ' -> mode(DEFAULT_MODE) ;
Что-то, чего вы не хотите, потому что вы (очевидно) все еще находитесь в CALLREFERENCE
контексте.
Один из способов справиться с этим — использовать директивы -> pushMode(...)
и -> popMode
, которые вызывают создание стека CALLREFERENCE
режимов. Всякий раз, когда вы натыкаетесь на ... (
и ... {
, вы помещаете новый CALLREFERENCE
в этот стек, а затем удаляете его, когда видите )
или }
.
Краткая демонстрация грамматики lexer:
lexer grammar OEFLexer;
TITLE : '\title' S? OB -> pushMode(CALLREFERENCE);
fragment OB : '{';
fragment OP : '(';
fragment S : [ trn] ;
mode CALLREFERENCE;
CB : '}' -> popMode;
CP : ')' -> popMode;
DRAW : '\draw' S? OP -> pushMode(CALLREFERENCE);
IF : '\if' S? OB -> pushMode(CALLREFERENCE);
BSLASH : '\';
ID : [a-zA-Z] ;
CR_OTHER : .;
и грамматика синтаксического анализатора:
parser grammar OEFParser;
options { tokenVocab=OEFLexer; }
document
: TITLE ( callreference | string )* CB EOF
;
string
: CR_OTHER
| ID
;
commandDraw
: DRAW ( callreference | string )* CP
;
commandIf
: IF ( callreference | string )* CB
;
callreference
: BSLASH ID
| commandDraw
| commandIf
;
Анализ вашего примера ввода приведет к следующему дереву синтаксического анализа: