我已经定义了一个哈希表keyword_table
来存储我语言的所有关键字。以下是代码的一部分:
(* parser.mly *)
%token CALL CASE CLOSE CONST
...
reserved_identifier:
| CALL { "Call" }
| CASE { "Case" }
| CLOSE { "Close" }
| CONST { "Const" }
...
(* lexer.mll *)
{let hash_table list =
let tbl = Hashtbl.create (List.length list) in
List.iter (fun (s, t) -> Hashtbl.add tbl (lowercase s) t) list;
tbl
let keyword_table = hash_table [
"Call", CALL; "Case", CASE; "Close", CLOSE; "Const", CONST;
... ]}
rule token = parse
| lex_identifier as li
{ try Hashtbl.find keyword_table (lowercase li)
with Not_found -> IDENTIFIER li }
由于有很多关键字,我真的希望避免重复代码。
在parser.mly
中,似乎无法简化%token CALL CASE ...
,因为必须明确定义每个令牌。但是,对于reserved_identifier
部分,是否可以调用函数从令牌中返回字符串,而不是对每个字符串进行硬编码?
因此,这表明哈希表可能不适用于此目的。哪种数据结构是双方搜索的最佳选择(我们假设双方的每个密钥都是唯一的)?因此,我们希望实现find_0 table "Call"
返回令牌CALL
(在lexer.mll
中使用)和find_1 table CALL
返回"Call"
(在parser.mly
中使用)
此外,如果可以定义此table
,我应该在哪里放置它以便parser.mly
可以使用它?
答案 0 :(得分:2)
当你在词法分析器中时,可以获得字符串,恰好在与令牌匹配的点(例如Lexing.lexeme
)。试图在解析器中获取它已经太晚了。我们不希望令牌流将所有字符串保留在内存中,因为它会大量增加内存消耗(实际上大多数令牌都不需要它们的字符串表示)。
为什么不构建从关键字值(或标记值)到字符串的反向表,同时构建第一个映射? hash_table
可以重命名为hash_tables
并返回两张反向地图。
如果您希望它从解析器和词法分析器中可见,则可能需要在解析器中定义。