2011-03-27 10 views
5

Estoy al final de mi cuerda aquí. No puedo hacer que funcione nada en ocamllex, y me está volviendo loco. Este es mi .mll archivo:OCaml lex: no funciona en absoluto,

{ 

open Parser 

} 

rule next = parse 
    | (['a'-'z'] ['a'-'z']*) as id { Identifier id } 
    | '=' { EqualsSign } 
    | ';' { Semicolon } 
    | '\n' | ' ' { next lexbuf } 
    | eof { EOF } 

Éstos son los contenidos del archivo que pase en como entrada:

a=b; 

Sin embargo, cuando me compilar y ejecutar la cosa, me sale un error en el primer personaje, diciendo que no es válido. Honestamente no tengo idea de lo que está pasando, y Google no me ha ayudado en absoluto. ¿Cómo puede esto ser posible? Como pueden ver, estoy realmente perplejo aquí.

EDIT:

estaba trabajando durante tanto tiempo que me di por vencido en el analizador. Ahora este es el código relevante en mi archivo principal:

let parse_file filename = 
    let l = Lexing.from_channel (open_in filename) in 
    try 
     Lexer.next l;() 
    with 
     | Failure msg -> 
     printf "line: %d, col: %d\n" l.lex_curr_p.pos_lnum l.lex_curr_p.pos_cnum 

Imprime "line: 1, col: 1".

+0

¿Podría proporcionar el archivo ML donde definió los constructores como identificador? Además, ¿podría confirmar que ocamllex y ocamlc no presentaron una queja en el momento de la compilación? – Surikator

+0

Se definieron en parser.mly como estándar y ninguno se queja. – marsolk

+1

@marsolk: Tengo curiosidad, ¿alguna vez te diste cuenta? ¿Cual fue el problema? – lebowski

Respuesta

10

Sin el correspondiente analizador ocamlyacc, nadie podrá encontrar el problema con su código ya que su lexer funciona perfectamente bien!

Me he tomado la libertad de escribir el siguiente pequeño analizador (parser.mly) que construye una lista de pares de identificadores, p. entrada "a = b" debería dar la lista singleton [("a", "b")].

%{%} 

%token <string> Identifier 
%token EqualsSign 
%token Semicolon 
%token EOF 

%start start 
%type <(string * string) list> start 

%% 

start: 
| EOF {[]} 
| Identifier EqualsSign Identifier Semicolon start {($1, $3) :: $5} 
; 

%% 

Para probar si el analizador hace lo que prometí, creamos otro archivo (main.ml) que analiza la cadena "a = b;" e imprime el resultado.

let print_list = List.iter (fun (a, b) -> Printf.printf "%s = %s;\n" a b) 
let() = print_list (Parser.start Lexer.next (Lexing.from_string "a=b;")) 

El código debe compilar (por ejemplo ocamlbuild main.byte) sin ninguna queja y el programa debe ser la salida "a = b;" como fue prometido.


En respuesta a la última edición:

En general, no creo que la captura de excepciones de la biblioteca estándar que están destinados a indicar un fallo o mal uso (como Invalid_argument o fracaso) es una buena idea. La razón es que se utilizan de forma ubicua en toda la biblioteca, de modo que, por lo general, no se puede saber qué función provocó la excepción y por qué lo hizo.

Además, está desperdiciando la única información útil: ¡el mensaje de error! El mensaje de error debe decirle cuál es el origen del problema (mi mejor estimación es un problema relacionado con IO). Por lo tanto, debe imprimir el mensaje de error o dejar que la excepción se propague a toplevel. Personalmente, prefiero la última opción.

Sin embargo, es probable que todavía desee tratar las entradas sintácticamente mal formadas de una manera elegante. Para esto, puede definir una nueva excepción en el lexer y agregar un caso predeterminado que capture tokens no válidos.

{ 
    exception Unexpected_token 
} 
... 
| _ {raise Unexpected_token} 

Ahora, se puede coger la excepción que acaba de definir en el archivo principal y, a diferencia de antes, la excepción es específica a las entradas no válidas sintácticamente. En consecuencia, usted sabe tanto la fuente como la causa de la excepción que le da la oportunidad de hacer algo mucho más significativo que antes.

Indicación de desarrollo de OCaml bastante aleatoria: Si compila el programa con información de depuración habilitada, establecer la variable de entorno OCAMLRUNPARAM en "b" (por ejemplo, exportar OCAMLRUNPARAM = b) ¡habilita las trazas de pila para excepciones no detectadas!

+1

Supongo que debería haber mencionado que después de intentar durante tanto tiempo, ahora solo estoy probando sin el analizador, y aún así me da este error. Editaré la publicación con el código de mi archivo principal. – marsolk

+0

Normalmente, no lo haría; en este caso, obtenía 'Failure (" lexing: empty token ")', que levanté la vista para encontrar que significaba que veía un personaje que no correspondía a nada en el lexer. Finalmente, puse otra regla: '| _ como c {Printf.printf "Carácter no reconocido:% c \ n" c; raise (Failure "")} ' , y ahora imprime" Personaje no reconocido: a ". Sin embargo, intentaré con la información de depuración para ver qué está pasando. – marsolk

6

por cierto. ocamllex también puede hacer que el operador + de 'uno o más' en expresiones regulares, por lo que este

['a'-'z']+ 

es equivalente a su

['a'-'z']['a'-'z']* 
1

Estaba luchando con lo mismo (que es como yo encontró esta pregunta), solo para finalmente darse cuenta de que había especificado erróneamente la ruta al archivo de entrada como Sys.argv.(0) en lugar de Sys.argv.(1)! LOLs

¡Realmente espero que ayude! :)

-1

Parece que tiene un espacio en la expresión regular para los identificadores. Esto podría evitar que el lexer reconozca a = b, aunque todavía debería reconocer a = b;

Cuestiones relacionadas