1

我是 ANTLR 的新手,我正在尝试使用它。这是我能想到的最简单的语法,但当我解析变量“id123”时它仍然不起作用(NoViableAltException),但它适用于“abc1”、“ab”、“c1d2f3”。

我正在使用 ANTLR 3.1.3 和 ANTLRWorks 1.4。

options 
{
    language = 'CSharp2';
    output = AST;
}

assign  :   variable '=' value;
value   :   (variable|constant);
variable:   LETTER (LETTER|DIGIT)*;
constant:   (STRING|INTEGER);

DIGIT   :   '0'..'9';
NATURAL :   (DIGIT)+;   
INTEGER :   ('-')? NATURAL; 
REAL    :   (INTEGER '.' NATURAL);

LETTER  :   ('a'..'z'|'A'..'Z');

CR      :   '\r'        { $channel = HIDDEN; }; 
LF      :   '\n'        { $channel = HIDDEN; }; 
CRLF    :   CR LF       { $channel = HIDDEN; }; 
SPACE   :   (' '|'\t')  { $channel = HIDDEN; };

STRING  :   '"' (~'"')* '"';
4

1 回答 1

2

ANTLR 的词法分析器尝试尽可能多地匹配。每当两个(或更多)规则匹配相同数量的字符时,首先定义的规则将“获胜”。因此,每当词法分析器偶然发现一个数字时,DIGIT就会创建一个标记,因为它是在之前定义的NATURAL

DIGIT   :   '0'..'9';
NATURAL :   (DIGIT)+;   

但是对于输入"id123",词法分析器产生了以下 3 个标记:

LETTER          'i'
LETTER          'd'
NATURAL         '123'

因为词法分析器贪婪地匹配,因此NATURAL创建了一个,而不是三个DIGIT标记。

您应该做的是制定一个词法分析器规则variable

assign   :   VARIABLE '=' value;
value    :   (VARIABLE | constant);
constant :   (STRING | INTEGER | REAL);

VARIABLE :   LETTER (LETTER|DIGIT)*;
INTEGER  :   ('-')? NATURAL; 
REAL     :   (INTEGER '.' NATURAL);
SPACE    :   (' ' | '\t' | '\r' | '\n')  { $channel = HIDDEN; };
STRING   :   '"' (~'"')* '"';

fragment NATURAL :   (DIGIT)+;   
fragment DIGIT   :   '0'..'9';
fragment LETTER  :   ('a'..'z' | 'A'..'Z');

另请注意,我制作了几个词法分析器规则fragment。这意味着词法分析器永远不会产生NATURAL,DIGITLETTER标记。这些fragment规则只能由其他词法分析器规则使用。换句话说,您的词法分析器只会产生VARIABLEINTEGERREALSTRING标记*(所以这些是您唯一可以在解析器规则中使用的!)。

* 和'='令牌,当然...

于 2012-05-24T07:05:16.337 回答