通过单独创建.mly和.mll来检索解析的一部分

时间:2014-01-31 21:15:51

标签: parsing ocaml lexical-analysis ocamllex ocamlyacc

我正在编写一个前端来解析一组txt个文件,每个文件包含一组procedures,例如一个txt文件如下:

Sub procedure1
...
End Sub

Sub procedure2
...
End Sub

...

syntax.ml包含:

type ev = procedure_declaration list
type procedure_declaration = 
  { procedure_name : string; procedure_body : procedure_body }
type procedure_body = ...
...

parser.mly看起来像:

%start main
%type <Syntax.ev> main
%%
main: procedure_declarations EOF { List.rev $1 }

procedure_declarations:
  /* empty */ { [] }
| procedure_declarations procedure_declaration { $2 :: $1 }

procedure_declaration:
SUB name = procedure_name EOS
body = procedure_body
END SUB EOS
{ { procedure_name = name; procedure_body = body } }
...

现在,我想检索procedure_declaration的解析(出于异常处理的目的)。这意味着,我想创建parser_pd.mlylexer_pd.mll,并让parser.mly调用parser_pd.main。因此,parser_pd.mly看起来像:

%start main
%type <Syntax.procedure_declaration> main
%%
main: procedure_declaration EOF { $1 };
...

由于之前parser.mly中的大部分内容都应移至parser_pd.mlyparser.mly现在应该比之前更轻松,看起来像:

%start main
%type <Syntax.ev> main
%%
main: procedure_declarations EOF { List.rev $1 }

procedure_declarations:
  /* empty */ { [] }
| procedure_declarations procedure_declaration { $2 :: $1 }

procedure_declaration:
SUB name = procedure_name EOS
??????
END SUB EOS
{ { procedure_name = name; 
    procedure_body = Parser_pd.main (Lexer_pd.token ??????) } }

问题是我不知道如何编写??????部分和lexer.mll应该是轻量级的(因为它只读取令牌ENDSUBEOS,并允许lexer_pd.mll处理的内容。也许需要Lexing模块中的一些函数?

希望我的问题很清楚......有人可以帮忙吗?

1 个答案:

答案 0 :(得分:0)

你写的是你要检索procedure_declaration的解析, 但是在你的代码中,你只想检索一个procedure_body,所以我就是 假设这就是你想要的。

用我自己的话说,你想要不用编写语法 告诉嵌入语法嵌入了哪种语法。问题(没有 在你的情况下的问题,因为你幸运地有一个非常友好的语法) 这是在LALR(1)中,您需要一个前瞻标记来决定 要采取哪种规则。你的语法是这样的:

procedure_declaration:
  SUB procedure_name EOS
  procedure_body
  END SUB EOS

您可以将procedure_name和procedure_body组合在一起,这样您的规则就可以了 语义动作将如下所示:

procedure_declaration:
  SUB combined = procedure_name EOS /* nothing here */ EOS
  { { procedure_name = fst combined; procedure_body = snd combined; } }

procedure_name:
  id = IDENT {
    let lexbuf = _menhir_env._menhir_lexbuf in
    (id, Parser_pd.main Lexer_pd.token lexbuf)
  }

Parser_pd将包含此规则:

main: procedure_body END SUB { $1 }

你很可能在Parser_pd中想要END SUB,因为procedure_body是 可能不会自我划分。

请注意,在解析第一个EOS之前调用子解析器 过程名称标识符,因为这是你的前瞻。如果你打电话 EOS中,为时已晚,解析器将从中提取令牌 身体,已经。第二个EOS是END SUB之后的那个。

_menhir_env显然是一种只适用于menhir的黑客攻击。 您可能需要另一个hack来使menhir --infer工作(如果您使用它), 因为不希望用户引用它,所以符号不会 在适用范围。那个黑客将是:

%{
  type menhir_env_hack = { _menhir_lexbuf : Lexing.lexbuf }
  let _menhir_env = { _menhir_lexbuf = Lexing.from_function
    (* Make sure this lexbuf is never actually used. *)
    (fun _ _ -> assert false) }
%}