【问题标题】:ANTLR: unexpected characterANTLR:意想不到的角色
【发布时间】:2016-06-02 12:00:18
【问题描述】:

给定以下 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 会赶上这类问题。如何修复语法,使上述错误消息不再显示?

【问题讨论】:

    标签: c antlr interpreter antlr3


    【解决方案1】:

    主要错误

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

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

    当词法分析器遇到可以匹配为UNKNOWN_KEYWORD" 并且作为STRING_KEYWORD 的开头时,它决定将输入匹配为STRING_KEYWORD,因为此规则比UNKNOWN_KEYWORD 长。

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

    其他错误

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

    • 缺少用于描述在规则中使用 AST 运算符的输出类型的 options 块。
    • statement 规则中的UNKNOWN_KEYWORD 之后缺少+。如果没有+,则表示该语句是SET_KEYWORD value_list 或任何单个 字符。
    • 缺少换行符和空格的规则。
    • statement 规则的末尾缺少EOF。像SET "abc"bla-bla-bla 这样的输入将被解析为SET_KEYWORD value_list 与AST (SET (LIST "abc"))bla-bla-bla 将被忽略而没有EOF
    • 缺少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;
    

    【讨论】:

      猜你喜欢
      • 2021-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多