ANTLR4 g4语法用于读取不同块中的键/值对

时间:2018-02-09 15:33:26

标签: antlr4

我是antlr的新手,我正在努力制作简单的语法,但我不能成功。 我想解析这种文件:

BEGIN HEADER
    CharacterSet "CP1252"
END HEADER
BEGIN DSJOB
    test "val"
END DSJOB
BEGIN DSJOB
    test "val2"
END DS

JOB

我正在使用这种语法:

grammar Hello;
dsxFile             :   headerDeclaration? jobDeclaration* EOF;
headerDeclaration   :   'BEGIN HEADER' param* 'END HEADER';
jobDeclaration      :   'BEGIN DSJOB' subJobDeclaration* param* 'END DSJOB';
subJobDeclaration       :   'BEGIN DSSUBJOB' param* 'END DSSUBJOB';

headParam
    :   (   'CharacterSet'     
        |   'name'  
        ) StringLiteral
    ;

// ANNOTATIONS
param   :   PNAME PVALUE;

PNAME :StringCharacters;
PVALUE :StringCharacters;
// STATEMENTS / BLOCKS
//block
//    :   '{' blockStatement* '}';

// LEXER

// Keywords

ABSTRACT      : 'abstract';
ASSERT        : 'assert';
BOOLEAN       : 'boolean';
BREAK         : 'break';
BYTE          : 'byte';
CASE          : 'case';
CATCH         : 'catch';
CHAR          : 'char';
CLASS         : 'class';
CONST         : 'const';
CONTINUE      : 'continue';
DEFAULT       : 'default';
DO            : 'do';
DOUBLE        : 'double';
ELSE          : 'else';
ENUM          : 'enum';
EXTENDS       : 'extends';
FINAL         : 'final';
FINALLY       : 'finally';
FLOAT         : 'float';
FOR           : 'for';
IF            : 'if';
GOTO          : 'goto';
IMPLEMENTS    : 'implements';
IMPORT        : 'import';
INSTANCEOF    : 'instanceof';
INT           : 'int';
INTERFACE     : 'interface';
LONG          : 'long';
NATIVE        : 'native';
NEW           : 'new';
PACKAGE       : 'package';
PRIVATE       : 'private';
PROTECTED     : 'protected';
PUBLIC        : 'public';
RETURN        : 'return';
SHORT         : 'short';
STATIC        : 'static';
STRICTFP      : 'strictfp';
SUPER         : 'super';
SWITCH        : 'switch';
SYNCHRONIZED  : 'synchronized';
THIS          : 'this';
THROW         : 'throw';
THROWS        : 'throws';
TRANSIENT     : 'transient';
TRY           : 'try';
VOID          : 'void';
VOLATILE      : 'volatile';
WHILE         : 'while';

//  Boolean Literals

BooleanLiteral  :   'true' |   'false';

//  Character Literals


fragment
SingleCharacter
    :   ~['\\] ;
//  String Literals
StringLiteral
    :   '"' StringCharacters? '"'
    ;
fragment
StringCharacters
    :   StringCharacter+
    ;
fragment
StringCharacter
    :   ~["\\]
    ;


// Separators

LPAREN          : '(';
RPAREN          : ')';
LBRACE          : '{';
RBRACE          : '}';
LBRACK          : '[';
RBRACK          : ']';
SEMI            : ';';
COMMA           : ',';
DOT             : '.';

// Operators

ASSIGN          : '=';
GT              : '>';
LT              : '<';
BANG            : '!';
TILDE           : '~';
QUESTION        : '?';
COLON           : ':';
EQUAL           : '==';
LE              : '<=';
GE              : '>=';
NOTEQUAL        : '!=';
AND             : '&&';
OR              : '||';
INC             : '++';
DEC             : '--';
ADD             : '+';
SUB             : '-';
MUL             : '*';
DIV             : '/';
BITAND          : '&';
BITOR           : '|';
CARET           : '^';
MOD             : '%';

ADD_ASSIGN      : '+=';
SUB_ASSIGN      : '-=';
MUL_ASSIGN      : '*=';
DIV_ASSIGN      : '/=';
AND_ASSIGN      : '&=';
OR_ASSIGN       : '|=';
XOR_ASSIGN      : '^=';
MOD_ASSIGN      : '%=';
LSHIFT_ASSIGN   : '<<=';
RSHIFT_ASSIGN   : '>>=';
URSHIFT_ASSIGN  : '>>>=';


//
// Additional symbols not defined in the lexical specification
//

AT : '@';
ELLIPSIS : '...';

//
// Whitespace and comments
//

WS  :  [ \t\r\n\u000C]+ -> skip
    ;

COMMENT
    :   '/*' .*? '*/' -> skip
    ;

LINE_COMMENT
    :   '//' ~[\r\n]* -> skip
;

但我仍然遇到这个问题:

  

第1行:0输出不匹配'BEGIN HEADER \ r \ n \ tCharacterSet'期待   {,'BEGIN HEADER','开始DSJOB'}(dsxFile BEGIN   HEADER \ r \ n \ tCharacterSet“CP1252”\ r \ nEND HEADER \ r \ nBEGIN   DSJOB \ r \ n \ ttest“val”\ r \ nEND DSJOB)

有人能解释一下这是什么意思吗?它似乎无法跳过\ r \ t。

感谢您的帮助!

1 个答案:

答案 0 :(得分:2)

问题是您的输入未按预期标记。这是因为词法分析器尽可能多地匹配输入。因此,如果您查看PNAME规则:

PNAME : StringCharacters;

fragment StringCharacter
 : ~["\\]
 ;

然后您会注意到输入"BEGIN HEADER\n CharacterSet "与该规则匹配。

这是错误信息:

  

不匹配的输入&#39; BEGIN HEADER \ r \ n \ tCharacterSet&#39;期待{,&#39; BEGIN HEADER&#39;,&#39; BEGIN DSJOB&#39;}

告诉我:找到了令牌'BEGIN HEADER\r\n\tCharacterSet ',而解析器需要其中一个令牌'BEGIN HEADER''BEGIN DSJOB'

您可能需要在该类中添加空格,制表符和换行符:~["\\ \t\r\n](但由您自行决定)

此外,词法分析器独立于解析器运行(解析器对生成的令牌没有影响)。词法分析器只是尝试匹配尽可能多的字符,并且只要有两个(或更多)规则匹配相同的字符,首先定义的规则&#34;胜出&#34;。根据这个逻辑,然后从以下规则:

PNAME : StringCharacters;
PVALUE : StringCharacters;

很明显规则PVALUE永远不会匹配(只有PNAME,因为首先定义了grammar Hello; dsxFile : headerDeclaration? jobDeclaration* EOF; headerDeclaration : BEGIN HEADER param* END HEADER; jobDeclaration : BEGIN DSJOB subJobDeclaration* param* END DSJOB; subJobDeclaration : BEGIN DSSUBJOB param* END DSSUBJOB; param : PNAME pvalue; pvalue : STRING /* other alternaives here? */; STRING : '"' ~["\r\n]* '"'; BEGIN : 'BEGIN'; END : 'END'; HEADER : 'HEADER'; DSJOB : 'DSJOB'; DSSUBJOB : 'DSSUBJOB'; WS : [ \t\r\n\u000C]+ -> skip; COMMENT : '/*' .*? '*/' -> skip; LINE_COMMENT : '//' ~[\r\n]* -> skip; // Be sure to put this rule _after_ the rules BEGIN, END, HEADER, ... // otherwise this rule will match those keywords instead PNAME : ~["\\ \t\r\n]+;

以下是解析示例输入的方法:

{{1}}

enter image description here

当然,您需要更改它以完全满足您的需求,但这只是一个开始。