2009-12-19 4 views
15

Sto usando ocamlyacc e ocamllex. Ho una produzione di errori nella mia grammatica che segnala un'eccezione personalizzata. Finora, posso farlo per segnalare la posizione di errore:errore di analisi ocamlyacc: quale token?

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

Ma voglio anche sapere quale pegno è stato letto. Ci deve essere un modo --- qualcuno lo sa?

Grazie.

risposta

14

Gettoni sono generati da lexer, quindi è possibile utilizzare il token lexer corrente quando si verifica l'errore:

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 è quello che ti serve. Altre parti non sono necessarie ma utili. ruleTail concatena tutti i rimanenti token in stringa per consentire all'utente di individuare facilmente la posizione dell'errore. lexbuf.Lexing.lex_curr_p deve essere aggiornato nel lexer per contenere le posizioni corrette. (source)

+0

Ottima risposta. Ho una domanda, però: perché dobbiamo usare 'lexbuf.Lexing.lex_curr_p' invece di' lexbuf.lex_curr_p'? – GiantSquid

+0

Poiché 'lex_curr_p' appartiene al modulo' Lexing'. O aprilo o aspetta che OCaml diventi più saggio e capisca i riferimenti ai campi dei record non qualificati. – ygrek

+2

Dove trovi Sql_lexer. ed errore? –

2

Penso che, analogamente a yacc, i token siano memorizzati in variabili corrispondenti ai simboli nella regola della grammatica. Qui poiché c'è un simbolo (errore), potresti essere in grado di produrre semplicemente $ 1 usando printf, ecc.

Modifica: rispondere al commento.

Perché si utilizza un terminale di errore? Sto leggendo un tutorial su ocamlyacc che dice che una speciale routine di gestione degli errori viene chiamata quando si verifica un errore di analisi. In questo modo:

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 

Beh, sembra che si ottiene solo "Errore di sintassi" con quella funzione però. Restate sintonizzati per maggiori informazioni.

+1

Purtroppo, che non funziona: File "parser.mly", la linea 372: $ 1 si riferisce al terminale ' errore ', che non ha argomenti –

+1

Puoi mostrarmi il codice per l'intera funzione? Potrei essere in grado di offrire più informazioni allora. – danben

19

Il modo migliore per eseguire il debug ocamlyacc parser è quello di impostare il OCAMLRUNPARAM param per includere il personaggio p - questo renderà la stampa parser tutti gli stati che passa attraverso, e ogni turno/ridurre esegue.

Se si utilizza bash, è possibile farlo con il seguente comando:

$ export OCAMLRUNPARAM='p'