Ocaml 基于语境的标记意义
我有一个奇怪的字符串语法,其中 分隔符取决于上下文。在下面的示例中 输入: 结果是两个字符串的列表Ocaml 基于语境的标记意义,ocaml,ocamllex,Ocaml,Ocamllex,我有一个奇怪的字符串语法,其中 分隔符取决于上下文。在下面的示例中 输入: 结果是两个字符串的列表[“foo”;“bar”]。 外圆括号对进入列表模式。 然后,下一对括号分隔字符串。 在字符串中,要使用平衡的括号对 作为字符串的一部分处理 现在lexer决定返回什么取决于 在全局变量内部上 { open Sample_parser exception Error of string let inside = ref false (* <= to be eliminated *)
[“foo”;“bar”]
。
外圆括号对进入列表模式。
然后,下一对括号分隔字符串。
在字符串中,要使用平衡的括号对
作为字符串的一部分处理
现在lexer决定返回什么取决于
在全局变量内部
上
{
open Sample_parser
exception Error of string
let inside = ref false (* <= to be eliminated *)
}
*样本_scanner.mly*:
%token <string> String
%token Enter
%token Leave
%start <string list> process
%%
process:
| Enter lst = string_list Leave { lst }
string_list:
| elm = element lst = string_list { elm :: lst }
| elm = element { [elm] }
element:
| str = String { str }
您可以将状态作为参数传递给
tokenize
。它仍然必须是可变的,但不能是全局的
rule tokenize inside = parse
| ws { tokenize inside lexbuf }
| lpar { if not !inside then begin
inside := true;
Enter
end else begin
let buf = Buffer.create 20 in
String (string_scanner
(Lexing.lexeme_start lexbuf)
0
buf
lexbuf)
end }
| rpar { inside := false; Leave }
规则标记化内部=解析
|ws{tokenize inside lexbuf}
|lpar{如果不是!在内部,则开始
内:=真;
进入
结束,否则开始
设buf=Buffer.create 20英寸
字符串(字符串)扫描仪
(Lexing.lexeme\u start lexbuf)
0
缓冲器
莱克斯巴夫)
结束}
|rpar{inside:=false;Leave}
您可以按如下方式调用解析器:
Sample_parser.process (Sample_lexer.tokenize (ref false)) buf
Sample_parser.process(Sample_lexer.tokenize(ref false))buf
这确实是一个很好的例子,回答了这个问题。但是有没有办法完全摆脱指针呢?
open Batteries
let sample_input = "( (foo (bar) baz) (xyzzy) )"
(* EibssssssssssssseibssssseiL
* where E := enter inner
* L := leave inner
* i := ignore (whitespace)
* b := begin string
* e := end string
* s := part of string
*
* desired result: [ "foo (bar) baz"; "xyzzy" ] (type string list)
*)
let main () =
let buf = Lexing.from_string sample_input in
try
List.print
String.print stdout
(Sample_parser.process Sample_lexer.tokenize buf);
print_string "\n";
with
| Sample_lexer.Error msg -> Printf.eprintf "%s%!" msg
| Sample_parser.Error -> Printf.eprintf
"Invalid syntax at pos %d.\n%!"
(Lexing.lexeme_start buf)
let _ = main ()
rule tokenize inside = parse
| ws { tokenize inside lexbuf }
| lpar { if not !inside then begin
inside := true;
Enter
end else begin
let buf = Buffer.create 20 in
String (string_scanner
(Lexing.lexeme_start lexbuf)
0
buf
lexbuf)
end }
| rpar { inside := false; Leave }
Sample_parser.process (Sample_lexer.tokenize (ref false)) buf