Ocamlyacc ошибка анализа: какой токен?

Я использую ocamlyacc и ocamllex. У меня есть ошибка в моей грамматике, которая сигнализирует о специальном исключении. Пока что я могу сообщить об ошибке:

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

Но я также хочу знать, какой токен был прочитан. Должен быть какой-то способ - кто-нибудь знает?

Спасибо.

Ответы

Ответ 1

Токены генерируются с помощью lexer, поэтому при возникновении ошибки можно использовать текущий токен лексера:

  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 - это то, что вам нужно. Другие части не нужны, но полезны. ruleTail выполнит все оставшиеся токены в строке, чтобы пользователь мог легко найти местоположение ошибки. lexbuf.Lexing.lex_curr_p должен быть обновлен в лексере, чтобы содержать правильные позиции. (источник)

Ответ 2

Лучший способ отладки вашего синтаксического анализатора ocamlyacc - установить параметр OCAMLRUNPARAM для включения символа p - это заставит синтаксический анализатор распечатать все состояния, через которые он проходит, и каждая смена /.

Если вы используете bash, вы можете сделать это с помощью следующей команды:

$ export OCAMLRUNPARAM='p'

Ответ 3

Я думаю, что, подобно yacc, токены хранятся в переменных, соответствующих символам в правиле грамматики. Здесь, поскольку есть один символ (ошибка), вы можете просто вывести $1 с помощью printf и т.д.

Изменить: ответ на комментарий.

Почему вы используете терминал ошибок? Я читаю учебник ocamlyacc, в котором говорится, что специальная процедура обработки ошибок вызывается при возникновении ошибки синтаксического анализа. Например:

3.1.5. Процедура отчетности об ошибках

Когда функция parser обнаруживает синтаксическая ошибка, она вызывает функцию с именем parse_error со строкой "синтаксическая ошибка" в качестве аргумента. функция по умолчанию parse_error делает ничего и не возвращает, тем самым инициируя (см. Восстановление ошибок). Пользователь может определить индивидуальный parse_error в заголовке раздел файла грамматики, например:

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

Ну, похоже, вы только получаете "синтаксическую ошибку" с этой функцией. Оставайтесь с нами для получения дополнительной информации.