如何使用词法分析器生成的标记构建散列 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 ()
我想用词法分析器生成的词素构建一个散列 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 ()