2

以下は、入力アセンブリ ファイルを解析する文法の簡略版です。3 文字のラベル (つまり、文法の OPCODE と同じ長さ) を使用するまでは、文法のすべてに問題がないため、Antlr は LABEL ではなく OPCODE として照合していると想定していますが、「inこの位置は、OPCODE ではなく LABEL である必要があります」?

試行入力:

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');
4

1 に答える 1

2

パーサーは、レクサーが生成するトークンに影響を与えません。そのため、パーサーが何を照合しようとしても、入力"abc"は常に としてトークン化されます。OPCODE

できることは、またはのいずれかに一致するパーサー ルールを作成し、ルールlabelでこのルールを使用することです。LABELOPCODElabeloperand

label
 : LABEL
 | OPCODE
 ;

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

入力例の次の AST になります。

ここに画像の説明を入力

これは のみに一致OPCODEしますが、トークンのタイプは変更しません。タイプも変更したい場合は、少しのカスタム コードをルールに追加して、それを type に変更しますLABEL

label
 : LABEL
 | t=OPCODE {$t.setType(LABEL);}
 ;
于 2012-05-13T10:28:58.613 に答える