Грамматический LaTeX like со смешанным пробелом utf и командами

#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
 ;
  

Анализ вашего примера ввода приведет к следующему дереву синтаксического анализа:

введите описание изображения здесь