ANTLR4

2016-11-21 2 views
0

에서 문법 모호성을 처리 내가 (예를 들어) 다음 코드를 분석한다 문법이 있습니다ANTLR4

vmthread programm_start 
{ 
    CALL main 
} 

subcall main 
{ 
    // Declarations 
    DATAF i 

    CALL i 

    // Statements 
    MOVEF_F 3 i 
} 

문제는 CALL 문 사이의 모호성이다. 이 op 코드는 vmthread 섹션 (및 CALL!)뿐만 아니라 해당 서브 콜 섹션에서도 유효합니다. 모든 op 코드와 추가 OC_CALL 토큰이있는 OP_CODES 토큰을 정의하면 렉서가 상황을 처리 할 수 ​​없습니다 (분명히).

다음 목록은 내 문법 (첫 렉서, 두 번째 파서)의 조각입니다

VMTHREAD 
    : 'vmthread' 
    ; 

SUBCALL 
    : 'subcall' 
    ; 

CURLY_OPEN 
    : '{' 
    ; 

CURLY_CLOSE 
    : '}' 
    ; 

OP_CODES 
    : 'DATA8' 
    | 'DATAF' 
    | 'MOVE8_8' 
    | 'MOVEF_F' 
    | 'CALL' 
    ; 

OC_CALL 
    : 'CALL' 
    ; 

lms 
    : vmthread subcalls+ 
    ; 

vmthread 
    : VMTHREAD name = ID CURLY_OPEN vmthreadCall CURLY_CLOSE 
    ; 

vmthreadCall 
    : oc = OC_CALL name = ID 
    ; 

subcalls 
    : SUBCALL name = ID CURLY_OPEN ins = instruction* CURLY_CLOSE 
    ; 

//instruction+ 
instruction 
    : oc = OP_CODES args = argumentList 
    ; 

argumentList 
    : arguments+ 
    ; 

arguments 
    : INTEGER 
    | NUMBER 
    | TEXT 
    | ID 
    ; 

내가 토큰 OP_CODES와 vmthreadCall 파서 규칙에 OC_CALL 토큰을 전환했습니다 내 작업을 계속합니다. 코드가 자동 생성되므로 문제가 해결되었습니다. 그러나 사용자가이 코드를 입력하여 잘못 될 수있는 가능성이 있습니다.

이것에 대한 해결책이 있습니까 아니면 파서로 유효성 검사를 이동해야합니다. 여기서 vmthread 섹션의 명령문에 call 문만 포함되어 있는지 쉽게 판단 할 수 있습니다.

설명 : vmthread에는 CALL 만 허용됩니다. subcall (둘 이상일 수 있음)에서 모든 op 코드가 허용됩니다 (CALL + 모든 다른 op 코드가 정의 됨). 그리고 나는 다른 CALL 문장을 구별하고 싶지 않습니다. 문맥 자유 문법에서는 불가능하다고 생각합니다. 나는 파서에서 이것을 처리 할 것이다. vmthread를 하나의 CALL 문으로 제한하고 하위 호출의 모든 문 (모든 op 코드)을 허용하려고합니다. 바라기를 바란다.

+0

귀하의 질문은 불분명하다. 두 서브 루틴 모두에서 "호출"이 허용됩니까? 서브 콜의 호출과 vmthread의 호출을 구별하려고합니까? (ANTLR과 같은 문맥 자유 문법에서는 그렇게 할 수 없다). 내가 설명을위한 텍스트를 쓴 @IraBaxter –

+0

는 ("CALL"는 모두 서브 루틴에서 허용되고 나는 서로 다른 통화를 구별하지 않음). – FDeitelhoff

+0

확인. 너는 CALL이 애매하다고 말했다. 증거가 뭐니? –

답변

1
이처럼 렉서 규칙을 변경

:

OP_CODES 
    : 'DATA8' 
    | 'DATAF' 
    | 'MOVE8_8' 
    | 'MOVEF_F' 
    | OP_CALL 
    ; 

OC_CALL 
    : 'CALL' 
    ; 

또는 대안 그렇게 :

OP_CODES 
    : 'DATA8' 
    | 'DATAF' 
    | 'MOVE8_8' 
    | 'MOVEF_F' 
    | CALL 
    ; 

OC_CALL 
    : CALL 
    ; 

fragment CALL: 'CALL'; 

을, BTW 나는 (그 CALL 조각처럼) 당신이 당신의 리터럴에 대한 명시 적 렉서 규칙을 만드는 것이 좋습니다, 어떤 나중에 처리하기 쉽습니다. ANTLR은 암시 적으로 작성된 리터럴에 일반 이름을 할당하므로 어떤 토큰이 어떤 리터럴에 속하는지 찾기 어렵게 만듭니다. 당신은 당신이 의도와 일치 생각 문법을 생산 단지, 우리에게 * 구성 * 규칙을 이야기하지 않았기 때문에

+0

그래서 모든 연산 코드에 대한 렉서 규칙을 작성해야합니까? 지금까지는 다음과 같은 구문 분석 규칙을 사용하고 있습니다. oc = OP_CODES args = arguments newline oc 매개 변수를 통해 액세스 할 수 있습니다. 명시적인 렉서 규칙은 여전히 ​​개선 되었습니까? – FDeitelhoff

+0

예, 각 리터럴에 대한 렉서 규칙을 만들 것입니다.그런 다음 나중에 알려진 열거 형 (렉서 규칙 이름에서 파생 됨)을 통해 액세스 할 수 있습니다. 그것이 여기에있는 방식은 자동 생성 된 이름을 줄 것이고 어떤 문자를 사용했는지 알아내는 데 어려움을 겪을 것입니다. –