2

これは複数の部分からなる質問です。まず、私の入力ファイルは次のようになります。

category Shoes brand:char[50],cost:int
category Shirts brand:char[20],cost:int

私の質問は次のとおりです。

:a。)カテゴリ名の後でのみ行を分割するにはどうすればよいですか?ShoesまたはShirtsこれらの場合。

char[30]b。)各行の情報を保持する構造体 の変数(例)を決定するように、Bisonパーサーをどのように記述しますか?

これらの質問があまりにもローカライズされているように思われる場合は、同じことを行うのに役立ついくつかのリソースに案内されれば幸いです。

4

3 に答える 3

5

欠落している詳細が多すぎます。たとえば、「int」をカテゴリ名として使用できますか? 解析したデータをどのように保存する予定ですか?

それでも、パーサーの最初のスケッチは次のようになります。

%token CATEGORY "category"
       EQ       "="
       COLON    ":"
       COMMA    ","
       LBRA     "["
       RBRA     "]"
       INT      "int"
       CHAR     "char"
       ID
       NATURAL
;
%%    
categories:
  category
| categories category
;

category:
  "category" ID fields
;

fields:
  field
| fields "," field
;

field:
  ID ":" type
;

type:
  "char"
| "int"
| type "[" NATURAL "]"
;

そしてこれはスキャナー用です:

%%
"category"   return CATEGORY;
"="          return EQ;
":"          return COLON;
","          return COMMA;
"["          return LBRA;
"]"          return RBRA;
"int"        return INT;
"char"       return CHAR;
[a-zA-Z]+    return ID;
[0-9]+       return NATURAL;
[ \n\t]+     continue;
于 2013-03-18T12:56:30.857 に答える
2

(b.) あなたの質問を正しく理解しているかどうか確信が持てません。入力ファイルの各エントリを解析し、その情報を構造体に格納するとします。カテゴリとブランドは文字列になり、コストは整数になります。文字列の長さを事前に知りたいので、解析された値を保持する変数を割り当てることができます (char[20] など)。

C++ 文字列を使用しないのはなぜですか? その後、 length を宣言する必要はありません。例はこちら。C を使用する必要がある場合は、char * を使用して、malloc を使用してヒープに文字列を割り当てることができます。

于 2013-03-18T08:36:30.663 に答える
0

このページには、何をしようとしているのかのガイドとなる合理的で単純な例があります。flex/bison パーサーを作成するための完全な一般的な手順は次のとおりです。

  1. トークンが何であるかを決定し、正規表現を書き、それぞれの識別子を選択します (@akim が flex/bison コードで行ったように)。
  2. 解析しようとしている「法的」入力の LALR(1) Context Free Grammar を記述します。@akim は、これについてあなたに有利な立場を与えてくれました。
  3. パーサーの結果を保持するターゲット データ構造を設計します。これはあなたの投稿に欠けている重要なことです。単一の整数サイズを計算しようとしているだけなら、それで完了です。さらに処理するために詳細を渡す必要がある場合は、何らかのレコード/列挙/リスト構造が必要になります。これは通常、抽象構文ツリーまたは AST と呼ばれますが、実際にはツリーではないことがよくあります。
  4. などのコンストラクター関数を含む AST (必要な場合) データ構造を実装しますCATEGORY_NODE make_category(enum category_e cat);。これらのコンストラクターは、パーサーによって呼び出されます。
  5. アクション コードなしでフレックス スキャナー プログラム ファイルにトークンを実装します。
  6. アクション コードなしで Bison パーサー プログラム ファイルに CFG を実装します。
  7. テスト フレームとテスト スイートを構築し、スキャナーとパーサーが正当な入力を読み取り、不正な入力を拒否することをテストします。これまでのところ、プログラムは他に何もしていません。これが @akim のコードの現在の場所です。
  8. 各トークンに関連付ける必要があるデータがある場合は、そのデータを決定します。たとえば、符号なし数値の値は、スキャナから として返される大きさになりますunsigned int。識別子の値は文字列になります。しかし、ブラケット[にはまったく価値がありません。%unionこれらの型を使用して、スキャナーから値を受け入れるbison ディレクティブを作成します。これらを<union_field>タグとしてそれぞれの%tokenディレクティブに追加します。そこで使用されている の例を参照してください@union。これには 2 つのトークン値の型があります。
  9. 先頭に を追加し、それぞれのトークンの正しいトークン値を返すアクション コードを追加して、flexスキャナーを修正します。#include "foo.tab.h"この時点で、すべてがコンパイルされて再び実行されるはずですが、それでも何もしません。もう一度例を参照してください。
  10. 次に、パーサーでデータ処理を実装します。ドル$n$$ディレクティブを使用し、<union_field>型タグを文法の非終端記号に追加して、文法規則間でデータを移動し、最後に AST 構造のコンストラクターを呼び出して、入力が読み取られるときに構造を構築します (または整数の場合はインクリメントします)。それがすべてです)。これには、LALR パーサーの経験と深い知識が役立ちます。Bisonドキュメントの後半の例は、この部分の別のリファレンスです。障害にぶつかった場合は、具体的な質問をして戻ってきてください。
  11. テストを再度実行し、結果の AST を検証可能な形式で出力します。XML はこれに適しています。

これまでのところ、この完全に一般的なアプローチはやり過ぎであることに誰かが気付くと思います。それは場合によって異なります。現在の入力は非常に単純なので、flex や bison をまったく使用せずに、ちょっとしたアドホックパーサーをより迅速に手書きできるでしょう。

ただし、作成しているプログラムがしばらく使用され、時間の経過とともに変更される可能性が高い場合は、最初に汎用パーサーのすべての機構を用意しておくと、作業がはるかに簡単になります。プログラム入力を単なる生データではなく、実際の言語として考えると、他の方法では思いもよらなかった機能を作成できるようになります。

于 2013-03-24T17:21:38.023 に答える