2009-12-19 8 views
15

Ich benutze ocamlyacc und ocamllex. Ich habe eine Fehlerproduktion in meiner Grammatik, die eine benutzerdefinierte Ausnahme signalisiert. Bisher kann ich es die Fehlerposition zu berichten:ocamlyacc parse Fehler: Was Token?

| error { raise (Parse_failure (string_of_position (symbol_start_pos()))) } 

Aber ich möchte auch wissen, welche Token gelesen wurde. Es muss einen Weg geben - jemand weiß?

Danke.

Antwort

14

Tokens werden von Lexer erzeugt, daher können Sie den aktuellen Lexer-Token verwenden, wenn Fehler auftreten:

let parse_buf_exn lexbuf = 
    try 
     T.input T.rule lexbuf 
    with exn -> 
     begin 
     let curr = lexbuf.Lexing.lex_curr_p in 
     let line = curr.Lexing.pos_lnum in 
     let cnum = curr.Lexing.pos_cnum - curr.Lexing.pos_bol in 
     let tok = Lexing.lexeme lexbuf in 
     let tail = Sql_lexer.ruleTail "" lexbuf in 
     raise (Error (exn,(line,cnum,tok,tail))) 
     end 

Lexing.lexeme lexbuf ist das, was Sie brauchen. Andere Teile sind nicht notwendig, aber nützlich. ruleTail concat alle verbleibenden Token in Zeichenfolge für den Benutzer leicht Fehlerstelle zu lokalisieren. lexbuf.Lexing.lex_curr_p sollte im Lexer aktualisiert werden, um korrekte Positionen zu enthalten. (source)

+0

Große Antwort. Ich habe jedoch eine Frage: Warum müssen wir 'lexbuf.Lexing.lex_curr_p' anstelle von' lexbuf.lex_curr_p' verwenden? – GiantSquid

+0

Weil 'lex_curr_p' zum' Lexing' Modul gehört. Öffnen Sie es oder warten Sie, bis OCaml weiser wird und nicht qualifizierte Feldreferenzen kennt. – ygrek

+2

Wo finden Sie Sql_lexer? und Fehler? –

2

Ich denke, dass die Token ähnlich wie yacc in Variablen gespeichert sind, die den Symbolen in Ihrer Grammatikregel entsprechen. Hier, da es ein Symbol (Fehler) gibt, können Sie möglicherweise $ 1 ausgeben, indem Sie printf, etc.

Edit: Reagieren auf Kommentar.

Warum verwenden Sie ein Fehlerterminal? Ich lese ein ocamlyacc-Tutorial, das besagt, dass eine spezielle Fehlerbehandlungsroutine aufgerufen wird, wenn ein Parse-Fehler auftritt. Wie so:

3.1.5. The Error Reporting Routine

When ther parser function detects a syntax error, it calls a function named parse_error with the string "syntax error" as argument. The default parse_error function does nothing and returns, thus initiating error recovery (see Error Recovery). The user can define a customized parse_error function in the header section of the grammar file such as:

let parse_error s = (* Called by the parser function on error *) 
    print_endline s; 
    flush stdout 

Nun sieht, wie du nur wenn mit dieser Funktion "Syntaxfehler" erhalten. Bleiben Sie dran für weitere Informationen.

+1

Leider, das nicht funktioniert: File "parser.mly", Zeile 372: $ 1 bezieht sich auf Terminal ' Fehler ', der kein Argument hat –

+1

Können Sie mir den Code für die gesamte Funktion zeigen? Vielleicht kann ich dann mehr Einblick geben. – danben

19

Der beste Weg, um Ihren ocamlyacc Parser zu debuggen ist die OCAMLRUNPARAM param, um den Charakter schließen p - das ist der Parser Druck machen alle Staaten, dass es durchläuft, und jede Verschiebung/verringern er ausführt.

Wenn Sie bash verwenden, können Sie dies mit folgendem Befehl tun:

$ export OCAMLRUNPARAM='p'