fslex 和 fsyacc 工具目前需要 2 阶段编译,生成文件,然后由 fsc 编译。在我看来,如果源文件是嵌入式资源,以编程方式提供给 fslex 和 fsyacc 并使用 CodeDom 即时编译生成的代码,那么这些工具会更容易使用。
这是否可行,如果可行,实施该方案需要什么?
fslex 和 fsyacc 工具目前需要 2 阶段编译,生成文件,然后由 fsc 编译。在我看来,如果源文件是嵌入式资源,以编程方式提供给 fslex 和 fsyacc 并使用 CodeDom 即时编译生成的代码,那么这些工具会更容易使用。
这是否可行,如果可行,实施该方案需要什么?
乔恩,这是一个很好的问题;事实上,我对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
文件并在运行时调用相应的编译器。您可以通过编译工具并从您自己的项目中引用程序集来完成此操作。IIRC,我在两个编译器中都公开了一个入口点,以便可以从外部代码调用它们;主要入口点(例如,当您从控制台调用工具时执行的操作)只需解析命令行参数,然后将它们传递到这个“外部”入口点。
*.fsl
但是,直接嵌入and*.fsy
文件存在一个问题;如果您嵌入它们,然后在运行时通过fsharplex和fsharpyacc运行它们,您的用户定义操作(例如,匹配词法分析器或解析器规则时执行的代码)仍将被指定为 F# 源代码——您将需要决定如何将它们编译成可执行代码。
为使用表达式树(F# 的 LISP“eval”)或类似的东西的后端提供一个类似于解析器组合器的接口应该是可行的,以便与语言完全集成。或者一个 TypeProvider。有很多选择。如果表生成是一项昂贵的计算,则可以通过提供一个来缓存它Cache
,例如磁盘缓存。
我认为除了缺乏时间、奉献精神和专业知识之外,没有什么能阻止我们拥有具有(非单子)解析器组合器类接口的工具,但有效的编译实现。
有时我会回到我的这个宠物项目,使用代数方法来优化使用组合器在源代码中指定的正则表达式(和词法分析器),然后编译到状态机。它仍然缺少一些提高效率的关键部分,但它是: