ANTLR生成的解析器产生MissingTokenException

时间:2012-02-11 17:43:28

标签: parsing exception antlr grammar lexer

我正在使用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生成以下分析树:

without_star_in_item_text

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

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

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

with_star_in_item_text

这是ANTLRWorks中的输出:

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

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

2 个答案:

答案 0 :(得分:2)

fragment中使用门控语义谓词 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
然后

将被解析为:

enter image description here

1 What is a 'semantic predicate' in ANTLR?

答案 1 :(得分:0)

您是否尝试过简化语法?

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:
    '*'+ 
;