阅读了一篇两年前的网页,对fslex/fsyacc进行了批评,称其有缺陷、速度慢、愚蠢等等,与OCamel相比。我想知道在词法和语法分析方面什么是最好的选择?
我以前用过ANTLR,并使用C#绑定,但现在正在学习F#,当我看到它带有一个解析器生成器时感到兴奋。由于F#现在正式发布,并且似乎是微软真正想要支持和开发的东西。您认为fslex和fsyacc是否值得用于生产代码吗?
阅读了一篇两年前的网页,对fslex/fsyacc进行了批评,称其有缺陷、速度慢、愚蠢等等,与OCamel相比。我想知道在词法和语法分析方面什么是最好的选择?
我以前用过ANTLR,并使用C#绑定,但现在正在学习F#,当我看到它带有一个解析器生成器时感到兴奋。由于F#现在正式发布,并且似乎是微软真正想要支持和开发的东西。您认为fslex和fsyacc是否值得用于生产代码吗?
Fslex和fsyacc被F#编译器使用,因此它们在某种程度上可用。我几年前使用过它们,在我的需求方面表现良好。
然而,我的经验是,在F#中,lex/yacc比OCaml不成熟得多。许多OCaml社区的人多年来一直在使用它们,包括许多学生(似乎使用它们编写小型解释器/编译器是一项常见练习)。我认为很少有F#开发人员使用它们,也不认为F#团队最近在这些工具上做了很多工作(例如,VS集成不是重点)。如果您不是非常苛求,Fslex和fsyacc可能就足够了。
一个解决方案可以是将Menhir(camlyacc替代品,具有几个不错的功能)适应于F#的使用。我不知道这需要多少工作。
个人而言,每当我需要编写解析器时,我现在都使用FParsec。它的使用方式非常不同,但也更加灵活,并且生成良好的解析错误消息。我一直对它感到非常满意,其作者在我有问题时总是非常乐于助人。
Fslex和fsyacc已经可以投入生产使用。毕竟,它们被用于Microsoft Visual Studio 2010中,因为F#词法分析器和解析器是使用它们编写的(F#编译器源代码也是一个很好的示例,展示了如何有效地使用它们)。
我不确定fslex/fsyacc与它们的OCaml等效物或ANTLR相比如何。然而,Frederik Holmstrom有一篇文章将ANTLR与用F#手写的解析器在IronJS中使用进行了比较。不幸的是,他没有fslex/fsyacc版本,因此没有直接比较。
回答一些具体问题-您可以获取MSBUILD任务以便在构建过程中运行fslex/fsyacc,因此它集成得非常好。您不会获得语法高亮,但我认为这并不是什么大问题。它可能比OCaml版本慢,但这只影响您更改解析器时的编译-我对F#解析器进行了一些修改,并没有发现编译时间是个问题。
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#代码。我发现它易于阅读和可维护性。在我的生产代码中,性能已经超过了足够的水平。