如何使用词法分析器生成的标记构建散列 table?

How to build a hash table with tokens produced by a lexer?

我想用词法分析器生成的词素构建一个散列 table。词法分析器只是一个简单的词法分析器,由 ocamllex 生成。
我产生的是以下代码:

          ...
let ht = Hashtbl.create 300
let add_lexeme = function
  | "MINUS" -> Hashtbl.add ht "-" "BINOP"
  ...
  | "EOF" -> Hashtbl.add ht "eof" "EOF"

let main () =
   let lexbuf = set_filename "stdin" @@ Lexing.from_channel stdin in
   let rec make_table =
     | EOF -> add_lexeme EOF
     | x   -> add_lexeme x (tokens lexbuf)
   let () = main ()

make_table 中出现语法错误。但是,我不喜欢这段代码的整体结构。我想知道一种更好(和正确)的方式来编码这个想法(我对 ocaml 很陌生)。

在你解决了很多小问题之后,我觉得你的代码在高层次上看起来还不错。它遍历标准输入的所有词位,将它们添加到 table.

一些低级评论:

正如评论者所说,您对 make_table 的定义没有意义。它在语法上无效。可能你想要:

let rec make_table = function
| EOF ...

您的 make_table 函数没有递归调用,因此它只是向 table 添加一个词素。事实上,根本没有对 make_table 的调用。您大概想要一个递归调用和一个来自 main.

的调用

您将一个名为 EOF 的值传递给 add_lexeme,它需要两个参数,第一个是字符串。所以,这不是一个有效的调用。可能你想要 "EOF" 在这里。如果是这样,您需要确保您的词法分析器 returns "EOF" 在文件末尾。 (但是 return 如果 EOF 实际出现在文件中会是什么?)

词法分析器通常return是代数类型,而不是字符串。你的词法分析器正在 returning 一个字符串。但它可以return任何你喜欢的类型。

@@ 运算符使得 f @@ g x 等价于 f (g x)。换句话说,避免括号主要有用。如果我看这个片段:

let lexbuf = set_filename "stdin" @@ Lexing.from_channel stdin

我很难决定它在做什么。相当于:

let lexbuf = set_filename "stdin" (Lexing.from_channel stdin)

这里有不少问题。有一个函数 Lexing.set_filename 但您没有提供模块名称。除非您自己编写名为 set_filename 的函数,否则这将不是有效调用。

假设您正在调用 Lexing.set_filename,这个函数 returns 单元。把lexbuf设置成unit是没有意义的。

我怀疑你本质上想要 ; 而不是 @@:

 let lexbuf = Lexing.from_channel stdin in
 Lexing.set_filename lexbuf "stdin";
 (* and so on *)

您调用了一个未在任何地方定义的名为 tokens 的函数。

这些都是小问题,您似乎要求的是更笼统的意见。如果您提供完整的工作示例,评论会更容易。

(* This is just an alias of the Hashtable module *)
module H = Hashtable

(* This function open a lexbuf and add the output to a hash table *)
let main () =
  let my_buf = set_filename "stdin" (Lexing.from_channel stdin) in
  let ht = H.create_hash 100 in
  let rec loop = function
    | EOF -> H.to_table EOF ht
    | x   -> (H.to_table x ht); loop (token my_buf)
  in
  loop (token my_buf);
  H.print_hash ht
  let () = main ()