Anggap saja ini lebih merupakan kumpulan elemen yang belum tentu semuanya memiliki tipe yang sama. Saya memiliki kode berikut:
// 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;
Lalu di Bison saya punya:
%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
;
Ada beberapa hal/masalah di sini. Namun pertama-tama, mencoba membuat parser seperti ini Bison mengatakan bahwa $3 dalam produksi rekursif dan $1 dalam kasus dasar /terminal tidak memiliki tipe yang dideklarasikan. Menurut saya, mereka sebenarnya memiliki tipe yang dideklarasikan. Mereka adalah LiteralType dan dengan demikian, dapat berupa string atau int atau float, yang harus diatur secara otomatis dengan membiarkan produksi terminal terakhir kosong (mengingat hal pertama yang saya lakukan adalah membuat tipenya eksplisit dengan memilih yang sesuai dari gabungan global) .
Kedua, saya tidak berharap Bison mengeluh bahwa tidak ada tipe yang dideklarasikan melainkan ada bentrokan atau ambiguitas karena saya menugaskannya ke $$->value tetapi $2,$1 dapat memiliki salah satu dari tiga nilai yang mungkin (tergantung pada gabungan mana anggota ditugaskan dalam produksi masing-masing). Untuk situasi ini saya membuat anggota nilai dalam struct ListElementType menjadi gabungan. Saya berpikir alih-alih mencoba mengambil keuntungan dari fakta bahwa anggota pertama suatu struct akan berada di lokasi "label" dari alamat struct itu sendiri ditambah bahwa semua anggota serikat pekerja juga memulai pada alamat mem serikat untuk mencoba dan langsung menetapkan terlepas dari jenis. Sesuatu seperti (void)$$ = $2, apa pun $2 yang terjadi.
JADI, saya mengubah kode menjadi:
//----------------------------------------------------
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;
}
;
Sekarang saya telah secara eksplisit mengatur gabungan untuk kasus INT, REAL,STRING. Yang saya pikir tidak perlu, tetapi seseorang mengoreksi saya jika saya salah. DAN, saya juga mencoba penugasan gabungan tanpa tipe tetapi kesalahannya masih sama: $3 dan $1 tidak memiliki tipe yang dideklarasikan.
Jadi pendapat saya, pertanyaan:
Haruskah saya membuat produksi StringList, IntList, dan RealList terpisah di mana satu-satunya hal yang berubah adalah nonterminal sisi kanan langsung merupakan tipe elemen tertentu dalam daftar, seperti:
//----------------------------------------------------
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;
}
;
Atau adakah cara untuk menyatakan bahwa LiteralType dapat memiliki salah satu dari tiga nilai dan kemudian mencoba dan menarik tugas gabungan tanpa tipe?
Atau apakah keseluruhan pendekatannya salah dan ada cara yang lebih baik?