从 stdin\file 读取时的 OCaml 字符串长度限制

OCaml string length limitation when reading from stdin\file

作为我在大学学习的编译器原理课程的一部分,我们正在编写一个在 OCaml 中实现的编译器,它将 Scheme 代码编译成类似 CISC 的程序集(这只是 C 宏)。 编译器的基本操作是这样的:

  1. 读取 *.scm 文件并将其转换为 OCaml string
  2. 解析字符串并执行各种分析。
  3. 运行 语义分析器输出的 AST 上的代码生成器,将文本输出到 *.c 文件中。
  4. 使用 GCC 编译该文件并在终端中运行它。

嗯,一切都很好,除了这个:我正在尝试读取一个大约 4000 行长的输入文件,基本上是一个混合了 Scheme if & and。 我正在通过 utop 执行编译器。当我尝试读取输入文件时,我立即收到堆栈溢出错误消息。我最初猜测该文件对于 OCaml 来说太大了,但我找不到任何支持这一理论的文档。

有什么建议吗?

最大字符串长度由 Sys.max_string_length 给出。对于 32 位系统,它很短:16777211。对于 64 位系统,它是 144115188075855863。

除非您使用的是 32 位系统,并且您的 4000 行文件超过 16MB,否则我认为您没有达到字符串长度限制。

当字符串太长时,堆栈溢出不是您期望看到的。

更有可能的是你有无限递归,或者可能只是嵌套很深的计算。

嗯,事实证明限制是 ​​OCaml 配置使用的最大 ram 的数量。

我运行在终端中执行以下命令以增加配额:

export OCAMLRUNPARAM="l=5555555555"

这太棒了 - 我几乎在瞬间就读取并编译了输入文件。

为了参考,这是读取文件的代码:

let file_to_string input_file =
  let in_channel = open_in input_file in
  let rec run () =
    try
      let ch = input_char in_channel in ch :: (run ())
    with End_of_file ->
      ( close_in in_channel;
       [] )
  in list_to_string (run ());;

其中 list_to_string 是:

let list_to_string s =
  let rec loop s n =
    match s with
    | [] -> String.make n '?'
    | car :: cdr ->
       let result = loop cdr (n + 1) in
       String.set result n car;
       result
  in
  loop s 0;;

有趣的是——我在尾递归中写了 file_to_string。这防止了堆栈溢出,但由于某种原因进入了无限循环。哦,好吧...