我正在创建一个编译器,并试图从解析器中提取行信息。我希望将此作为元数据附加到 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 “Index out of bounds”异常。这是raise (ParseErr (error msg (rhs_start_pos nterm) (rhs_end_pos nterm)))
在线检测的。我最终想创建一个包含此解析器行信息的 AST 节点,因为它是元数据,但无法通过此异常。我不确定我的实施方法是否错误,或者我是否犯了其他错误。希望对此有所帮助。