OCaml lex: вообще не работает - PullRequest
4 голосов
/ 27 марта 2011

Я нахожусь в конце моей веревки здесь. Я ничего не могу заставить работать в ocamllex, и это сводит меня с ума. Это мой .mll файл:

{

open Parser

}

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

Вот содержимое файла, который я передаю в качестве ввода:

a=b;

Тем не менее, когда я компилирую и запускаю эту вещь, я получаю сообщение об ошибке на самом первом символе, говоря, что это недопустимо. Я, честно говоря, понятия не имею, что происходит, и Google не помог мне вообще. Как это вообще возможно? Как видите, я действительно в тупике.

EDIT:

Я работал так долго, что отказался от парсера. Теперь это соответствующий код в моем главном файле:

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

Распечатывает «строку: 1, столбец: 1».

Ответы [ 4 ]

10 голосов
/ 27 марта 2011

Без соответствующего анализатора 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) разрешает трассировку стека для необработанных исключений!

7 голосов
/ 28 марта 2011

кстати.ocamllex также может выполнять оператор + для 'одного или нескольких' в регулярных выражениях, поэтому этот

['a'-'z']+

эквивалентен вашему

['a'-'z']['a'-'z']*
1 голос
/ 15 января 2013

Я просто боролся с тем же (именно так я и нашел этот вопрос), только чтобы наконец понять, что я ошибочно указал путь к входному файлу как Sys.argv.(0) вместо Sys.argv.(1)!LOLs

Я очень надеюсь, что это поможет!:)

0 голосов
/ 03 апреля 2013

Похоже, у вас есть пробел в регулярном выражении для идентификаторов.Это может помешать лексеру распознать a = b, хотя он все равно должен распознать a = b;

...