F#fslex fsyacc是否适合生产代码?

Jep*_*eps 9 f# fsyacc maturity fslex

在阅读了一个2年历史的网页后,真的扯掉fslex/fsyacc,越野车,慢,愚蠢等等与他们的OCamel同行相比,我想知道什么是最好的选择lexing解析需求?

我之前使用过ANTLR和C#绑定,但我目前正在学习F#,当我看到它带有解析器生成器时很兴奋.由于F#现在正式发布,似乎微软真的希望支持和​​发展.你会说fslex和fsyacc对于生产代码是否值得?

Tom*_*cek 10

Fslex和fsyacc当然可以用于生产.毕竟,它们在Microsoft Visual Studio 2010中使用,因为F#lexer和解析器是使用它们编写的(F#编译器源代码也是演示如何有效使用它们的一个很好的示例).

我不确定fslex/fsyacc与他们的OCaml等价物或ANTLR相比如何.但是,Frederik Holmstrom有一篇文章将ANTLR与用IronJS中使用的 F#编写的手写解析器进行了比较.不幸的是,他没有fslex/fsyacc版本,所以没有直接比较.

要回答一些特定问题 - 您可以获得运行fslex/fsyacc的MSBUILD任务作为构建的一部分,因此它可以很好地集成.你没有得到语法高亮,但我不认为这是一个大问题.它可能比OCaml版本慢,但只有在更改解析器时才会影响编译 - 我对F#解析器进行了一些修改,但没有发现编译时间有问题.


Lau*_*ent 10

F#编译器使用Fslex和fsyacc,因此它们很有用.几年前我用过它们,它足以满足我的需求.

但是,我的经验是,在F#中,lex/yacc比在OCaml中成熟得多.OCaml社区中的许多人已经使用它们多年,包括许多学生(似乎用它们编写一个小的解释器/编译器是一种常见的练习).我不认为很多F#开发人员使用它们,我认为F#团队最近没有对这些工具做过大量工作(例如,VS集成并不是优先考虑的事项).如果你不是很紧急,Fslex和fsyacc对你来说已经足够了.

一个解决方案可能是使Menhir(具有几个不错的功能的camlyacc替换)与F#一起使用.我不知道会有多少工作.

就个人而言,我现在每次需要编写解析器时都使用FParsec.它使用起来完全不同,但它也更加灵活,它可以生成良好的解析错误消息.我对此非常满意,当我遇到问题时,它的作者一直非常乐于助人.


Jon*_*rop 5

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
Run Code Online (Sandbox Code Playgroud)

这种方法不需要任何VS集成,因为它只是vanilla F#代码.我发现它易于阅读和维护.在我的生产代码中,性能已经足够了.