2012-05-13 2 views
2

아래는 입력 어셈블리 파일을 구문 분석하는 문법의 축소 버전입니다. 내 문법의 모든 것은 내가 3 개의 문자 (예 : 문법에서 OPCODE와 같은 길이)를 사용하기 전까지는 괜찮습니다. 그래서 Antlr이 LPCEL이 아닌 OPCODE로 일치한다고 가정합니다. 그러나 어떻게해야합니까? 이 위치는 레이블이어야하며 OPCODE가 아니어야합니까? "규칙 대신 일치하는 고정 문자열 길이를 해석하는 Antlr

시험 입력 :

표준 장비에서
set a, label1 
set b, abc 

출력이 제공 : 나는 ANTLRWorks을 통해 디버깅 단계 때

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

, 나는 그것을 명령 규칙 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

파서는 렉서가 생성하는 토큰 무엇에 영향을주지 않습니다. 따라서 입력 된 "abc"은 구문 분석기의 일치 여부와 관계없이 항상 OPCODE으로 토큰 화됩니다.

label 
: LABEL 
| OPCODE 
; 

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

귀하의 예제 입력을위한 다음 AST 결과 :

은 당신이 할 수있는 것은 중 하나 LABEL 또는 OPCODE 일치하는 label 파서 규칙을 생성 한 다음 operand 규칙이 label 규칙을 사용하는 것입니다

enter image description here

에만 OPCODE 일치하지만, 토큰의 유형을 변경하지 않습니다. 유형을 변경하려면 유형을 변경하는 규칙에 약간의 맞춤 코드를 추가하여 LABEL을 입력하십시오.

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

우수 다시 감사합니다. 나는 실제로 레퍼런스와 다른 레지스터를 때리는 것을 알고 싶다. 그래서 나는 그것에 대한 단편을 사용하지 않았다. 필자가 제안한 것처럼 규칙을 작성하는 방법에 대해 생각했지만 파서가 이미 3 개의 문자열을 항상 'OPCODE'로 결정한다는 사실을 해결할 수있는 방법이라고 생각합니다. 나는 커스텀 코드에 당신이 추가 한 것을 좋아한다. 전에는 그렇게 보지 못했다. 그래서 매우 유용하다. 다시 한번 감사드립니다. –

+0

문제는 없습니다. @MarkFisher. –