语法LaTeX像混合空白utf和命令一样

时间:2019-03-26 21:57:30

标签: whitespace grammar antlr4

我试图实现像LaTeX这样的语法,可以让我解析这种句子:

\title{Un pré é"'§è" \VAR state \draw( 200\if{expression kjlkjé} ) bis tèr }

如您所见,\ title {}可以包含多种项目:

    utf8中的
  • 字符串(不带引号和空格),我想 保留一个令牌

  • 变量调用为:\ variable_name

  • 一些\关键字后跟括号或其他带有花括号的关键字:例如\ draw(utf8 \ var \ if {} ...)或\ if {idem}。

这些项目可以嵌套。

我从ANTLR 4书中介绍的XML解析器中得到启发,并尝试使用模式。我遇到一个有关识别圆括号的大括号的问题。我也遇到了一些空格问题,例如遵循\ 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生成的此生成树

enter image description here

感谢您的帮助,以帮助我解决此问题。 克里斯

1 个答案:

答案 0 :(得分:1)

问题是expression后的空格:

\title{Un pré é"'§è" \VAR state \draw( 200\if{expression kjlkjé} ) bis tèr }
                                                        ^
                                                        ^
                                                        ^

导致模式返回到DEFAULT_MODE

CLOSECALLVAR : ' ' -> mode(DEFAULT_MODE) ;

因为(显然)仍处于CALLREFERENCE上下文中而不需要的东西。

一种解决方法是使用-> pushMode(...)-> popMode伪指令,这些伪指令导致创建CALLREFERENCE模式的堆栈。每当您偶然发现\... (\... {时,都会将新的CALLREFERENCE推入该堆栈,然后在看到)}时弹出一个。

一个快速的词法分析器语法演示:

lexer grammar OEFLexer;

TITLE   : '\\title' S? OB -> pushMode(CALLREFERENCE);

fragment OB : '{';
fragment OP : '(';
fragment S : [ \t\r\n]+;

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
 ;

解析您的示例输入将产生以下解析树:

enter image description here