ParserErr генерирует исключение индекса за пределами границ

Я создаю компилятор и пытаюсь извлечь информацию о строке из парсера. Я хочу прикрепить это к узлу AST в качестве метаданных, чтобы можно было легко сообщить о любой ошибке на более позднем этапе. Мне удалось извлечь информацию о строке в Lexer, используя это:

exception LexErr of string
exception ParseErr of string

let error msg start finish  = 
    Printf.sprintf "(line %d: char %d..%d): %s" start.pos_lnum 
      (start.pos_cnum -start.pos_bol) (finish.pos_cnum - finish.pos_bol) msg

let lex_error lexbuf = 
    raise ( LexErr (error (lexeme lexbuf) (lexeme_start_p lexbuf) (lexeme_end_p lexbuf)))

Это генерирует номер строки, номер символа для Lexer после его использования следующим образом:

rule read = parse
(* Lexing tokens *)
| _ { lex_error lexbuf }

Для парсера я использую этот метод:

exception LexErr of string
exception ParseErr of string

let error msg start finish = 
    Printf.sprintf "(line %d: char %d..%d): %s" start.pos_lnum 
      (start.pos_cnum -start.pos_bol) (finish.pos_cnum - finish.pos_bol) msg

let parse_error msg nterm =
    raise (ParseErr (error msg (rhs_start_pos nterm) (rhs_end_pos nterm)))

Мой парсер выглядит так:

%start <Ast.stmt> program

%%

program:
  | s = stmt; EOF { s }
  ;

stmt:
  | TINT; e = expr { Decl(e) }
  | e1 = expr; EQUALS; e2 = expr { Assign(e1,e2) }
  | error             { parse_error "wsorword" 1 }
  ;

expr:
  | i = INT; { Const i }
  | x = ID { Var x }
  | e1 = expr; b = binop; e2 = expr; { Binop(e1,b,e2) }
  ;

binop:
  | SUM { Sum }
  | SUB { Sub }
  | MUL { Mul }
  | DIV { Div }
  ;

При выполнении этого, если обнаружена ошибка синтаксического анализатора, он выдает исключение invalid_argument «Индекс вне границ». Это обнаружено в строке raise (ParseErr (error msg (rhs_start_pos nterm) (rhs_end_pos nterm))). В конечном итоге я хотел бы создать узел AST, который содержит информацию об этой строке синтаксического анализатора в качестве метаданных, но не может пройти через это исключение. Я не уверен, что мой метод реализации неверен или я делаю какую-то другую ошибку. Хотелось бы помощи в этом.


person pleasehalp    schedule 08.05.2018    source источник
comment
Я только что быстро погуглил, но мне кажется, что в вашем правиле ошибок есть только 0-й символ. Символа номер 1 нет. Возможно, проблема в том, что вы передаете 1 в rhs_start_pos и rhs_end_pos.   -  person Jeffrey Scofield    schedule 08.05.2018
comment
Я имел в виду руководство ocamlyacc. Там написано, что Parsing.rhs_start_pos n, где n равно 1 для крайнего левого элемента, а первый символ в файле имеет смещение 0. Кроме того, я пытался передать 0 в качестве аргумента, это не работает. Если вы имели в виду что-то другое? @ДжеффриСкофилд   -  person pleasehalp    schedule 08.05.2018


Ответы (1)


Функцию rhs_start_pos nth нельзя использовать с парсерами менгиров; в этом случае вы должны использовать $symbolstartpos или $startpos.

Точно так же e = expr недействителен с ocamlyacc.

Таким образом, я не уверен, какой генератор парсера вы пытаетесь использовать.

person octachron    schedule 08.05.2018
comment
Я использую менгир. Я предполагал, что модуль Locations будет работать с ним. Не могли бы вы указать мне на некоторые ресурсы или библиотеку примеров, на которые я могу ссылаться, чтобы понять это? Я просмотрел документацию по менгиру, но мне нужно немного больше примеров, чтобы разобраться. - person pleasehalp; 09.05.2018
comment
Модуль Location работает, это модуль Parsing специфичный для ocamlyacc. Хорошим, но длинным примером может быть анализатор причин, github .com/facebook/reason/blob/master/src/reason-parser/ . Примечательно, что он использует как $symbolstart, так и друзья и параметрическое правило (github.com/facebook/reason/blob/master/src/reason-parser/), чтобы вставить местоположение в нужном месте. - person octachron; 09.05.2018