【问题标题】:Grammar LaTeX like with mixed whitespace utf and commands语法 LaTeX,如混合空格 utf 和命令
【发布时间】:2019-03-27 15:59:42
【问题描述】:

我尝试实现一个类似于 LaTeX 的语法,它可以让我解析这种句子:

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

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

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

  • 变量调用为:\variable_name

  • 一些 \keyword 后跟括号或其他大括号:例如 \draw( utf8 \var \if{ } ... ) 或 \if{ idem }。

这些项目可以嵌套。

我从 ANTLR 4 书中介绍的 XML 解析器获得灵感并尝试使用模式。我遇到了一个关于识别右括号的右括号的问题。我还遇到了一些空格的问题,例如遵循 \variable_name 的那个(我得到一个:无关输入'')。

这是我的词法分析器语法代码:

 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 生成的生成树

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

【问题讨论】:

    标签: whitespace grammar antlr4


    【解决方案1】:

    问题是expression后面的空格:

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

    这会导致模式回到DEFAULT_MODE

    CLOSECALLVAR : ' ' -> mode(DEFAULT_MODE) ;
    

    你不想要的东西,因为你(显然)仍然在 CALLREFERENCE 上下文中。

    处理此问题的一种方法是使用-&gt; pushMode(...)-&gt; 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
     ;
    

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

    【讨论】:

      猜你喜欢
      • 2011-11-26
      • 1970-01-01
      • 2022-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-25
      • 2011-10-27
      • 2012-05-02
      相关资源
      最近更新 更多