F# 对fslex和fsyacc的编程访问

F# 对fslex和fsyacc的编程访问,f#,F#,fslex和fsyacc工具目前需要两个阶段的编译,生成文件,然后由fsc编译。在我看来,如果源文件是嵌入式资源,以编程方式提供给fslex和fsyacc,并使用CodeDom动态编译生成的代码,那么这些工具将更易于使用 这可行吗?如果可行,实现这一点需要什么?应该可以提供一个类似解析器组合器的接口,其后端使用表达式树(F#的LISP“eval”)或类似的东西,以便与语言完全集成。或者是一个类型提供者。有很多选择。如果表生成是一项昂贵的计算,则可以通过提供缓存来缓存它,例如磁盘缓存 我认为,除了

fslex和fsyacc工具目前需要两个阶段的编译,生成文件,然后由fsc编译。在我看来,如果源文件是嵌入式资源,以编程方式提供给fslex和fsyacc,并使用CodeDom动态编译生成的代码,那么这些工具将更易于使用


这可行吗?如果可行,实现这一点需要什么?

应该可以提供一个类似解析器组合器的接口,其后端使用表达式树(F#的LISP“eval”)或类似的东西,以便与语言完全集成。或者是一个类型提供者。有很多选择。如果表生成是一项昂贵的计算,则可以通过提供
缓存来缓存它,例如磁盘缓存


我认为,除了缺乏时间、奉献精神和专业知识之外,没有什么能阻止我们使用具有(非一元的)解析器组合器接口的工具,而这种接口是高效的编译实现

有时我会回到我的这个宠物项目,使用代数方法来优化源代码中使用组合器指定的正则表达式(和lexer),然后编译到状态机。它仍然缺乏一些提高效率的关键要素,但它有:


乔恩,这是一个很好的问题;事实上,我的设计目标之一(新的F#lexer和parser生成器实现)是使它们可嵌入,特别是支持这样的场景

到目前为止,我还没有实现(还没有)可以让你在fsharplex中轻松实现的功能,但不要让它阻止你;我写过fsharplex(以及fsharp工具中的其他工具),或多或少都是纯函数式的,所以全局状态或类似的东西不应该有任何问题。破解编译器代码应该相对简单,这样您就可以使用一些组合器构建一个regex-AST,运行编译器以获得一个已编译的DFA,然后将状态机的IL发送到一个动态程序集中(然后可以“烘焙”并执行)

fsharpyacc目前使用的方法是,我将大部分编译逻辑放入纯函数库Graham;这里的想法是语法分析/操作和解析器DFA编译算法应该是通用的、可重用的、易于测试的,因此任何想用F#构建语言工具的人都将有一个通用的框架来构建它们。同样,对Graham的贡献/改进可以很容易地流回到fsharpyacc。最后,我将修改fsharplex以使用相同的方法,这将允许您通过引用NuGet包(您只需要编写代码以从DFA生成IL)将regex编译器嵌入到您自己的代码中

fsharplex和fsharpyacc使用MEF允许插入各种后端;目前,出于兼容性原因,他们只针对
fslex
fsyacc
,但我希望实现基于代码的后端(与当前基于表的后端相反),以在将来获得更好的性能

更新——我刚刚重新阅读了您的问题,注意到您希望嵌入
*.fsl
*.fsy
文件本身,并在运行时调用相应的编译器。您可以通过编译工具并从自己的项目中引用程序集来实现这一点。IIRC,我在两个编译器中都公开了一个入口点,这样就可以从外部代码调用它们;主要入口点(例如,当您从控制台调用工具时执行的内容)只需解析命令行参数,然后将它们传递到此“外部”入口点


但是,直接嵌入
*.fsl
*.fsy
文件有一个问题;如果您嵌入它们,然后在运行时通过fsharplex和fsharpyacc运行它们,您的用户定义操作(例如,当lexer或解析器规则匹配时执行的代码)仍将被指定为F#源代码——您需要决定如何将它们编译成可执行代码。

我的
fslex
的新实现,
fsharplex
也是基于*正则表达式派生,重新检查`。如果您想看一看,这里有代码:“类似解析器组合器的接口”。这正是我不想要的。我想要相同的易于使用的DSL,但需要运行时编译,而不是两阶段构建。@JonHarrop在运行时编译相同的DSL听起来毫无意义。您是否在购买更好的构建工具?@toyvo“在运行时编译相同的DSL听起来毫无意义。您是否在购买更好的构建工具?”。我不认为我有选择另一个构建工具的奢侈,但为什么要在你可以集成这些工具的情况下使构建复杂化呢?@JonHarrop抱歉,我一定是误解了你的想法。再读一遍,这种IDE集成是否更好,使用fslex/yacc的点击/操作是否更少?这可能会有所帮助,但这并不需要嵌入资源或在运行时运行该工具。一个类型提供者也许能做到这一点吗?