在bison/yacc语义操作中构建异构数据类型数组(或集合)的最佳方法
可以将其视为一组元素,这些元素不一定都是同一类型的。我有以下代码:在bison/yacc语义操作中构建异构数据类型数组(或集合)的最佳方法,c,bison,yacc,C,Bison,Yacc,可以将其视为一组元素,这些元素不一定都是同一类型的。我有以下代码: // The struct I'll use inside Bison to dynamically create collections: typedef struct ListElementType { union value { int intVal; float floatVal; char* charptrVal; } value; struct
// 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
;
或者有没有一种方法可以声明LiteralType可以有三个值中的任意一个,然后尝试提取无类型联合赋值
或者整个方法都错了,还有更好的方法吗?我认为您忽略了一个事实,即Bison没有尝试实现完整的C类型检查。因为您为STRING和LiteralType指定了不同的类型名称,所以它的任务是报告它的默认操作($$=$1)从(bison)类型检查的角度来看做了一些奇怪的事情。如果您确实想使用默认赋值,只需给它们相同的类型(在您的情况下为值) 此外,您编码的并集值是并集值的两倍,这似乎不是必需的:
%code requires
{
typedef struct ListElementType {
union value {
int intVal;
float floatVal;
char* charptrVal;
} value;
struct ListElementType* next;
} ListElementType;
}
%union
{
union value value;
ListElementType* list;
};
%token <value> STRING INTEGER REAL
%type <value> LiteralType
%type <list> ElementList
%%
ElementList
: ElementList ',' LiteralType
{
$$ = malloc(sizeof($$));
$$->next = $1;
$$->value = $3;
}
| LiteralType
{
$$ = malloc(sizeof($$));
$$->next = 0;
$$->value = $1;
}
;
//----------------------------------------------------
LiteralType
: STRING
| INTEGER
| REAL
;
%代码需要
{
类型定义结构ListElementType{
联合价值{
int intVal;
浮球浮球;
char*charptrVal;
}价值观;
结构ListElementType*下一步;
}李斯特类型;
}
%联合
{
联合价值;
ListElementType*列表;
};
%令牌字符串整数实数
%类型文字类型
%类型元素列表
%%
元素列表
:ElementList','LiteralType
{
$$=malloc(sizeof($);
$$->next=$1;
$$->value=$3;
}
|文字类型
{
$$=malloc(sizeof($);
$$->next=0;
$$->value=$1;
}
;
//----------------------------------------------------
文字类型
:字符串
|整数
|真实的
;
我最终选择了这种方法
%code requires {
typedef struct Element {
union {
int intVal;
float floatVal;
char* charptrVal;
};
char type;
} ElementType;
typedef struct ListType {
void* element;
struct ListType* next;
} ListType;
}
%union
{
int int_type;
char char_type;
float float_type;
char* charptr_type;
ListType* ListType;
ElementType* ElementType;
}
%token <charptr_type> KEYWORD
%token <charptr_type> ID
%token <charptr_type> STRING
%token <int_type> INTEGER
%token <float_type> REAL
%token END 0
%type<ElementType> Element
%type<ListType> ElementList
//----------------------------------------------------
ElementList
: Element ',' ElementList
{
$$ = malloc(sizeof(ListType));
$$->element = (void*)$1;
$$->next = $3;
}
| Element
{
$$ = malloc(sizeof(ListType));
$$->element = (void*)$1;
$$->next = NULL;
}
;
//----------------------------------------------------
Element
: STRING
{
char* aString = malloc(sizeof(char)*strlen($1)+1);
strcpy(aString, $1);
free(yylval.charptr_type);
$$ = malloc(sizeof(ElementType));
$$->charptrVal = aString;
$$->type = 's';
}
| INTEGER
{
$$ = malloc(sizeof(ElementType));
$$->intVal = $1;
$$->type = 'i';
}
| REAL
{
$$ = malloc(sizeof(ElementType));
$$->floatVal = $1;
$$->type = 'f';
}
;
%代码需要{
类型定义结构元素{
联合{
int intVal;
浮球浮球;
char*charptrVal;
};
煤焦类型;
}元素类型;
类型定义结构列表类型{
void*元素;
结构ListType*next;
}列表类型;
}
%联合
{
int_型;
字符型;
浮球型;
char*charptr_类型;
ListType*ListType;
ElementType*ElementType;
}
%令牌关键字
%令牌ID
%令牌串
%令牌整数
%象征性真实
%令牌端0
%类型元素
%类型元素列表
//----------------------------------------------------
元素列表
:元素“,”元素列表
{
$$=malloc(sizeof(ListType));
$$->element=(void*)$1;
$$->next=$3;
}
|元素
{
$$=malloc(sizeof(ListType));
$$->element=(void*)$1;
$$->next=NULL;
}
;
//----------------------------------------------------
元素
:字符串
{
char*aString=malloc(sizeof(char)*strlen($1)+1);
strcpy(阿斯汀,1美元);
免费(yylval.charptr_型);
$$=malloc(sizeof(ElementType));
$$->charptrVal=aString;
$$->type='s';
}
|整数
{
$$=malloc(sizeof(ElementType));
$$->intVal=$1;
$$->type='i';
}
|真实的
{
$$=malloc(sizeof(ElementType));
$$->floatVal=$1;
$$->type='f';
}
;
通常,您要做的是在异构列表类型中有一个类型标记:
typedef enum ListElementType { INTEGER, REAL, STRING } ListElementType
typedef struct ListElement {
ListElementType type;
union {
int intVal;
float floatVal;
char* charptrVal;
} value;
struct ListElement* next;
} ListElement;
然后,无论何时创建ListElement,都可以适当地设置类型
字段。稍后,您可以检查类型
字段以查看它是什么
您的野牛代码将变为:
%union
{
int int_type;
char char_type;
float float_type;
char* charptr_type;
ListElement* listElement;
struct { ListElement *head, *tail } list;
}
//----------------------------------------------------
%token <charptr_type> STRING
%token <int_type> INTEGER
%token <float_type> REAL
%type<list> ElementList
%type<listElement> LiteralType
//----------------------------------------------------
%%
//----------------------------------------------------
ElementList
: ElementList ',' LiteralType
{ $$.head = $1.head;
$$.tail = $1.tail->next = $3; }
| LiteralType
{ $$.head = $$.tail = $1; }
;
//----------------------------------------------------
LiteralType
: STRING { ($$ = NewListElement(STRING))->value.charptrVal = $1; }
| INTEGER { ($$ = NewListElement(INTEGER))->value.intVal = $1; }
| REAL { ($$ = NewListElement(REAL))->value.floatVal = $1; }
;
%%
ListElement *NewListElement(ListElementType type) {
ListElement *rv = malloc(sizeof(ListElement));
rv->type = type;
rv->next = 0;
return rv; }
%union
{
int_型;
字符型;
浮球型;
char*charptr_类型;
ListElement*ListElement;
结构{ListElement*head,*tail}列表;
}
//----------------------------------------------------
%令牌串
%令牌整数
%象征性真实
%类型元素列表
%类型文字类型
//----------------------------------------------------
%%
//----------------------------------------------------
元素列表
:ElementList','LiteralType
{$$.head=$1.head;
$$.tail=$1.tail->next=$3;}
|文字类型
{$$.head=$$.tail=$1;}
;
//----------------------------------------------------
文字类型
:STRING{($=NewListElement(STRING))->value.charptrVal=$1;}
|整数{($=NewListElement(整数))->value.intVal=$1;}
|REAL{($=NewListElement(REAL))->value.floatVal=$1;}
;
%%
ListElement*NewListElement(ListElementType类型){
ListElement*rv=malloc(sizeof(ListElement));
rv->type=type;
rv->next=0;
返回rv;}
我明白你的意思,但如果我举你的例子,Bison仍然会为LiteralType默认赋值提供类型冲突:!=!=!=!=此外,即使我将自己$$.intVal=$1;,等等添加到文字的每个动作中,Bison也不再抱怨,但现在gcc抱怨ListermentType是未知类型否,它不会报告冲突。您可能已经删除了我指定的%type LiteralType
,并且您还保留了所有更改的%token
。因此,实际上,除了我回答的内容之外,您可能会得到不同的结果:)1-我的版本(2.6)仍然需要我在LiteralType产品中显式地完成赋值。没有它们,它就无法完成赋值并报告冲突。2-添加此项实际上解决了问题。3-ListermentType未知类型是由于bison 2.3(当我切换到2.6时,它消失了)4-我看不出我在哪里对联合进行了两次编码。5-为什么你要声明STRING、REAL和INTEGER与LiteralType属于同一类型,而它们不是。这3个是标记/终端。它们不是非终端,并且具有特定的类型。6-t
typedef enum ListElementType { INTEGER, REAL, STRING } ListElementType
typedef struct ListElement {
ListElementType type;
union {
int intVal;
float floatVal;
char* charptrVal;
} value;
struct ListElement* next;
} ListElement;
%union
{
int int_type;
char char_type;
float float_type;
char* charptr_type;
ListElement* listElement;
struct { ListElement *head, *tail } list;
}
//----------------------------------------------------
%token <charptr_type> STRING
%token <int_type> INTEGER
%token <float_type> REAL
%type<list> ElementList
%type<listElement> LiteralType
//----------------------------------------------------
%%
//----------------------------------------------------
ElementList
: ElementList ',' LiteralType
{ $$.head = $1.head;
$$.tail = $1.tail->next = $3; }
| LiteralType
{ $$.head = $$.tail = $1; }
;
//----------------------------------------------------
LiteralType
: STRING { ($$ = NewListElement(STRING))->value.charptrVal = $1; }
| INTEGER { ($$ = NewListElement(INTEGER))->value.intVal = $1; }
| REAL { ($$ = NewListElement(REAL))->value.floatVal = $1; }
;
%%
ListElement *NewListElement(ListElementType type) {
ListElement *rv = malloc(sizeof(ListElement));
rv->type = type;
rv->next = 0;
return rv; }