如何用词法分析器生成的令牌构建哈希表?



我想用词法分析器生成的词元构建一个哈希表。词法分析器只是一个简单的词法分析器,由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)。

在你解决了许多小问题之后,你的代码在高层次上看起来还不错。它遍历stdin的所有元素,并将它们添加到表中。

一些低级注释:

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

let rec make_table = function
| EOF ...

你的make_table函数没有递归调用,所以它只会向表中添加一个词素。实际上根本没有对make_table的调用。您可能需要一个递归调用和一个来自main的调用。

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

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

@@运算符使得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,这个函数返回unit。设置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 ()

最新更新