使用intellij vs命令行的简单antlr语法的不同结果

时间:2019-04-13 03:42:22

标签: antlr4

我有一个简单的语法,它在ItelliJ antlr4插件中似乎可以正常工作,但是当在命令行中通过antlr运行时,会产生一些异常错误

我曾尝试寻找类似的问题并重新排列词法分析器,但没有成功。

词法分析器如下

lexer grammar kscriptLexer;

TEXT_COMMENT
    :   '//' ~[\r\n]*?
    ;

TAG_COMMENT
    :   '<%//' .*? '%>'
    ;

TAG_OPEN
    :   '<%' //->pushMode(SCRIPT)
    ;

//TEXT
//  :   ~'<'+ ->skip
//  ;



//mode SCRIPT;

TAG_CLOSE
    :   '%>' //->popMode
    ;

IF  :   I F;
ENDIF   :   E N D I F;
ELSE    :   E L S E;
LOOP    :   L O O P;
ENDLOOP :   E N D L O O P;

INT
    :   [0-9]+
    ;

FLOAT
    :   [0-9]+ DOT [0-9]+
    ;

STRING
    :   '"' ~'"'* '"'
    ;

NE  :   '<>';
LE  :   '<=';
GE  :   '>=';
LT  :   '<';
GT  :   '>';
EQ  :   '=';
ASSIGN  :   ':=';
AMPERSAND:  '&';

MUL :   '*';
DIV :   '/';
ADD :   '+';
SUB :   '-';

LBKT    :   '(';
RBKT    :   ')';

COMMA   :   ',';
DOT :   '.';

fragment A: 'a' | 'A';
fragment B: 'b' | 'B';
fragment C: 'c' | 'C';
fragment D: 'd' | 'D';
fragment E: 'e' | 'E';
fragment F: 'f' | 'F';
fragment G: 'g' | 'G';
fragment H: 'h' | 'H';
fragment I: 'i' | 'I';
fragment J: 'j' | 'J';
fragment K: 'j' | 'K';
fragment L: 'l' | 'L';
fragment M: 'm' | 'M';
fragment N: 'n' | 'N';
fragment O: 'o' | 'O';
fragment P: 'p' | 'P';
fragment Q: 'q' | 'Q';
fragment R: 'r' | 'R';
fragment S: 's' | 'S';
fragment T: 't' | 'T';
fragment U: 'u' | 'U';
fragment V: 'v' | 'V';
fragment W: 'w' | 'W';
fragment X: 'x' | 'X';
fragment Y: 'y' | 'Y';
fragment Z: 'z' | 'Z';

ID
    :   [a-zA-Z_] [a-zA-Z_0-9]*
    ;

WS
    :   [ \t\r\n]+ -> channel(HIDDEN)
    ;

语法是


tokens {TAG_COMMENT,TEXT_COMMENT,TAG_OPEN,TAG_CLOSE,IF,ENDIF,ELSE,LOOP,ENDLOOP,TEXT,ID,DOT,ASSIGN,LBKT,RBKT,INT,FLOAT,STRING,MUL,DIV,ADD,AMPERSAND,
        SUB,EQ,NE,LT,GT,GE,LE,COMMA}

start
    :   part+
    ;

part
//  :   TAG_COMMENT                                 # TagComment
    :   TEXT_COMMENT                                    # TextComment
    |   TAG_OPEN part1 TAG_CLOSE                            # PartA
    |   TEXT                                        # TextStmt
    ;

part1
        :   IF expr TAG_CLOSE part* TAG_OPEN ELSE TAG_CLOSE part* TAG_OPEN ENDIF        # IfElseStmt
        |   LOOP expr TAG_CLOSE part* TAG_OPEN ENDLOOP                  # LoopStmt
        |   stmt                                        # ScriptOpen
    ;

stmt
    :   ID (DOT ID)* ASSIGN expr                            # Assign
    |   ID (DOT ID)* LBKT params RBKT                           # Proc
    |   expr                                        # Expression
    ;

params
    :   expr (COMMA expr)*
    ;

expr
    :   expr MUL expr               # Mul
    |   expr DIV expr               # Div
    |   expr ADD expr               # Add
    |   expr AMPERSAND expr         # Ampersand
    |   expr SUB expr               # Sub
    |   expr EQ expr                # Eq
    |   expr NE expr                # Ne
    |   expr LT expr                # Lt
    |   expr GT expr                # Gt
    |   expr GE expr                # Ge
    |   expr LE expr                # Le
    |   ID (DOT ID)*                # Id
    |   ID (DOT ID)* LBKT params RBKT       # Func
    |   INT                 # Int
    |   FLOAT                   # Float
    |   STRING                  # String
    |   LBKT expr RBKT              # Expr1
    ;

我的示例输入是

<%if GlobalValue("operationtype") = "Add"%>
<%else%>
<%endif%>

enter image description here

我从intellij获得了我期望的解析树,但是我从命令行获得了以下内容

C:\Antlr\complex>set GRAMMAR=kscript
C:\Antlr\complex>set JAVAROOT=C:\Program Files\Java\jdk-11.0.1\bin
C:\Antlr\complex>"C:\Program Files\Java\jdk-11.0.1\bin\java.exe" -jar c:\batch\antlr-4.7.2-complete.jar -o tmp -lib tmp kscriptLexer.g4
C:\Antlr\complex>"C:\Program Files\Java\jdk-11.0.1\bin\java.exe" -jar c:\batch\antlr-4.7.2-complete.jar -o tmp -lib tmp kscriptParser.g4
C:\Antlr\complex>"C:\Program Files\Java\jdk-11.0.1\bin\javac" -cp .\;c:\batch\antlr-4.7.2-complete.jar tmp\kscript*.java
C:\Antlr\complex>cd tmp
C:\Antlr\complex\tmp>"C:\Program Files\Java\jdk-11.0.1\bin\java.exe" -cp .\;c:\batch\antlr-4.7.2-complete.jar org.antlr.v4.gui.TestRig kscript start 

c:\x\sample.kscript -tree
line 1:5 mismatched input 'GlobalValue' expecting {ID, LBKT, INT, FLOAT, STRING}
(start (part <% (part1 if (expr GlobalValue ( "operationtype" ) = "Add") %> <% else %> <% endif) %>))

但是,当我使用-tokens选项时,会得到以下信息流

[@0,0:1='<%',<'<%'>,1:0]
[@1,2:3='if',<IF>,1:2]
[@2,4:4=' ',<WS>,channel=1,1:4]
[@3,5:15='GlobalValue',<ID>,1:5]
[@4,16:16='(',<'('>,1:16]
[@5,17:31='"operationtype"',<STRING>,1:17]
[@6,32:32=')',<')'>,1:32]
[@7,33:33=' ',<WS>,channel=1,1:33]
[@8,34:34='=',<'='>,1:34]

其中“ GlobalValue”看起来可以识别为ID,但不符合IF语法规则。

1 个答案:

答案 0 :(得分:1)

如果查看您的tmp目录,您将看到两个.tokens文件:一个用于词法分析器,一个用于解析器。如果查看它们的内部,将会看到它们为令牌分配了不同的数字。与当前问题最相关的是,词法分析器文件包含ID=29,而解析器文件包含ID=11LE=29

因此,当词法分析器看到一个标识符时,它会正确地识别出该标识符并生成令牌类型为29的令牌。然后,解析器将看到该令牌并将其识别为LE令牌,因为解析器认为这就是令牌类型29表示。

为避免此类问题,词法分析器和解析器应使用相同的标记定义,而不是独立的标记定义。您可以通过从解析器中删除tokens {...}块,而改为使用tokenVocab选项来实现此目的:

options {
    tokenVocab=kscriptLexer;
}
相关问题