1

我正在编写一个前端来解析一组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.mlyand lexer_pd.mll,并让parser.mlycall parser_pd.main。因此,parser_pd.mly看起来像:

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

由于之前的大部分内容parser.mly都应该移到parser_pd.mly中,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
??????
END SUB EOS
{ { procedure_name = name; 
    procedure_body = Parser_pd.main (Lexer_pd.token ??????) } }

问题是我不知道如何编写该??????部分,lexer.mll哪个应该很轻(因为它只读取 token和END,并让内容由 处理)。也许一些功能来自SUBEOSlexer_pd.mllLexing需要模块中的一些功能?

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

4

1 回答 1

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。您可能需要另一个 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) }
%}
于 2014-02-04T03:37:33.683 回答