在编写解析器时,我想记住发现的词法的位置,这样我就可以向程序员报告有用的错误消息,如“第23行的if-less else”或“第45行的意外字符,字符6“或”未定义的变量“或类似的东西。但是一旦我构建了语法树,我将以多种方式对其进行转换,优化或扩展某种宏。转换产生或重新排列没有有意义位置的词位。
因此,似乎表示语法树的类型应该有两种风格,一种具有装饰词位的位置和没有词位的味道。理想情况下,我们希望使用纯粹抽象的语法树,如OCaml book:
中所定义# type unr_op = UMINUS | NOT ;;
# type bin_op = PLUS | MINUS | MULT | DIV | MOD
| EQUAL | LESS | LESSEQ | GREAT | GREATEQ | DIFF
| AND | OR ;;
# type expression =
ExpInt of int
| ExpVar of string
| ExpStr of string
| ExpUnr of unr_op * expression
| ExpBin of expression * bin_op * expression ;;
# type command =
Rem of string
| Goto of int
| Print of expression
| Input of string
| If of expression * int
| Let of string * expression ;;
# type line = { num : int ; cmd : command } ;;
# type program = line list ;;
我们应该被允许在处理该树时完全忘记位置,并具有将expression
映射回其位置(例如)的特殊功能,以便在紧急情况下使用。
在OCaml中定义此类型或处理词位位置的最佳方法是什么?
答案 0 :(得分:1)
最好的方法是始终使用位置完全注释AST节点。例如:
type expression = {
expr_desc : expr_desc;
expr_loc : Lexing.position * Lexing.position; (* start and end *)
}
and expr_desc =
ExpInt of int
| ExpVar of string
| ExpStr of string
| ExpUnr of unr_op * expression
| ExpBin of expression * bin_op * expression
我相信你的想法,保持AST没有位置并编写功能来检索缺失的位置并不是一个好主意。这样的函数应该要求通过AST节点的指针等价或类似的东西进行搜索,这不能真正扩展。
我强烈建议您查看OCaml编译器parser.mly
,这是带位置的AST的完整示例。