คิดว่ามันเป็นการรวบรวมองค์ประกอบที่ไม่จำเป็นต้องเป็นประเภทเดียวกันทั้งหมดมากกว่า ฉันมีรหัสต่อไปนี้:
// 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;
จากนั้นใน Bison ฉันมี:
%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
;
มีบางสิ่ง / ปัญหาที่นี่ แต่ก่อนอื่น พยายามสร้าง parser เช่น Bison นี้บอกว่า $3 ในการผลิตแบบเรียกซ้ำและ $1 ในกรณีฐาน /terminal ไม่มีประเภทที่ประกาศ เท่าที่ฉันเห็น จริงๆ แล้วพวกเขาได้ประกาศประเภทไว้แล้ว เป็น LiteralType และด้วยเหตุนี้ อาจเป็นสตริงหรือ ints หรือ floats ซึ่งควรตั้งค่าโดยอัตโนมัติโดยปล่อยเทอร์มินัลสุดท้ายให้ว่างไว้ (เนื่องจากสิ่งแรกที่ฉันทำคือทำให้ประเภทชัดเจนโดยเลือกสิ่งที่เหมาะสมจากสหภาพสากล) .
ประการที่สอง ฉันไม่คาดหวังว่า Bison จะบ่นว่าไม่มีประเภทที่ประกาศไว้ แต่มีข้อขัดแย้งหรือความคลุมเครือเนื่องจากฉันกำหนดให้กับ $$->value แต่ $2,$1 สามารถมีค่าใดก็ได้จากสามค่าที่เป็นไปได้ (ขึ้นอยู่กับว่าสหภาพใด สมาชิกได้รับมอบหมายให้ทำหน้าที่ในการผลิตตามลำดับ) สำหรับสถานการณ์นี้ ฉันกำหนดให้สมาชิกค่าใน ListElementType struct เป็นสหภาพ ฉันคิดว่าแทนที่จะพยายามใช้ประโยชน์จากความจริงที่ว่าสมาชิกคนแรกของ struct จะอยู่ในตำแหน่ง "ป้ายกำกับ" ของที่อยู่ struct เองบวกกับที่สมาชิกของสหภาพแรงงานทั้งหมดเริ่มต้นจากที่อยู่ mem ของสหภาพด้วยเพื่อลองและมอบหมายโดยตรงโดยไม่คำนึงถึง พิมพ์. บางสิ่งที่อยู่ในบรรทัดของ (void)$$ = $2 ไม่ว่า $2 จะเป็นเช่นไรก็ตาม
ดังนั้นฉันจึงเปลี่ยนเป็นรหัสเป็น:
//----------------------------------------------------
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 แยกกันโดยที่สิ่งเดียวที่เปลี่ยนแปลงคือ nonterminal ทางด้านขวามือนั้นตรงกับประเภทองค์ประกอบเฉพาะในรายการ เช่น:
//----------------------------------------------------
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 สามารถมีค่าใด ๆ จากสามค่าจากนั้นลองดึงการกำหนดสหภาพแบบไม่มีประเภท
หรือวิธีการทั้งหมดผิดและมีวิธีที่ดีกว่า?