【问题标题】:ANTLR generated parser produces MissingTokenExceptionANTLR 生成的解析器产生 MissingTokenException
【发布时间】:2012-02-11 17:43:28
【问题描述】:

我正在使用 ANTLRv3 解析如下所示的输入:

* this is an outline item at level 1
** item at level 2
*** item at level 3
* another item at level 1
* an item with *bold* text

行首的星号表示大纲项目的开始。星号也可以是项目文本的一部分(例如*bold*)。

这是在项目文本中不支持星号的情况下解析大纲项目的语法:

outline_item: OUTLINE_ITEM_MARKER ITEM_TEXT;
OUTLINE_ITEM_MARKER: STAR_IN_COLUMN_ZERO STAR* (' '|'\t');
ITEM_TEXT: ('a'..'z'|'A'..'Z'|'0'..'9'|'\r'|'\n'|' '|'\t')+;
fragment STAR_IN_COLUMN_ZERO: {getCharPositionInLine()==0}? '*';
fragment STAR: {getCharPositionInLine()>0}? '*';

对于输入*** foo bar,ANTLR 生成以下解析树:

到目前为止,这按预期工作。现在我正在尝试为项目文本的可能字符添加星号,因此我将 ITEM_TEXT 的词法分析器规则更改为以下内容:

ITEM_TEXT: ('a'..'z'|'A'..'Z'|'0'..'9'|'\r'|'\n'|' '|'\t'|STAR)+;

现在对于相同的输入,生成以下解析树:

这是 ANTLRWorks 中的输出:

input.txt line 1:0 rule STAR failed predicate: {getCharPositionInLine()>0}?
input.txt line 1:1 missing OUTLINE_ITEM_MARKER at '** foo bar'

由于MissingTokenExceptionOUTLINE_ITEM_MARKER 似乎不匹配。语法有什么问题,我需要更改什么才能让星号成为ITEM_TEXT 的一部分?

【问题讨论】:

    标签: parsing exception antlr grammar lexer


    【解决方案1】:

    在您的fragments 中使用门控语义谓词1,而不是验证语义谓词

    以下语法:

    grammar Test;
    
    outline_items
     : outline_item+ EOF
     ;
    
    outline_item
     : OUTLINE_ITEM_MARKER ITEM_TEXT
     ;
    
    OUTLINE_ITEM_MARKER 
     : STAR_IN_COLUMN_ZERO STAR* (' '|'\t')
     ;
    
    ITEM_TEXT
     : ('a'..'z'|'A'..'Z'|'0'..'9'|'\r'|'\n'|' '|'\t'|STAR)+
     ;
    
    fragment STAR_IN_COLUMN_ZERO
     : {getCharPositionInLine()==0}?=> '*'
     ;
    
    fragment STAR
     : {getCharPositionInLine()>0}?=> '*'
     ;
    

    您的意见:

    * this is an outline item at level 1
    ** item at level 2
    *** item at level 3
    * another item at level 1
    * an item with *bold* text
    

    然后将被解析为:

    1What is a 'semantic predicate' in ANTLR?

    【讨论】:

      【解决方案2】:

      你试过让你的语法更简单吗?

      outline_item: OUTLINE_ITEM_MARKER ITEM_TEXT;
      
      ITEM_TEXT:
          (' '|'\t') (' '|'\t'|'a'..'z'|'A'..'Z'|'0'..'9'| STAR)+
      ;
      
      OUTLINE_ITEM_MARKER:
          STAR+ 
      ;
      
      fragment STAR:   
          '*'
      ;
      

      或者,如果您不需要将 STAR 保留为显式片段,并且想要捕获项目文本中的所有字符,而不是子集:

      outline_item: OUTLINE_ITEM_MARKER ITEM_TEXT;
      
      ITEM_TEXT:
          (' '|'\t') (~('\n'|'\r'))+
      ;
      
      OUTLINE_ITEM_MARKER:
          '*'+ 
      ;
      

      【讨论】:

      • 确实,这大大简化了语法......但是,您的语法并没有区分行首的 * 和其他地方:OP正在尝试的东西去做。
      • @BartKiers 在做出这个假设之前,请阅读提供的语法(或者最好在 ANTLRWorks 中对其进行测试)。
      • 请注意,我并没有说您的建议无效。当然,它只适用于一些规则,但我高度怀疑 OP 是否只这样做:这可以在没有成熟的递归下降解析器的帮助下完成。 OP 的问题是当放置在输入中的特定位置时,如何区分两个相同的字符(在本例中为 *)。这是您在词法分析器规则中没有解决的问题。
      • Bart Kiers 的假设是正确的,我想根据角色的位置进行区分。我试图将问题隔离到最低限度,所以我忽略了稍后我还想用相同的语法解析 'bold' 的事实。
      猜你喜欢
      • 2012-08-05
      • 2010-10-15
      • 1970-01-01
      • 2023-03-19
      • 1970-01-01
      • 2022-01-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多