代码之家  ›  专栏  ›  技术社区  ›  Damien F

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

  •  1
  • Damien F  · 技术社区  · 8 年前

    我是antlr的新手,我正在尝试简单的语法,但我没有成功。 我想分析此类文件:

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

    工作

    我使用这种语法:

    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”,“BEGIN DSJOB”}(dsxFile BEGIN 标题\r\n\t字符集“CP1252”\r\n标题\r\n登录 DSJOB\r\n\t设置“val”\r\n和DSJOB)

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

    谢谢你们的帮助!

    1 回复  |  直到 8 年前
        1
  •  3
  •   Bart Kiers    8 年前

    问题是您的输入没有按照您的预期进行标记化。这是因为lexer匹配尽可能多的输入。所以如果你看看 PNAME 规则:

    PNAME : StringCharacters;
    
    fragment StringCharacter
     : ~["\\]
     ;
    

    然后您会注意到输入 "BEGIN HEADER\n CharacterSet " 符合该规则。

    错误消息如下:

    输入不匹配的“BEGIN HEADER\r\n\tCharacterSet”应为{,“BEGIN HEADER”,“BEGIN DSJOB”}

    正在讲述:令牌 'BEGIN HEADER\r\n\tCharacterSet ' ,而解析器需要一个标记 'BEGIN HEADER' 'BEGIN DSJOB' .

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

    此外,lexer独立于解析器进行操作(解析器对生成的标记没有影响)。lexer只是尝试匹配尽可能多的字符,每当有两个(或更多)规则匹配相同的字符时,第一个定义的规则“获胜”。根据此逻辑,然后根据以下规则:

    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]+;
    

    enter image description here

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