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