Без соответствующего анализатора ocamlyacc никто не сможет найти проблему с вашим кодом, так как ваш лексер работает отлично!
Я позволил себе написать следующий крошечный синтаксический анализатор (parser.mly), который создает список пар идентификаторов, например, введите "a = b;" должен дать список синглтонов [("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}
;
%%
Чтобы проверить, выполняет ли парсер то, что я обещал, мы создаем другой файл (main.ml), который анализирует строку «a = b;» и печатает результат.
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;"))
Код должен компилироваться (например, ocamlbuild main.byte) без каких-либо жалоб, и программа должна вывести «a = b;» как и обещал.
В ответ на последнее изменение:
В общем, я не верю, что перехват стандартных библиотечных исключений, предназначенных для указания сбоя или неправильного использования (например, Invalid_argument или Failure), является хорошей идеей. Причина в том, что они используются повсеместно в библиотеке, так что вы обычно не можете определить, какая функция вызвала исключение и почему она это сделала.
Кроме того, вы выбрасываете единственную полезную информацию: сообщение об ошибке! В сообщении об ошибке должно быть указано, в чем причина проблемы (моя лучшая догадка - проблема, связанная с IO). Таким образом, вы должны либо распечатать сообщение об ошибке, либо разрешить распространению исключения на верхний уровень. Лично я предпочитаю последний вариант.
Однако вы, вероятно, все еще хотите иметь дело с синтаксически неправильно сформированными входами изящно. Для этого вы можете определить новое исключение в лексере и добавить регистр по умолчанию, который перехватывает недопустимые токены.
{
exception Unexpected_token
}
...
| _ {raise Unexpected_token}
Теперь вы можете перехватить вновь определенное исключение в вашем основном файле, и, в отличие от ранее, это исключение относится к синтаксически неверным входам. Следовательно, вы знаете как источник, так и причину исключения, что дает вам возможность сделать что-то гораздо более значимое, чем раньше.
Довольно случайный совет по разработке OCaml: Если вы компилируете программу с включенной отладочной информацией, задайте для переменной среды OCAMLRUNPARAM значение "b" (например, экспорт OCAMLRUNPARAM = b) разрешает трассировку стека для необработанных исключений!