Antlr错误:以下令牌定义永远不能匹配,因为先前的令牌匹配相同的输入

时间:2012-02-14 07:29:33

标签: antlr

我用antlr扭曲一个简单的语言,我在AntlrWorks中定义了一个Lexer语法,但是当我想生成java代码时,它给了我错误:

Antlr错误:以下令牌定义永远不能匹配,因为先前的令牌匹配相同的输入: FLOAT_OR_INT,OPEN_PAR,CLOSE_PAR,....(几乎适用于所有规则!)

我是antlr的新手,我认为这是因为规则位置的顺序,但我不知道他们应该怎么做,我的错误是什么?

这是语法:

lexer grammar OurCompiler;
options
{
    k=5;

} 


ID                      : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
                        ;



protected
INT                     : ('0'..'9')+
                        ;

protected
FLOAT                   : INT '.' INT
                        ;


FLOAT_OR_INT            : ( INT '.' ) => FLOAT { $setType(FLOAT); }
                        | INT { $setType(INT); }
                        ;       


OPENPAR_OR_OUTPUT_OPERATOR  :   '(' { $setType(OPEN_PAR); } | '(' '(' { $setType(OUTPUT_OPERATOR); }
                            ;

CLOSEPAR_OR_INPUT_OPERATOR  :   ')' { $setType(CLOSE_PAR); } | ')' ')' { $setType(INPUT_OPERATOR); }
                            ;

protected   
OPEN_PAR                :  '('  ;

protected
CLOSE_PAR               :  ')'  ;

protected
INPUT_OPERATOR          :   ')' ')' ;

protected
OUTPUT_OPERATOR         :   '(' '(' ;



BOOLEAN                 :   't' 'r' 'u' 'e' | 'f' 'a' 'l' 's' 'e'   ;    

LOWER                   :   '<'     ;

LOWER_EQUAL             :   LOWER '='   ;

UPPER                   :  '>'  ;

UPPER_EQUAL             :    UPPER '='  ;

ASSIGN                  : '='  ;

EQUAL                   :  '=' '='  ;

NOT                     :   '!'  ;

NOT_EQUAL               :  NOT '='  ;

ADD                     :   '+'  ;

ADD_TO_PREVIOUS         :  ADD '='  ;

INCREMENT               :   ADD ADD  ;

MINUS                   : '-'  ;

MINUS_FROM_PREVIOUS     :  MINUS '='  ;

DECREMENT               :  MINUS MINUS  ;

MULTIPLY                :  '*'  ;

MULTIPLY_TO_PREVIOUS    :  MULTIPLY '='  ;

DIVIDE                  :  '/'  ;

DIVIDE_FROM_PREVIOUS    :  DIVIDE '='  ;

MODE                    :  '%'  ;

OPEN_BRAKET             :  '['  ;

CLOSE_BRAKET            :  ']'  ;

OPEN_BRACE              :  '{'  ;

CLOSE_BRACE             :  '}'  ;

COLON                   : ':'   ;

SEMICOLON               :  ';'  ;

COMMA                   :  ','  ;


SINGLE_LINE_COMMENT     : 
                        '#' '#' ( ~ ('\n'|'\r') )*  ( '\n' | '\r' ('\n')? )? { $setType(Token.SKIP); newline(); }
                        ; 


MULTIPLE_LINE_COMMENT   :   '#' ( options {greedy=false;} : . )* '#' { $setType(Token.SKIP); }
                        ;



WS                      : 
                        ( ' '
                        | '\t'
                        | '\r'    { newline(); }
                        | '\n'    { newline(); }
                        )
                        { $setType(Token.SKIP); } 
                        ;


protected
ESC_SEQ                 :   '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
                    ;

STRING                  :  
                        '"' ( ESC_SEQ | ~('\\'|'"') )* '"'
                        ;

CHAR                    :
                        '\'' ( ESC_SEQ | ~('\''|'\\') ) '\''
                        ;





INT_KEYWORD             :   'i' 'n' 't'         ;

FLOAT_KEYWORD           :   'f' 'l' 'o' 'a' 't'     ;

CHAR_KEYWORD            :   'c' 'h' 'a' 'r'         ;

STRING_KEYWORD          :   's' 't' 'r' 'i' 'n' 'g'     ;

BOOLEAN_KEYWORD         :   'b' 'o' 'o' 'l' 'e' 'a' 'n'     ;

INPUT_KEYWORD           :   'i' 'n' ID  { $setType(ID); }
                        |   'i' 'n'     
                        ;

OUTPUT_KEYWORD          :   'o' 'u' 't' ID  { $setType(ID); }
                        |   'o' 'u' 't'     ;

IF_KEYWORD              :   'i' 'f'             ;

FOR_KEYWORD             :   'f' 'o' 'r'         ;

SWITCH_KEYWORD          :   's' 'w' 'i' 't' 'c' 'h'     ;

CASE_KEYWORD            :   'c' 'a' 's' 'e'         ;

BREAK_KEYWORD           :   'b' 'r' 'e' 'a' 'k'     ;

DEFAULT_KEYWORD         :   'd' 'e' 'f' 'a' 'u' 'l' 't' ;

WHILE_KEYWORD           :   'w' 'h' 'i' 'l' 'e'     ;

ELSE_KEYWORD            :   'e' 'l' 's' 'e'         ;

ELSEIF_KEYWORD          :   'e' 'l' 's' 'e' 'i' 'f'     ;

AND_KEYWORD             :   'a' 'n' 'd'         ;

OR_KEYWORD              :   'o' 'r'             ;

NOT_KEYWORD             :   'n' 'o' 't'         ;

CONSTANT_KEYWORD        :   'c' 'o' 'n' 's' 't' 'a' 'n' 't' ;

1 个答案:

答案 0 :(得分:15)

在看了一下你的语法后,我有7条评论:

1

k=?表示解析器规则的预测,因为你的是词法分析器语法,所以删除它;

2

虽然没有错,但BOOLEAN_KEYWORD : 'b' 'o' 'o' 'l' 'e' 'a' 'n';相当冗长。请改为BOOLEAN_KEYWORD : 'boolean';

3

关键字protected已在ANTLR 3中更改为fragment。但是你做的很奇怪。遵循以下规则:

fragment
INT 
 : ('0'..'9')+
 ;

fragment
FLOAT 
 : INT '.' INT
 ;

FLOAT_OR_INT 
 : ( INT '.' ) => FLOAT { $setType(FLOAT); }
 | INT { $setType(INT); }
 ;

您创建了两个片段,然后FLOAT_OR_INT检查谓词是否“看到”INT后跟'.',然后将其更改为FLOAT 。以下内容相同,更具可读性/更好/首选:

FLOAT 
 : DIGIT+ '.' DIGIT+
 ;

INT 
 : DIGIT+
 ;

fragment DIGIT 
 : '0'..'9'
 ;

4

默认情况下

.*是不合适的,所以更改:

'#' ( options {greedy=false;} : . )* '#'

进入

'#' .* '#'

甚至更好:

'#' ~'#'+ '#'

5

规则:

OPENPAR_OR_OUTPUT_OPERATOR
 : '('     { $setType(OPEN_PAR); } 
 | '(' '(' { $setType(OUTPUT_OPERATOR); }
 ;

应该只是:

OUTPUT_OPERATOR
 : '(('
 ;

OPEN_PAR
 : '('
 ;

6

ANTLR的词法分析器尝试匹配尽可能多的字符。每当两个规则匹配相同数量的字符时,定义为firs的规则将“获胜”。这就是为什么您应该在 *_KEYWORD规则之前定义所有ID规则

7

最后,您无需检查"in""out"后面是ID(然后更改令牌的类型)。每当词法分析器“看到”"inside"之类的输入时,它总会创建一个ID令牌,而一个INPUT_KEYWORD后跟ID ,因为词法分析器尽可能匹配(见注释#6)。


您似乎试图通过反复试验来学习ANTLR,或者正在使用过时的文档。这是学习ANTLR的方法。试着抓住Parr的The Definitive ANTLR Reference来正确学习它。

祝你好运!

修改

好吧,如果你没有设法让它工作,这是你的语法的工作版本:

lexer grammar OurCompiler; // A bit of an odd name for a lexer...

K_INT      : 'int';
K_FLOAT    : 'float';
K_CHAR     : 'char';
K_STRING   : 'string';
K_BOOLEAN  : 'boolean';
K_INPUT    : 'in';
K_OUTPUT   : 'out';
K_IF       : 'if';
K_FOR      : 'for';
K_SWITCH   : 'switch';
K_CASE     : 'case';
K_BREAK    : 'break';
K_DEFAULT  : 'default';
K_WHILE    : 'while';
K_ELSE     : 'else';
K_ELSEIF   : 'elseif';
K_AND      : 'and';
K_OR       : 'or';
K_NOT      : 'not';
K_CONSTANT : 'constant';

BOOLEAN : 'true' | 'false';
FLOAT   : DIGIT+ '.' DIGIT+; 
INT     : DIGIT+;
STRING  : '"'  ( ESC_SEQ | ~('\\'|'"') )* '"';
CHAR    : '\'' ( ESC_SEQ | ~('\''|'\\') ) '\'';

ID : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*;

INPUT_OPERATOR  : '))';
OUTPUT_OPERATOR : '((';
OPEN_PAR        : '(';
CLOSE_PAR       : ')';

LOWER                : '<';
LOWER_EQUAL          : '<=';
UPPER                : '>';
UPPER_EQUAL          : '>=';
ASSIGN               : '=';
EQUAL                : '==';
NOT                  : '!';
NOT_EQUAL            : '!=';
ADD                  : '+';
ADD_TO_PREVIOUS      : '+=';
INCREMENT            : '++';
MINUS                : '-';
MINUS_FROM_PREVIOUS  : '-=';
DECREMENT            : '--';
MULTIPLY             : '*';
MULTIPLY_TO_PREVIOUS : '*=';
DIVIDE               : '/';
DIVIDE_FROM_PREVIOUS : '/=';
MODE                 : '%';
OPEN_BRAKET          : '[';
CLOSE_BRAKET         : ']';
OPEN_BRACE           : '{';
CLOSE_BRACE          : '}';
COLON                : ':';
SEMICOLON            : ';';
COMMA                : ',';

SINGLE_LINE_COMMENT   : '##' ~('\r' | '\n')*        {skip();}; 
MULTIPLE_LINE_COMMENT : '#' ~'#'+ '#'               {skip();};
WS                    : ( ' ' | '\t' | '\r' | '\n') {skip();};

fragment ESC_SEQ : '\\' ('b' | 't' | 'n' | 'f' | 'r' | '\"' | '\'' | '\\');
fragment DIGIT   : '0'..'9';