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