Flex&Bison编译报错:非结构体/联合体成员请求问题求助
Flex/Bison编译错误:结构/union成员访问失败
问题概述
我使用Flex处理tokens.l、Bison处理expressions.y,执行编译命令后出现大量编译错误,核心错误为error: request for member 'code' in something not a structure or union,尽管已在%union中定义相关成员,问题仍未解决,需协助修复。
原始代码
expressions.y
// expressions.y代码 %{ #include<stdio.h> #include<stdlib.h> #include<string.h> #include "../lex/lex.yy.c" int yylex(); void yyerror(const char *s); int i=0; %} %union { char *lexeme; char *value; char *code; char *addr; struct { char *code; char *addr; } exp; }; %left '+' '-' %token <lexeme> id %token <value> LITERAL %type <code> S %type <exp> E %% S : id '=' E { char *code = (char *)malloc(sizeof(char) * 100); // Adjust size accordingly sprintf(code, "%s=%s", $1.lexeme, $3.exp.addr); $$.code = code; } E : E '+' E { char *temp = (char *)malloc(sizeof(char) * 10); // Adjust size accordingly sprintf(temp, "t%d", i++); $$.exp.addr = temp; char *code = (char *)malloc(sizeof(char) * 100); // Adjust size accordingly sprintf(code, "%s=%s+%s", $$.exp.addr, $1.exp.addr, $3.exp.addr); $$.exp.code = code; } | '-' E { char *temp = (char *)malloc(sizeof(char) * 10); // Adjust size accordingly sprintf(temp, "t%d", i++); $$.exp.addr = temp; char *code = (char *)malloc(sizeof(char) * 100); // Adjust size accordingly sprintf(code, "%s=-%s", $$.exp.addr, $2.exp.addr); $$.exp.code = code; } | '(' E ')' { $$.exp.addr = $2.exp.addr; $$.exp.code = $2.exp.code; } | id { $$.exp.addr = $1.lexeme; $$.exp.code = ""; }; %% void yyerror(const char *s) { fprintf(stderr, "Parser error: %s\n", s); } int main() { yyparse(); // Start parsing return 0; }
tokens.l
// tokens.l代码 %{ #include<stdio.h> #include<stdlib.h> #include<string.h> #include "../yacc/grammer.tab.h"; typedef struct SymbolTable{ char token[10]; char attr[100]; char type[10]; } SymbolTable; SymbolTable ST[1000]; int STn=0; void printST(){ int i; printf("\nPrinting Symbol Table "); for(i=0;i<STn;i++){ printf("\n%s : %s",ST[i].token, ST[i].attr); } } int installID(char *a, char *t){ int i; for(i=0;i<STn;i++){ if((strcmp(ST[i].token, "ID")==0)&&(strcmp(ST[i].attr, a)==0)){ return i; } } strcpy(ST[STn].token,"ID"); strcpy(ST[STn].attr,a); strcpy(ST[STn].type,t); STn++; return STn-1; } int installLit(char *b, char *t){ int i; for(i=0;i<STn;i++){ if((strcmp(ST[i].token, "NUM")==0)&&(strcmp(ST[i].attr, b)==0)){ return i; } } strcpy(ST[STn].token,"LITERAL"); strcpy(ST[STn].attr,b); strcpy(ST[STn].type,t); STn++; return STn-1; } %} id [a-zA-Z_][a-zA-Z_0-9]* int [-]?[0-9]+ float [-]?[0-9]+([.][0-9]+)?([Ee][+-]?[0-9]+)? bool "True" | "False" str ("([^"\\]|\\.)*")|('([^'\\]|\\.)*') %% %union { char *lexeme; char *value; } %token <lexeme> ID {id} { printf("\nIdentifier : %s ", yytext); int a = installID(yytext, NULL); yylval.lexeme = strdup(yytext); return ID; } {int} {printf("\nInteger : %s ",yytext); int a = installLit(yytext,"INT"); yylval.value = strdup(yytext); return LITERAL;} {str} {printf("String "); int a = installLit(yytext,"STR"); yylval.value = strdup(yytext); return LITERAL;} {float} {printf("Float "); int a = installLit(yytext,"FLOAT"); yylval.value = strdup(yytext); return LITERAL;} %% int yywrap(){ return 1; }
编译命令
flex tokens.l bison expressions.y gcc expressions.tab.c ../lex/lex.yy.c -o myprg && myprg
核心错误
error: request for member 'code' in something not a structure or union error: request for member 'exp' in something not a structure or union
修复方案及修改后代码
关键问题点
- 头文件包含错误:Yacc文件不应包含
lex.yy.c,Lex文件应包含Bison生成的正确头文件(expressions.tab.h而非grammer.tab.h)。 - 令牌名称不统一:Yacc中定义的
id令牌与Lex中返回的ID不匹配,需统一为ID。 - 语义动作中成员访问错误:
- 已绑定类型的符号直接使用
$n访问成员,无需额外加.lexeme或.exp(如$1而非$1.lexeme,$3.addr而非$3.exp.addr)。 - 非终结符
S类型为<code>,直接赋值$$ = code即可,无需.code。
- 已绑定类型的符号直接使用
- Lex文件中定义段位置错误:
%union和%token应放在%{ ... %}与%%之间,且无需重复定义%union(Bison生成的头文件已包含)。 - 空字符串赋值问题:
$$.code = ""应改为$$.code = strdup(""),避免只读内存赋值问题。
修改后的expressions.y
%{ #include<stdio.h> #include<stdlib.h> #include<string.h> // 只声明yylex,不包含lex.yy.c int yylex(); void yyerror(const char *s); int i=0; %} %union { char *lexeme; char *value; char *code; char *addr; struct { char *code; char *addr; } exp; }; %left '+' '-' // 统一令牌名称为ID %token <lexeme> ID %token <value> LITERAL %type <code> S %type <exp> E %% S : ID '=' E { char *code = (char *)malloc(sizeof(char) * 100); sprintf(code, "%s=%s", $1, $3.addr); // S类型是code,直接赋值$$ $$ = code; // 打印生成的代码 printf("\n生成代码:%s\n", $$); } E : E '+' E { char *temp = (char *)malloc(sizeof(char) * 10); sprintf(temp, "t%d", i++); $$.addr = temp; char *code = (char *)malloc(sizeof(char) * 100); sprintf(code, "%s=%s+%s", $$.addr, $1.addr, $3.addr); $$.code = code; printf("%s\n", code); } | '-' E { char *temp = (char *)malloc(sizeof(char) * 10); sprintf(temp, "t%d", i++); $$.addr = temp; char *code = (char *)malloc(sizeof(char) * 100); sprintf(code, "%s=-%s", $$.addr, $2.addr); $$.code = code; printf("%s\n", code); } | '(' E ')' { $$.addr = $2.addr; $$.code = $2.code; } | ID { $$.addr = $1; // 使用strdup避免只读内存问题 $$.code = strdup(""); }; %% void yyerror(const char *s) { fprintf(stderr, "Parser error: %s\n", s); } int main() { yyparse(); return 0; }
修改后的tokens.l
%{ #include<stdio.h> #include<stdlib.h> #include<string.h> // 包含Bison生成的正确头文件 #include "../yacc/expressions.tab.h" typedef struct SymbolTable{ char token[10]; char attr[100]; char type[10]; } SymbolTable; SymbolTable ST[1000]; int STn=0; void printST(){ int i; printf("\nPrinting Symbol Table "); for(i=0;i<STn;i++){ printf("\n%s : %s",ST[i].token, ST[i].attr); } } int installID(char *a, char *t){ int i; for(i=0;i<STn;i++){ if((strcmp(ST[i].token, "ID")==0)&&(strcmp(ST[i].attr, a)==0)){ return i; } } strcpy(ST[STn].token,"ID"); strcpy(ST[STn].attr,a); strcpy(ST[STn].type,t); STn++; return STn-1; } int installLit(char *b, char *t){ int i; for(i=0;i<STn;i++){ if((strcmp(ST[i].token, "NUM")==0)&&(strcmp(ST[i].attr, b)==0)){ return i; } } strcpy(ST[STn].token,"LITERAL"); strcpy(ST[STn].attr,b); strcpy(ST[STn].type,t); STn++; return STn-1; } %} id [a-zA-Z_][a-zA-Z_0-9]* int [-]?[0-9]+ float [-]?[0-9]+([.][0-9]+)?([Ee][+-]?[0-9]+)? bool "True" | "False" str ("([^"\\]|\\.)*")|('([^'\\]|\\.)*') %% {id} { printf("\nIdentifier : %s ", yytext); int a = installID(yytext, NULL); yylval.lexeme = strdup(yytext); return ID; } {int} { printf("\nInteger : %s ",yytext); int a = installLit(yytext,"INT"); yylval.value = strdup(yytext); return LITERAL; } {str} { printf("\nString : %s ",yytext); int a = installLit(yytext,"STR"); yylval.value = strdup(yytext); return LITERAL; } {float} { printf("\nFloat : %s ",yytext); int a = installLit(yytext,"FLOAT"); yylval.value = strdup(yytext); return LITERAL; } // 忽略空白符 [ \t\n]+ ; %% int yywrap(){ return 1; }
修正后的编译命令
假设文件目录结构为:
project/ ├─ lex/ │ └─ tokens.l └─ yacc/ └─ expressions.y
执行命令:
cd lex flex tokens.l cd ../yacc bison -d expressions.y # 加上-d生成头文件 gcc expressions.tab.c ../lex/lex.yy.c -o myprg ./myprg
测试输入如x = a + -(b),会生成对应的中间代码并打印符号表。
内容的提问来源于stack exchange,提问作者Hello World
相关产品推荐
相关产品推荐

