2012-05-13 46 views
2

下面是解析輸入程序集文件的語法的簡化版本。我的語法中的一切都很好,直到我使用具有3個字符(即與我的語法中的OPCODE相同的長度)的標籤時,所以我假設Antlr將其作爲OPCODE而不是LABEL匹配,但我怎麼說「in這個位置,它應該是一個LABEL,而不是一個操作碼「?Antlr解析匹配固定字符串長度而不是規則

試用輸入:

從標準鑽機
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'); 

回答

2

解析器對詞法分析器生成的標記沒有影響。因此,輸入​​將始終被標記爲OPCODE,無論解析器嘗試匹配什麼。

你可以做的是建立一個滿足無論是LABELOPCODE一個label的語法規則,然後在你的operand規則使用label規則:

label 
: LABEL 
| OPCODE 
; 

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

導致以下AST爲您例如輸入:

enter image description here

這將只匹配OPCODE,但不會改變令牌的類型。如果你想要的類型,以相應的更改,有點自定義代碼添加到其更改爲輸入LABEL規則:

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

優秀再次巴特,謝謝。我確實想知道什麼時候打到與引用不同的寄存器,所以我沒有使用它的片段。在我寫這個問題的時候,我想過要創建一個像你所建議的規則,但它感覺就像是解決了解析器已經決定3個字母字符串必須始終是'OPCODE'的解決方案。我喜歡你添加到自定義代碼,我以前沒有見過,非常有用。再次感謝。 –

+0

沒問題@MarkFisher。 –