使用ocamllex构建无parser模块的lexer时Unbound constructor报错如何解决
基于ocamllex独立实现可用lexer的操作方案
你遇到的报错是因为词法规则中返回的COMMA等构造子没有提前定义类型,按以下步骤操作即可解决:
步骤1:补充token类型定义
.mll文件的开头有一段被{}包裹的OCaml原生代码区域,你需要在这个区域先定义所有用到的token变体类型,示例如下:
{ (* 定义所有词法规则会返回的token构造子 *) type token = | COMMA | SEMICOLON | LPAREN | RPAREN | LBRACKETS | RBRACKETS | LBRACE | RBRACE (* 后续你自己新增的其他token也需要补在这里,比如标识符、数字、关键字: *) | IDENT of string | INT of int | KEYWORD_IF | EOF (* 可选:新增token转字符串的工具函数,方便测试打印 *) let show_token = function | COMMA -> "COMMA" | SEMICOLON -> "SEMICOLON" | LPAREN -> "LPAREN" | RPAREN -> "RPAREN" | LBRACKETS -> "LBRACKETS" | RBRACKETS -> "RBRACKETS" | LBRACE -> "LBRACE" | RBRACE -> "RBRACE" | IDENT s -> Printf.sprintf "IDENT(%s)" s | INT i -> Printf.sprintf "INT(%d)" i | KEYWORD_IF -> "KEYWORD_IF" | EOF -> "EOF" }
步骤2:补全词法规则的EOF分支
在你现有的tokens规则最后新增EOF匹配分支,避免扫描到文件末尾时报错:
rule tokens = parse | ',' { COMMA } | ';' { SEMICOLON } | '(' { LPAREN } | ')' { RPAREN } | '[' { LBRACKETS } | ']' { RBRACKETS } | '{' { LBRACE } | '}' { RBRACE } (* 你自己写的其他规则,比如匹配标识符、数字的规则 *) | ['a'-'z' 'A'-'Z' '_'] ['a'-'z' 'A'-'Z' '0'-'9' '_']* as s { IDENT s } | ['0'-'9']+ as s { INT (int_of_string s) } (* 忽略空格、换行、制表符 *) | [' ' '\t' '\n'] { tokens lexbuf } (* 新增EOF匹配 *) | eof { EOF }
步骤3:(可选)新增测试用主函数
如果你需要直接运行lexer验证效果,可以在开头的{}代码区域新增递归扫描所有token的逻辑和主函数:
{ (* 前面的type token、show_token定义放这里 *) let rec scan_all lexbuf = match tokens lexbuf with | EOF -> print_endline "扫描完成,所有token已输出" | tk -> print_endline (show_token tk); scan_all lexbuf let () = let lexbuf = Lexing.from_channel stdin in scan_all lexbuf }
编译运行命令
- 生成OCaml源码:
ocamllex lexer.mll - 编译为可执行文件:
ocamlc -o lexer lexer.ml - 测试效果:
echo "(test_var, 123); { }" | ./lexer
你会得到对应的token序列输出。
内容的提问来源于stack exchange,提问作者Egydio Pacheco
相关产品推荐
相关产品推荐

