首页 文章

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

提问于
浏览
4

我用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 回答

  • 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 检查谓词是否"sees" 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的规则将为"win" . 这就是为什么你应该在 ID 规则之前定义所有 *_KEYWORD 规则的原因 .

    7

    最后,您不需要检查 "in""out" 后面是 ID (然后更改令牌的类型) . 每当词法分子"sees"输入像 "inside" 时,它总是会创建一个 ID 标记,而不是 INPUT_KEYWORD 后跟 ID ,因为词法分析器尽可能匹配(参见注释#6) .


    您似乎试图通过反复试验来学习ANTLR,或者正在使用过时的文档 . 这不是学习ANTLR的方法 . 尝试 grab 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';
    

相关问题