fslex および fsyacc ツールは、F# コンパイラ用に特別に作成されたものであり、より広く使用することを意図したものではありませんでした。そうは言っても、これらのツールのおかげで、OCaml から F# に重要なコード ベースを移植することができましたが、F# 側での VS 統合が完全に欠如していたため、骨の折れるものでした (OCaml には、構文の強調表示、定義へのジャンプ、およびエラーとの優れた統合があります)。スローバック)。特に、レクサーとパーサーからできるだけ多くの F# コードを移動しました。
私たちはしばしばパーサーを書く必要があり、Microsoft に fslex と fsyacc の公式サポートを追加するように依頼しましたが、これが実現するとは思いません。
私のアドバイスは、ocamllex と ocamllyacc を使用する大規模なレガシー OCaml コード ベースの翻訳に直面している場合にのみ、fslex と fsyacc を使用することです。それ以外の場合は、パーサーをゼロから作成します。
私は個人的にパーサー コンビネーター ライブラリのファンではなく、次の s 式パーサーのようなアクティブ パターンを使用してパーサーを作成することを好みます。
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
このアプローチは単なるバニラ F# コードであるため、VS 統合は必要ありません。読みやすく、保守しやすいと思います。私の製品コードでは、パフォーマンスは十分以上でした。