You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

修复方案及修改后代码

关键问题点

  1. 头文件包含错误:Yacc文件不应包含lex.yy.c,Lex文件应包含Bison生成的正确头文件(expressions.tab.h而非grammer.tab.h)。
  2. 令牌名称不统一:Yacc中定义的id令牌与Lex中返回的ID不匹配,需统一为ID。
  3. 语义动作中成员访问错误:
    • 已绑定类型的符号直接使用$n访问成员,无需额外加.lexeme或.exp(如$1而非$1.lexeme,$3.addr而非$3.exp.addr)。
    • 非终结符S类型为<code>,直接赋值$$ = code即可,无需.code。
  4. Lex文件中定义段位置错误:%union和%token应放在%{ ... %}与%%之间,且无需重复定义%union(Bison生成的头文件已包含)。
  5. 空字符串赋值问题:$$.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 07:12:04