この記事は、パーサーを作成するための2つの類似ライブラリー、C ++用の
Boost SpiritとHaskell用の
Parsecの視覚的な比較を目的としています。 それから、記事を3つの部分に分ける方が良いと判断しました。 最初の部分では、iniファイルの内容を説明するためのコンテキストフリー文法の書き方を説明します。
iniファイル
ini拡張子を持つファイルは、Windowsの世界だけでなく、他のシステム(php.iniなど)でも広く配布されています。 iniファイルの形式は非常に単純です。ファイルはセクションに分割され、各セクションには「パラメーター=値」の形式の任意の数のレコードを含めることができます。 異なるセクションのパラメーターの名前は一致できます。
[_1]
1=1
2=2
[_2]
1=1
2=2
各パラメーターは、セクション名とパラメーター名でアドレス指定できます:
'_1'.'2'
。
Iniファイルはコメントを提供します-「;」で始まる行。
文法を構築する
このフォーマットを、
拡張バッカス-ナウア表記法の文脈自由文法として説明してみましょう(詳しくない人でも明確になることを願っています)。
iniファイルとは何かを説明しましょう。 これを行うために、最も複雑な(iniファイル自体)から最も単純な(識別子と呼ばれる)までのすべての構造を説明します。 このような各構造は、他の非終端記号と通常の記号(終端記号)によって定義される特別な指定(非終端記号)に関連付けられます。
引用符で囲みます。
- iniファイルデータ(inidata)には、いくつかのセクションが含まれています(中括弧は、任意の回数繰り返すことを意味します)。
inidata = {section} .
- セクションは、角かっこで囲まれたセクションの名前と、次の行からのいくつかのエントリ(パラメーター)で構成されます。
section = "[", ident, "]", "\n", {entry} .
- レコードは、パラメーター名、「=」記号、パラメーター値で構成され、行の終わりで終わります。
entry = ident, "=", value, "\n" .
- 識別子とは何かを定義してみましょう。文字、数字、記号で構成されるすべての「_。、:(){}-#@&* |」 (実際には、他の文字が発生する場合があります)。
ident = {letter | digit | "_" | "." | "," | ":" | "(" | ")" | "{" | "}" | "-" | "#" | "@" | "&" |"*" | "|"} .
この定義は完全に真実ではありません、なぜなら 識別子は少なくとも1文字で構成する必要があります。 このようにやり直しましょう:
ident = identChar, {identChar} .
identChar = letter | digit | "_" | "." | "," | ":" | "(" | ")" | "{" | "}" | "-" | "#" | "@" | "&" |"*" | "|" .
- 次に、値が何であるかを定義しましょう:行の終わりを除くすべて(簡潔にするために、表記法を拡張する必要がありました)
value = {not "\n"} .
一部のパーサー/ユーザーが余分なスペースと空の行を挿入することを好むことを考慮する必要があります。
これを行うには、さらに2つの非終端記号を導入する必要があります。文字列で使用される空白文字と、単なる空白文字です。
stringSpaces = {" " | "\t"} .
spaces = {" " | "\t" | "\n" | "\r"} .
スペースはほぼどこでも使用できます。 したがって、文法をわずかに修正します。
inidata = spaces, {section} .
section = "[", ident, "]", stringSpaces, "\n", {entry} .
entry = ident, stringSpaces, "=", stringSpaces, value, "\n", spaces .
ident = identChar, {identChar} .
identChar = letter | digit | "_" | "." | "," | ":" | "(" | ")" | "{" | "}" | "-" | "#" | "@" | "&" |"*" | "|" .
value = {not "\n"} .
stringSpaces = {" " | "\t"} .
spaces = {" " | "\t" | "\n" | "\r"} .
それは基本的に文法=)についてすべてです。
おそらく誰かが私がコメントについて何も言わなかったことに気づいたでしょう。 忘れませんでした-「ペン」で切り取るのが簡単です=)(演習として、文法を修正してコメントを考慮に入れることができます)。
重要:再帰を残さないように、私は少しcheし、文法を作成しました。 私が検討している両方のライブラリーは、左再帰に対して脆弱
な再帰的下降パーサーを構築します。 これらのライブラリを実際のプロジェクトで使用する前に、それが何であり、どのように対処するかを理解してください=)。
これで、この文法の使用を比較して、
C ++と
Haskellでパーサーを構築できます。
PS。 この記事を開発ブログに
投稿するアイデアをくれた
maxshopenに感謝します。