在读了一个2年前的网页后,我想知道什么才是最适合词法解析需求的,与它们的OCamel对应物相比,fslex/fsyacc,bet,慢,愚蠢等等。
我以前在C#绑定中使用过F#,但目前我正在学习ANTLR,当我看到它附带了一个解析器生成器时,我很兴奋。由于F#现在是官方发布的,似乎是微软真正想要支持和开发的东西。你认为fslex和fsyacc对于生产代码来说是值得的吗?
发布于 2011-03-23 09:08:23
Fslex和fsyacc是由F#编译器使用的,所以它们可以正常工作。我几年前就用过了,它足够满足我的需求了。
然而,我的经验是,lex/yacc在F#中远不如在OCaml中成熟。OCaml社区中的许多人已经使用它们很多年了,包括许多学生(似乎用它们编写一个小的解释器/编译器是一种常见的练习)。我不认为很多F#开发人员使用过它们,我也不认为F#团队最近在这些工具上做了很多工作(例如,VS集成并不是优先考虑的)。如果您不是很迫切,那么Fslex和fsyacc可能就足够了。
一种解决方案可能是调整Menhir (一个具有几个很好的功能的camlyacc替代品),以便在F#中使用它。我不知道这会有多少工作量。
就我个人而言,我现在每次需要编写解析器时都会使用FParsec。它的使用有很大的不同,但它也更灵活,而且它可以生成良好的解析错误消息。我对它非常满意,当我有问题时,它的作者总是非常帮助我。
发布于 2011-03-23 01:06:41
Fslex和fsyacc肯定已经可以投入生产使用了。毕竟,在Microsoft Visual Studio2010中使用了它们,因为F#词法分析器和解析器就是使用它们编写的( F# compiler source code也是一个很好的例子,演示了如何有效地使用它们)。
我不确定fslex/fsyacc与它们的OCaml等价物或ANTLR相比如何。然而,Frederik有一篇文章将ANTLR与用F# used in IronJS编写的手写解析器进行了比较。不幸的是,他没有fslex/fsyacc版本,所以没有直接的比较。
为了回答一些特定的问题-您可以在构建中获得运行fslex/fsyacc的MSBUILD任务,因此它可以很好地集成。你不会得到语法突出显示,但我认为这没什么大不了的。它可能比OCaml版本慢,但只有当你改变解析器时才会影响编译-我对F#解析器做了一些修改,没有发现编译时间有问题。
发布于 2013-10-05 10:48:26
fslex和fsyacc工具是专门为F#编译器编写的,并不打算广泛使用。也就是说,多亏了这些工具,我成功地将重要的代码库从OCaml移植到了F#,但由于F#端完全缺乏VS集成,这很费力(OCaml与语法突出显示、跳转到定义和错误回溯有很好的集成)。特别是,我将尽可能多的F#代码移出词法分析器和解析器。
我们经常需要编写解析器,并要求微软添加对fslex和fsyacc的官方支持,但我不相信这会发生。
我的建议是,只有当您面临使用ocamllex和ocamlyacc转换大型遗留OCaml代码库时,才使用fslex和fsyacc。否则,从头开始编写一个解析器。
我个人不是解析器组合器库的粉丝,我更喜欢使用活动模式编写解析器,看起来像这样的s-expression解析器:
let alpha = set['A'..'Z'] + set['a'..'z']
let numeric = set['0'..'9']
let alphanumeric = alpha + numeric
let (|Empty|Next|) (s: string, i) =
if i < s.Length then Next(s.[i], (s, i+1)) else Empty
let (|Char|_|) alphabet = function
| Empty -> None
| s, i when Set.contains s.[i] alphabet -> Some(s, i+1)
| _ -> None
let rec (|Chars|) alphabet = function
| Char alphabet (Chars alphabet it)
| it -> it
let sub (s: string, i0) (_, i1) =
s.Substring(i0, i1-i0)
let rec (|SExpr|_|) = function
| Next ((' ' | '\n' | '\t'), SExpr(f, it)) -> Some(f, it)
| Char alpha (Chars alphanumeric it1) as it0 -> Some(box(sub it0 it1), it1)
| Next ('(', SExprs(fs, Next(')', it))) -> Some(fs, it)
| _ -> None
and (|SExprs|) = function
| SExpr(f, SExprs(fs, it)) -> box(f, fs), it
| it -> null, it这种方法不需要任何VS集成,因为它只是普通的F#代码。我发现它很容易阅读和维护。在我的生产代码中,性能已经足够了。
https://stackoverflow.com/questions/5393901
复制相似问题