必ずしもすべてが同じタイプであるとは限らない要素の集まりと考えてください。次のコードがあります。
// The struct I'll use inside Bison to dynamically create collections:
typedef struct ListElementType {
union value {
int intVal;
float floatVal;
char* charptrVal;
} value;
struct ListElementType* next;
} ListElementType;
次に、バイソンには次のものがあります。
%union
{
int int_type;
char char_type;
float float_type;
char* charptr_type;
ListElementType* listElementType;
}
//----------------------------------------------------
%token <charptr_type> STRING
%token <int_type> INTEGER
%token <float_type> REAL
%type<listElementType> ElementList
//----------------------------------------------------
//----------------------------------------------------
ElementList
: ElementList ',' LiteralType
{
$$ = malloc(sizeof(listElementType));
$$->next = $1;
$$->value = $3;
}
| LiteralType
{
$$ = malloc(sizeof(listElementType));
$$->next = 0;
$$->value = $1;
}
;
//----------------------------------------------------
LiteralType
: STRING
| INTEGER
| REAL
;
ここにはいくつかの問題があります。しかし、最初に、この Bison のようなパーサーを生成しようとすると、再帰生成の $3 と base /terminal ケースの $1 に宣言された型がないことがわかります。私が見ているように、実際には型が宣言されています。それらは LiteralType であり、文字列、int、または float のいずれかであり、最後のターミナル プロダクションを空白のままにして自動的に設定する必要があります (最初に行ったのは、グローバル ユニオンから適切なものを選択して型を明示したことを前提としています)。 .
第二に、宣言された型がないと Bison が文句を言うとは思いませんが、むしろ衝突やあいまいさがあります。メンバーはそれぞれの作品に配属されました)。この状況では、ListElementType 構造体の値メンバーを共用体にしました。構造体の最初のメンバーが構造体アドレス自体の「ラベル」の場所にあるという事実に加えて、ユニオンのメンバーもすべてユニオンのメモリアドレスから開始して、タイプ。(void )$$ = $2の行に沿った何か、たまたま $2 が何であれ。
SO、コードを次のように変更しました。
//----------------------------------------------------
ElementList
: ElementList ',' LiteralType
{
$$ = malloc(sizeof(listElementType));
$$->next = $1;
*$$ = (void*)$3;
}
| LiteralType
{
$$ = malloc(sizeof(listElementType));
$$->next = 0;
$$->value = $1;
}
;
//----------------------------------------------------
LiteralType
: STRING
{
$<charptr_type>$ = $1;
}
| INTEGER
{
$<int_type>$ = $1;
}
| REAL
{
$<float_type>$ = $1;
}
;
これで、INT、REAL、STRING のケースの共用体を明示的に設定しました。必要ないと思ったのですが、間違っていたら誰かが訂正してください。そして、型のない共用体の代入も試しましたが、それでも同じエラー: $3 と $1 には宣言された型がありません。
だから私の考え、質問:
StringList、IntList、および RealList プロダクションを個別に作成する必要があります。唯一の変更点は、右側の非終端要素がリスト内の特定のタイプの要素をそのまま示していることです。
//----------------------------------------------------
ElementList
: IntElementList
| RealElementList
;
IntElementList
: IntElementList ',' INTEGER
{
$$ = malloc(sizeof(listElementType));
$$->next = $1;
$$->intVal = $3;
}
| INTEGER
{
$$ = malloc(sizeof(listElementType));
$$->next = 0;
$$->intVal = $1;
}
RealElementList
: RealElementList ',' REAL
{
$$ = malloc(sizeof(listElementType));
$$->next = $1;
$$->floatVal = $3;
}
| REAL
{
$$ = malloc(sizeof(listElementType));
$$->next = 0;
$$->floatVal = $1;
}
;
または、LiteralType が 3 つの値のいずれかを持つことができると述べてから、型のない共用体の割り当てを試してプルする方法はありますか?
それとも、アプローチ全体が間違っていて、より良い方法がありますか?