-1

フレックスとバイソンを使用してパーサーを作成しようとしていますが、それがどのように機能するかについて混乱しています。次のようにフォーマットされたテキストファイルを取得しようとしています。

Version Header Version 1.00 <--- File always starts with a header
Key                     : Value <--- Each section includes these but these after the version header are in the "Root" section
==Section Name <--- A section
$Key                    : Value <--- These are properties
Key                     : Value <--- Same thing as in the "Root" section

サンプルフォーマット:

NasuTek Licensing Version 1.00
Vendor                  : NASUTEKENTERPRISES
Notice                  : NasuTek Enterprises
License Group           : NasuTek Asheila
License Name            : NasuTek Asheila
Vendor Notice           : NasuTek Asheila Internal Build License
Serial                  : ASHEL-87267-4987-3737-37821:32742
Start Date              : Wed July 04 00:00:00 2012
End Date                : Sat July 20 00:00:00 2013
Trial                   : Yes
Count                   : 0
Components              : EXPORT
Host                    : Any

==Software Configuration
$Signed Section         : Yes
Export Configuration    : {
    Supports Export to XML        : Yes
    Supports Export to Text       : Yes
}

==Signature
vpUsQJ+Qo4OS+RQg0vuLW0mXjAj/o6v[trunicated]

グループ化で混乱しているので、どうすればこれを達成できますか。キーペアを十分に単純なものとして見ることができますが、==と{}ペアを使用して分割を処理する方法がわかりませんか?

4

2 に答える 2

3

さて、flex/bison ベースのパーサーをどのように設計するかを決定しようとするときはいつでも、最初の質問は flex で何をすべきか、bison で何をすべきかということです。

Flex は任意の正規表現を使用でき、状態を使用して異なるコンテキストで異なる RE を許可することもできますが、一般的には孤立したものしか認識できません。フレックスでは再帰は難しい/不可能です

一方、Bison は再帰を簡単に処理し、さまざまなコンテキストでトークンを非常に簡単に関連付けることができますが、ルールは単純なトークンのシーケンスであり、正規表現はなく、限定された (1 トークン) ルックアッドです。

したがって、あなたの場合、認識が難しいものに目を向ける必要があります。最初に出てくるのは:、この文字を使用して、キーを値から分離し、値内で使用することです。キー内に表示できますか? そうでない場合は、おそらく行の最初:の行を特別に処理したいだけです (フレックスでは開始状態ですぐに実行できます。バイソンでは、コロンを含むことができるすべての値を記述する必要があるため、少し難しくなります)。

次に「認識するのが難しい」のはスペーシングです。キーと値内にスペースがあり、おそらく無視されるべき他のスペースもあります。これらはフレックスで簡単に管理できます。ただし、入力ファイルに表示される可能性のあるコメントは一切記述しません。コメントがある場合は、通常、flex でそれらを認識 (および無視) し、無視されたスペースのように扱います。

最後に、ファイルに表示される可能性のある他のすべての文字がありますが、例では説明されていません。これらには、他のすべての句読点文字が含まれます。キーまたは値内で有効かどうか。$andは、行の==先頭にのみ現れると説明されています -- それらが他の場所にある場合 (行頭の空白の後、またはキーまたは値の中/後)

漠然とした不完全な例でこのようなものを与えられたとき、私の傾向は、他のものは違法であり、何がうまくいかないかについて適切なエラーメッセージを与えるべきだと言うことです. したがって、次のようなフレックススキャナーになります。

{KVchar}    [-A-Za-z0-9.+/]      /* legal characters in a key or value */
{WS}        [ \t\r]              /* whitespace -- ignored but allowed in a key or value */

%s COLON                         /* seen a colon on the current line */
%%

":"        { BEGIN(COLON); return ':'; }
\n         { BEGIN(INITIAL); return '\n'; }
<INITIAL>({KVchar}+({WS}+{KVchar}+)*)           {
             yylval.key = strdup(yytext);
             return KEY; }
<COLON>({KVchar}+((:|{WS})+{KVchar}+)*)           {
             /* values may contain colons, but can't start or end with them */
             yylval.key = strdup(yytext);
             return VALUE; }
[${}]      { return *yytext; }
"=="       { return EQEQ; }
{WS}+      ; /* ignore */
.          { fprintf(stderr, "Spurious character '%c' in input\n"); }

bison ファイルは次のようになります。

%union {
    char *key; /* or value */
}
%token<key>  KEY VALUE
%token       EQEQ
%%

input: header kvpairs sections ;

header: KEY
;

kvpairs: kvpairs kvpair
       | /* empty */
;

kvpair: key ':' value '\n'
      | '\n'
;

key: KEY
   | '$' KEY
;

value: VALUE
     | '{' '\n' kvpairs '}' '\n'
;

sections: sections section | /*empty*/ ;

section: EQEQ KEY '\n' kvpairs ;
于 2012-07-15T20:25:48.903 に答える
1

さて、あなたの文法はそれほど単純ではありません。\n==しかし、私が行ったことは、セクション開始記号(私が呼んだ)として扱うためにレクサーでトークンを定義することでしたEQEQ。したがって、文法規則は次のようになります。

section_line:
      EQEQ section_name NEWLINE
    ;

そして、トークン化ルールは次のようになりました。

"\n=="           { BEGIN(SEC); return EQEQ; }

Signature単語がの直後にある場合はキーワードのように扱うことができるように開始条件をEQEQ使用し、署名セクションが署名データを単一のテキストblobとして取り込むように別の開始条件を使用しました。

<SEC>"Signature" { BEGIN(SIG); return SIGNATURE; }
<SIG>{text}      { return (BEGIN(INITIAL), TEXT); }

グループ化ルールは、単一のルールで定義するのが最も簡単です。これは、プロパティのキーと値のペアに使用した文法です。

section_property:
      key COLON value NEWLINE
    | key COLON value_block NEWLINE
    ;

そして、これは私が定義するために使用したルールですvalue_block

value_block:
      LBRACE NEWLINE sub_properties RBRACE
    ;

そして、asub_propertyはのように見えますsection_property

新しいセクションが検出されるたびに、解析コードは後続の値のペアが属するセクションを記憶している必要があります。同様に、サブプロパティブロックを解析するときは、サブプロパティを適切に割り当てることができるように、囲んでいるプロパティキーを保存する必要があります。

パーサーのようにあなたをつまずかせる可能性のあるものの1つyaccは、ボトムアップの性質です。ルールのリーフ要素が認識されたら、リーフルールに値を保存し、囲んでいるルールで、保存された値を参照します。たとえば、次のルールは次のとおりです。

words:
      WORD { words_add($1); free($1); }
    | WORD { words_add($1); free($1); } words
    ;

連続する単語を単語シーケンスを表す保存バッファに保存します。次に、囲みルールで、その保存バッファーが再度保存されます。

key:
      words { words_save_as_key(); }
    ;

基本words_save_as_key的に、保存された単語のバッファを複製してから、保存される別のシーケンス(おそらく、関連付けられた値を表すシーケンス)のためにそのバッファをリセットします。

于 2012-07-15T17:09:21.140 に答える