ANTLR:意外的角色

时间:2016-06-02 12:00:18

标签: c antlr interpreter antlr3

鉴于以下ANTLR语法:

tokens
{
   SET;
   UNKNOWN;
   LIST;
}


statement : SET_KEYWORD list = value_list -> ^(SET $list)
          | UNKNOWN_KEYWORD -> ^(UNKNOWN);

value_list : element += value (COMMA_KEYWORD element += value)* -> ^(LIST $element+);

value : STRING_KEYWORD;


SET_KEYWORD : 'SET';

UNKNOWN_KEYWORD : .;

fragment STRING_KEYWORD : '"' ('a'..'z' | 'A'..'Z')* '"';

当解析以下文本时(即不关闭双引号):

SET "example

ANTLR会出现以下错误:

TEST(1) : lexer error 1 :
        Unexpected character at offset 12, (end of input).
         This indicates a poorly specified lexer RULE
         or unterminated input element such as: "STRING["]
         The lexer was matching from line 1, offset 3, which
         looks like this:
                "example

有人会认为UNKNOWN_KEYWORD会赶上这类问题。如何修复语法,以便不再显示上述错误消息?

1 个答案:

答案 0 :(得分:0)

主要错误

你的语法的主要错误是将UNKNOWN_KEYWORDSTRING_KEYWORD描述为词法规则。您的解析器与SET "example输入不匹配,因为词法分析器具有following

  

Lexer寻找第一个最长的匹配规则。换句话说,如果多个规则与输入匹配,则选择最长的规则。

当词法分析器符合可以匹配为"UNKNOWN_KEYWORD开头的STRING_KEYWORD时,它会决定将输入与STRING_KEYWORD匹配,因为此规则比UNKNOWN_KEYWORD

因此,将这些规则重写为解析器规则会更好。让词法分析器匹配更简单的标记。

其他错误

除此之外,你的语法中还有其他错误:

  • 缺少options块以描述在规则中使用AST运算符的输出类型。
  • +规则UNKNOWN_KEYWORD之后遗失statement。如果没有+,则说该语句是SET_KEYWORD value_list或任何单个字符。
  • 缺少换行和空白的规则。
  • EOF规则末尾缺少statement。像SET "abc"bla-bla-bla这样的输入将被解析为SET_KEYWORD value_list,其中(SET (LIST "abc"))bla-bla-blaEOF将被忽略{。}}。
  • 缺少COMMA_KEYWORD规则的说明。
  • STRING_KEYWORD描述为片段规则。如果规则是片段,则解析器永远不会获得此规则描述的令牌。

AST问题

如果您将UNKNOWN_KEYWORDSTRING_KEYWORD重写为解析器规则并尝试使用SET "example"输入的解析器,则会获得以下AST:

(SET (LIST " e x a m p l e "))

即。 "example"不是AST的整个节点。每个字符都有单独的节点,因为AST中的一个节点在一般情况下构造一个令牌。但是可以通过调用CommonTree类的构造函数创建虚构标记并创建节点来解决它(参见ANTLR 3 Runtime 3.5.2 API):

 value :  st = string_keyword -> {new CommonTree(new CommonToken(KEYWORD, $st.text))};

产生的语法

所以,你的语法可能如下所示:

options {
  output=AST;
  ASTLabelType=CommonTree;
}

tokens {
   SET;
   UNKNOWN;
   LIST;
   KEYWORD;
}

statement : ((SET_KEYWORD value_list)=> SET_KEYWORD list= value_list NEWLINE -> ^(SET $list)
            | unknown_keyword+ NEWLINE -> ^(UNKNOWN)
            )
            EOF;

value_list : element += value (COMMA_KEYWORD element += value)* -> ^(LIST $element+);

value :  st= string_keyword -> {new CommonTree(new CommonToken(KEYWORD,$st.text))};

NEWLINE:'\r'? '\n' ;
WS: (' '|'\t'|'\n'|'\r')+ {skip();};
COMMA_KEYWORD: ',';
SET_KEYWORD : 'SET';
QUOTES:'"';
LETTER:('a'..'z' | 'A'..'Z');
ANY:.;
string_keyword : QUOTES LETTER* QUOTES ;
unknown_keyword : SET_KEYWORD|QUOTES|LETTER|COMMA_KEYWORD|ANY;