2016-11-21 2 views
0

ich eine Grammatik, die den folgenden Code-Schnipsel (als Beispiel) analysieren soll:Handhabung Grammar Mehrdeutigkeit in ANTLR4

vmthread programm_start 
{ 
    CALL main 
} 

subcall main 
{ 
    // Declarations 
    DATAF i 

    CALL i 

    // Statements 
    MOVEF_F 3 i 
} 

Das Problem ist die Mehrdeutigkeit zwischen der CALL-Anweisung. Dieser Op-Code ist im vmthread-Abschnitt (und nur in CALL!) Gültig, aber auch in diesen Unterabschnitten. Wenn ich ein OP_CODES-Token mit allen Op-Codes und einem zusätzlichen OC_CALL-Token definiere, kann der Lexer (offensichtlich) nicht mit der Situation umgehen.

Die folgenden Auflistungen sind Auszüge, meine Grammatik (erste Lexer, zweiter Parser):

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 
    ; 

meine Arbeit fortzusetzen Ich habe Token die OC_CALL Token in der vmthreadCall Parser-Regel mit dem OP_CODES geschaltet. Das löst das Problem jetzt, da der Code automatisch generiert wird. Aber es gibt die Möglichkeit, dass ein Benutzer diesen Code eingeben kann, damit dies schief gehen kann.

Gibt es eine Lösung dafür oder sollte ich die Validierung in den Parser verschieben. Dort kann ich leicht feststellen, ob die Anweisung im vmthread-Abschnitt nur die Aufrufanweisung enthält.

Zur Verdeutlichung: Im vmthread ist nur die CALL erlaubt. In der Unterklasse (könnte mehr als eine sein) ist jeder Op-Code erlaubt (CALL + jeder andere Op-Code definiert). Und ich möchte nicht zwischen diesen verschiedenen CALL-Anweisungen unterscheiden. Ich weiß, dass das in einer kontextfreien Grammatik nicht möglich ist. Ich werde das im Parser behandeln. Ich möchte nur den vmthread auf die eine CALL-Anweisung beschränken und alle Anweisungen (alle Op-Codes) in den Unteralls zulassen. Hoffentlich ist das klarer.

+0

Ihre Frage ist unklar, weil Sie uns die * beabsichtigten * Regeln nicht gesagt haben, nur dass Sie eine Grammatik produziert haben, die Ihrer Meinung nach den Absichten entspricht. Ist "CALL" in beiden Unterprogrammen erlaubt? Versuchen Sie, einen Aufruf im vmthread von dem Aufruf im Unterordner zu unterscheiden? (Sie können das nicht in einer kontextfreien Grammatik [wie ANTLR]). –

+0

@IraBaxter Ich schrieb einen Text zur Verdeutlichung ("CALL" ist in beiden Subroutinen erlaubt und ich möchte die verschiedenen CALLs nicht unterscheiden). – FDeitelhoff

+0

OK. Sie sagten, CALL sei zweideutig. Was sind deine Beweise? –

Antwort

1

Ihre Lexer Regeln wie folgt ändern:

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

OC_CALL 
    : 'CALL' 
    ; 

oder alternativ so:

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

OC_CALL 
    : CALL 
    ; 

fragment CALL: 'CALL'; 

Btw, ich empfehle, dass Sie explizite Lexer Regeln für Ihre Literale (wie die CALL-Fragment), erstellen die erleichtert die spätere Verarbeitung. ANTLR weist implizit erstellten Literalen generische Namen zu, wodurch es schwierig wird herauszufinden, welcher Token zu welchem ​​Literal gehört.

+0

Also sollte ich lexer Regeln für jeden Op-Code erstellen? Bis jetzt benutze ich eine Parser-Regel wie folgt: oc = OP_CODES args = Argumente newlines, die über den Parameter oc zugänglich sind. Sind explizite Lexer-Regeln immer noch eine Verbesserung? – FDeitelhoff

+0

Ja, ich würde eine Lexer-Regel für jedes Literal erstellen. –