【问题标题】:Antlr parsing matching fixed string length instead of ruleAntlr解析匹配固定字符串长度而不是规则
【发布时间】:2012-05-13 19:38:13
【问题描述】:

以下是解析输入汇编文件的语法的精简版本。我的语法中的一切都很好,直到我使用具有 3 个字符的标签(即与我的语法中的 OPCODE 长度相同),所以我假设 Antlr 将其匹配为 OPCODE 而不是 LABEL,但我怎么说“在这个位置,应该是LABEL,而不是OPCODE”?

试输入:

set a, label1
set b, abc

标准装备的输出给出:

line 2:5 missing EOF at ','
(OP_BAS set a (REF label1)) (OP_SPE set b)

当我通过 ANTLRWorks 进行单步调试时,我看到它从指令规则 2 开始,但在对“abc”的引用处跳转到规则 3,然后在“,”处失败。

我可以通过大量的左分解来解决这个问题,但它会使语法变得难以理解。我试图在可读性和功能之间找到一个折衷方案(没有太多输入,全局回溯会影响性能)。

grammar TestLabel;

options {
    language = Java;
    output = AST;
    ASTLabelType = CommonTree;
    backtrack = true;
}

tokens {
    NEGATION;
    OP_BAS;
    OP_SPE;
    OP_CMD;
    REF;
    DEF;
}

program
    : instruction* EOF!
    ;

instruction
    : LABELDEF                  -> ^(DEF LABELDEF)
    | OPCODE dst_op ',' src_op  -> ^(OP_BAS OPCODE dst_op src_op)
    | OPCODE src_op             -> ^(OP_SPE OPCODE src_op)
    | OPCODE                    -> ^(OP_CMD OPCODE)
    ;

operand
    : REG
    | LABEL                     -> ^(REF LABEL)
    | expr
    ;

dst_op
    : PUSH
    | operand
    ;

src_op
    : POP
    | operand
    ;

term
    : '('! expr ')'!
    | literal
    ;

unary
    : ('+'! | negation^ )* term
    ;

negation
    : '-' -> NEGATION
    ;

mult
    : unary ( ( '*'^ | '/'^ ) unary )*
    ;

expr
    :  mult ( ( '+'^ | '-'^ ) mult )*
    ;

literal
    :   number
    |   CHAR
    ;

number
    :   HEX
    |   BIN
    |   DECIMAL
    ;

REG: ('A'..'C'|'I'..'J'|'X'..'Z'|'a'..'c'|'i'..'j'|'x'..'z') ;
OPCODE: LETTER LETTER LETTER;

HEX: '0x' ( 'a'..'f' | 'A'..'F' | DIGIT )+ ;
BIN: '0b' ('0'|'1')+;
DECIMAL: DIGIT+ ;

LABEL: ( '.' | LETTER | DIGIT | '_' )+ ;
LABELDEF: ':' ( '.' | LETTER | DIGIT | '_' )+ {setText(getText().substring(1));} ;

STRING: '\"' .* '\"' {setText(getText().substring(1, getText().length()-1));} ;
CHAR: '\'' . '\'' {setText(getText().substring(1, 2));} ;
WS: (' ' | '\n' | '\r' | '\t' | '\f')+ { $channel = HIDDEN; } ;

fragment LETTER: ('a'..'z'|'A'..'Z') ;
fragment DIGIT: '0'..'9' ;
fragment PUSH: ('P'|'p')('U'|'u')('S'|'s')('H'|'h');
fragment POP: ('P'|'p')('O'|'o')('P'|'p');

【问题讨论】:

    标签: parsing antlr


    【解决方案1】:

    解析器对词法分析器产生的标记没有影响。因此,无论解析器尝试匹配什么,输入 "abc" 将始终被标记为 OPCODE

    您可以做的是创建一个匹配 LABELOPCODElabel 解析器规则,然后在您的 operand 规则中使用此 label 规则:

    label
     : LABEL
     | OPCODE
     ;
    
    operand
     : REG
     | label -> ^(REF label)
     | expr
     ;
    

    为您的示例输入生成以下 AST:

    这只会匹配OPCODE,但不会改变令牌的类型。如果您也想更改类型,请在规则中添加一些自定义代码,将其更改为类型LABEL

    label
     : LABEL
     | t=OPCODE {$t.setType(LABEL);}
     ;
    

    【讨论】:

    • 再次出色,巴特,谢谢。我确实想知道我何时点击了与参考不同的寄存器,所以我没有在上面使用片段。在我写这个问题的时候,我考虑过像你建议的那样创建一个规则,但感觉这是一个解决方法,可以解决解析器已经决定 3 个字母字符串必须始终为OPCODE 的事实。我喜欢您对自定义代码的添加,我以前从未见过,非常有用。再次感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-22
    • 2011-04-07
    • 1970-01-01
    • 2018-11-24
    • 1970-01-01
    • 2012-04-25
    • 1970-01-01
    相关资源
    最近更新 更多