【问题标题】:How to get more information out of the Ocaml Compiler如何从 Ocaml 编译器中获取更多信息
【发布时间】:2018-06-11 05:11:43
【问题描述】:

我在ocamlc 上度过了最艰难的时光,这是极其无信息的错误消息。现在,当我编译我的一个文件时,它给了我

Error: Syntax Error

在文件的最后一行,它是空的。所以,我假设我缺少一些左括号之类的东西,我不确定。无论如何,在生产环境中使用 Ocaml 的人如何处理这个问题?是否有任何可用的工具可以提供任何关于词法分析器期望的字符的任何提示,或者只是更好的一般错误消息?

具体来说,我正在寻找像this 这样的工具,它看起来很棒。但它看起来不再处于开发中,但这看起来像是一个将 Ocaml 编译为 Javascript 的工具,这不是我想要的最终结果。

任何关于人们通常如何解决 Ocaml 语法错误的建议都会很棒。

【问题讨论】:

  • 我不直接使用ocamlc,但至少应该有一些位置信息。你确定没有?
  • 顺便说一句,BetterErrors 已被“超级错误”取代,该错误已融入 BuckleScript 及其使用的稍加修改的编译器。我认为在上游进行了一些努力,但这些事情往往需要一些时间(从长远来看,这不一定是坏事)。
  • @glennsl 肯定有“位置信息”,但在我目前的情况下,位置指向文件的最后一行字符 0-0。并且文件的最后 40 行只有 cmets。 BuckleScript 似乎是一个“太重”的工具。我只是想要一个稍微好一点的错误报告系统,而不是一个 JS 集成/交叉编译/等的完整构建系统。
  • 如果位置信息不好,可能没有什么像 BetterErrors 或超级错误这样的“附加组件”可以做。您可能必须重新设计整个解析器,甚至更改语法以拥有更多包含语法错误的隔板。问题很可能是,在句法层面上,直到它到达结尾并注意到缺少某些东西(可能是未闭合的括号或其他东西)之前根本没有错误。如果您认为很难追查此类错误的原因,请想象一下自己是一个甚至不了解您要做什么的编译器!
  • 嗯,我绝对同意这一点。但是,就像我在 clang/GNU 编译器中看到的那样,也许它会告诉我它的期望。 Idk,也许我要求太多了:/无论如何,肯定没有任何公司在生产中使用 Ocaml 使用这些准系统错误消息。

标签: compiler-errors syntax-error ocaml


【解决方案1】:

给定一个.ml:

let a = 42 in
let f x = x + a
let g x = x + x

编译时会出现这个错误:

$ ocamlc one.ml 
File "one.ml", line 3, characters 0-3:
Error: Syntax error

ocamlc 放弃了在第三行的 let 处理解这一点,因为此时第 2 行的唯一可能延续是 in 和另一个表达式(或 x + x 的延续,如 @ 987654326@)。这里的基本问题是 ocamlc 没有在第 1 行的末尾抛出错误,因为 ocamlc 试图同时允许 正确的 OCaml 和你可以粘贴到交互式会话中的一堆表达式。它甚至允许在文件中使用;;,这很荒谬:;; 只需要交互,因为没有一些特殊的终止规则(如 Python 的结束定义的空白空行 - 但只能交互)OCaml 无法知道表达式是' 不能由运算符和另一个表达式继续。 ocamlc 试图容忍混淆,以至于混淆被延长,而不是被纠正。

那么什么是正确的 OCaml?无论出于何种原因,它都没有很好地记录下来。但是,当您了解某些形式可以将“最左边”放在文件中并且某些形式只能作为第一种形式的子表达式存在时,或者如果您在记住时尝试阅读编写良好的 OCaml,您会很快感受到它空格在 OCaml 中与 C 中的方式相同:OCaml 没有使用定义之间的空白行来理解这些定义是分开的,那么它是如何分隔它们的呢?

或者,您可以从一些规则开始。 “不要使用 let ... in 除非作为子表达式。” “不要尝试执行副作用,除非是 let () = 的子表达式”、“将分号视为需要右侧的运算符,而不是终止符”等。

因此,除了 one.ml,任何这些都可以工作:

let a = 42
let f x = x + a
let g x = x + x

let f x =
  let a = 42 in
  x + a
let g x = x + x

或者(显然这是不好的风格):

let f x = let a = 42 in x + a let g x = x + x

two.ml 还有另一个常见错误:

let () =
  print_endline "hi";

let f x = x + x

您将在第 5 行收到“语法错误”,字符 0=0。这是 ocamlc 到达文件的末尾,但仍然没有看到必须遵循的 in(或 x + x 的延续)。因为第 2 行的 ; 意味着第 4 行的 let 必须是第 1 行的 let 的子表达式。

除了两个.ml,任何一个都可以:

let () =
  print_endline "hi"

let f x = x + x

或者(还是不好的风格,但是用分号想象一下):

let () = print_endline "hi" let f x = x + x

虽然您也可以使用let x = [| ] 获得“纯”语法错误,但即使是 OCaml 的新手也会在发现抱怨的行和字符范围时识别出此类错误,因此此类错误不会令人沮丧one.ml和two.ml的级别

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-29
    • 1970-01-01
    • 2020-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多