Ошибка разбора ocamlyacc: какой токен? - PullRequest
15 голосов
/ 19 декабря 2009

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

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

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

Спасибо.

Ответы [ 3 ]

20 голосов
/ 29 июля 2010

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

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

$ export OCAMLRUNPARAM='p'
15 голосов
/ 21 декабря 2009

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

  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 голосов
/ 19 декабря 2009

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

Редактировать: ответ на комментарий.

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

3.1.5. Программа сообщений об ошибках

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

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

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

...