Fslex和Fsyacc的编程访问

5

目前,fslex和fsyacc工具需要两阶段编译,生成文件然后由fsc编译。如果将源文件作为嵌入资源传递给fslex和fsyacc,在程序中动态生成代码并使用CodeDom即时编译,我认为这些工具会更易于使用。

这种方法可行吗?如果是,实现这一点需要什么条件?

2个回答

4
Jon,这是一个很好的问题;实际上,我对于 F# 的设计目标之一是使其可嵌入,特别是为了实现这种情况。这里指的是 fsharp-tools(F# 的新词法分析器和解析器生成器实现)。
目前为止,在 fsharplex 中我还没有实现让你轻松做到这一点的功能,但是不要被吓到;我使用了几乎纯函数式的方式来编写 fsharplex(以及 fsharp-tools 中的其他工具),因此不应该存在全局状态或类似的问题。通过使用一些组合子构建正则表达式 AST 并运行编译器以获取已编译的 DFA,然后将状态机的 IL 发射到动态程序集中(然后可以“烘焙”并执行),应该相对容易地修改编译器代码。
目前 fsharpyacc 使用的方法是将大部分编译逻辑放入了一个纯函数库 Graham 中。其思想是语法分析/操作和解析器 DFA 编译算法应该是通用的、可重用的和易于测试的,因此任何想要使用 F# 构建语言工具的人都将有一个共同的框架来构建它们。同样,对 Graham 的贡献/改进可以很容易地流回到 fsharpyacc 中。最终,我将修改 fsharplex 以使用相同的方法,这将允许你通过引用 NuGet 包来嵌入正则表达式编译器在你自己的代码中(你只需要编写从 DFA 生成 IL 的代码)。
fsharplex 和 fsharpyacc 使用 MEF 允许插入各种后端;目前,它们只针对 fslex 和 fsyacc 进行兼容性测试,但我希望实现基于代码的后端(而不是当前基于表的后端),以在未来获得更好的性能。
更新--我刚刚重新阅读了您的问题,并注意到您想要嵌入 *.fsl 和 *.fsy 文件本身并在运行时调用相应的编译器。您可以通过编译工具并从自己的项目中引用程序集来实现这一点。如果我没记错的话,我在两个编译器中都公开了一个入口点,以便可以从外部代码调用它们;主入口点(例如,当您从控制台调用工具时执行的内容)仅解析命令行参数,然后将其传递到此“外部”入口点。

然而,直接嵌入*.fsl*.fsy文件存在一个问题;如果你将它们嵌入到程序中,在运行时通过fsharplexfsharpyacc运行,用户定义的操作(例如,当词法分析器或解析器规则匹配时执行的代码)仍然是以F#源代码指定的 - 你需要决定如何将其编译成可执行代码。


2
可以通过使用表达式树(F#的LISP“eval”)或类似的东西实现解析组合器式的接口,以完全集成到语言中。或者使用TypeProvider等其他选项。如果表生成是昂贵的计算,则可以通过提供缓存(例如磁盘缓存)来缓存它。
我认为除了时间、专注和专业知识之外,没有什么可以阻止我们拥有具有(非单子)解析组合器式接口的工具,同时具有高效的编译实现。
有时我会回到我的这个宠物项目,尝试用代数方法优化源代码中使用组合器指定的正则表达式(和词法分析器),然后编译成状态机。它仍然缺少一些关键的部分以实现高效,但它就在这里:https://github.com/toyvo/ocaml-regex-algebraic

1
我的新实现fslexfsharplex也基于“正则表达式导出,重新审视”。如果您想要查看代码,请访问此链接:https://github.com/jack-pappas/fsharp-tools - Jack P.
"类似解析器组合器的接口"。那正是我*不想要的。我希望使用相同易于使用的DSL,但是采用运行时编译而不是2阶段构建。 - J D
@JonHarrop 在运行时编译相同的DSL似乎完全没有意义。也许你正在寻找更好的构建工具? - t0yv0
@toyvo "在运行时编译相同的DSL听起来完全没有意义。也许您正在寻找更好的构建工具?" 我认为我没有选择另一个构建工具的奢侈,但为什么要复杂化构建,当您可以将工具集成在一起呢? - J D
@JonHarrop 抱歉,我可能只是误解了您的想法。再次阅读,这是更好的IDE集成,使用fslex/yacc需要更少的点击/操作吗?那会有所帮助 - 但这不一定涉及嵌入式资源或在运行时运行工具。也许可以用TypeProvider来实现它? - t0yv0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接