Bison与Flex集成时出现‘unknown type name ASTNode’错误求助
解决Bison/Flex项目中ASTNode类型未识别的编译错误
问题重现
编译时出现如下错误:
In file included from lexer.l:5:0: parser.y:39:5: error: unknown type name 'ASTNode' ASTNode *astNode; // Add ASTNode pointer for expression and other nodes
相关代码
parser.y
%{ #include <stdio.h> #include <stdlib.h> #include <string.h> extern FILE *yyin; extern FILE *yyout; void yyerror(const char *s); // Define NodeType enumeration for AST node types typedef enum { NODE_VAR, NODE_ICONST, NODE_ADD, NODE_SUB, NODE_MUL, NODE_DIV } NodeType; // Define the structure for AST nodes typedef struct ASTNode { NodeType type; union { char *sval; // for variables int ival; // for integer constants struct { struct ASTNode *left; struct ASTNode *right; } binary; // for binary operations } data; } ASTNode; // Function prototypes for creating AST nodes ASTNode* createVarNode(char *name); ASTNode* createIntNode(int value); ASTNode* createBinaryNode(NodeType type, ASTNode *left, ASTNode *right); void printAST(ASTNode *node); %} // Union for semantic values %union { int ival; char *sval; ASTNode *astNode; // Add ASTNode pointer for expression and other nodes } %token <sval> VAR %token <ival> ICONST %token EQUOP ADDOP SUBOP MULOP DIVOP LPAREN RPAREN %type <astNode> program expression expression_suffix term term_suffix factor %start program %% // Rules of the grammar program: VAR EQUOP expression { printf("Parsed program: %s = <expression>\n", $1); free($1); // Free the variable name after use $$ = $3; // Set the result of the program to the expression } ; expression: term expression_suffix { printf("Parsed expression\n"); } ; expression_suffix: ADDOP term expression_suffix { printf("Parsed ADDOP\n"); } | SUBOP term expression_suffix { printf("Parsed SUBOP\n"); } | /* empty */ { } ; term: factor term_suffix { $$ = $1; // Assign the factor to the term result printf("Parsed term\n"); } ; term_suffix: MULOP factor term_suffix { printf("Parsed MULOP\n"); } | DIVOP factor term_suffix { printf("Parsed DIVOP\n"); } | /* empty */ { } ; factor: LPAREN expression RPAREN { $$ = $2; // The result is the expression inside the parentheses printf("Parsed factor: (expression)\n"); printAST($$); // Print the AST for the expression inside the parentheses } | ICONST { $$ = createIntNode($1); // Create an integer node printf("Parsed ICONST: %d\n", $1); } | VAR { $$ = createVarNode($1); // Create a variable node printf("Parsed VAR: %s\n", $1); } ; %% void yyerror(const char *s) { fprintf(stderr, "Error: %s\n", s); } // Function definitions for AST creation and printing ASTNode* createVarNode(char *name) { ASTNode *node = malloc(sizeof(ASTNode)); node->type = NODE_VAR; node->data.sval = strdup(name); return node; } ASTNode* createIntNode(int value) { ASTNode *node = malloc(sizeof(ASTNode)); node->type = NODE_ICONST; node->data.ival = value; return node; } ASTNode* createBinaryNode(NodeType type, ASTNode *left, ASTNode *right) { ASTNode *node = malloc(sizeof(ASTNode)); node->type = type; node->data.binary.left = left; node->data.binary.right = right; return node; } void printAST(ASTNode *node) { if (!node) return; switch (node->type) { case NODE_VAR: printf("VAR(%s)\n", node->data.sval); break; case NODE_ICONST: printf("ICONST(%d)\n", node->data.ival); break; case NODE_ADD: printf("ADD\n"); printAST(node->data.binary.left); printAST(node->data.binary.right); break; case NODE_SUB: printf("SUB\n"); printAST(node->data.binary.left); printAST(node->data.binary.right); break; case NODE_MUL: printf("MUL\n"); printAST(node->data.binary.left); printAST(node->data.binary.right); break; case NODE_DIV: printf("DIV\n"); printAST(node->data.binary.left); printAST(node->data.binary.right); break; } } int main() { yyin = fopen("input.txt", "r"); if (!yyin) { perror("Failed to open input file"); return 1; } yyout = fopen("lexicalOutput.txt", "w"); if (!yyout) { perror("Failed to open output file"); fclose(yyin); return 1; } yyparse(); fclose(yyin); fclose(yyout); return 0; // Add return statement at the end }
lexer.l
%{ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "parser.tab.h" extern int yylex(); %} /* Lexical analyzer rules */ %% [ \t]+ ; /* Ignore whitespace */ [0-9]+ { yylval.ival = atoi(yytext); fprintf(yyout, "Read ICONST: %d\n", yylval.ival); return ICONST; } [a-zA-Z_][a-zA-Z0-9_]* { yylval.sval = strdup(yytext); fprintf(yyout, "Read VAR: %s\n", yylval.sval); return VAR; } "=" { fprintf(yyout, "Read =\n"); return EQUOP; } "+" { fprintf(yyout, "Read +\n"); return ADDOP; } "-" { fprintf(yyout, "Read -\n"); return SUBOP; } "*" { fprintf(yyout, "Read *\n"); return MULOP; } "/" { fprintf(yyout, "Read /\n"); return DIVOP; } "(" { fprintf(yyout, "Read (\n"); return LPAREN; } ")" { fprintf(yyout, "Read )\n"); return RPAREN; } . { /* Ignore unrecognized characters */ } %% int yywrap(void) { return 1; }
编译命令
$ bison -d parser.y $ flex lexer.l $ gcc -o myparser parser.tab.c lex.yy.c
错误原因
使用bison -d parser.y生成的parser.tab.h头文件,仅包含Bison自动生成的符号(如%union、%token、%type的声明),但你在parser.y的%{ ... %}块中定义的ASTNode结构体和NodeType枚举不会被写入该头文件。
而lexer.l包含了parser.tab.h,Flex生成的lex.yy.c中会使用yylval(属于%union类型),其中的astNode字段是ASTNode*类型,但此时ASTNode的定义并未在parser.tab.h中,导致编译时无法识别该类型。
解决方案
方案一:将AST类型定义移至独立头文件
- 创建
ast.h文件,写入AST相关的类型定义和函数原型:
#ifndef AST_H #define AST_H #include <stdio.h> #include <stdlib.h> #include <string.h> typedef enum { NODE_VAR, NODE_ICONST, NODE_ADD, NODE_SUB, NODE_MUL, NODE_DIV } NodeType; typedef struct ASTNode { NodeType type; union { char *sval; int ival; struct { struct ASTNode *left; struct ASTNode *right; } binary; } data; } ASTNode; ASTNode* createVarNode(char *name); ASTNode* createIntNode(int value); ASTNode* createBinaryNode(NodeType type, ASTNode *left, ASTNode *right); void printAST(ASTNode *node); #endif
- 修改
parser.y的%{ ... %}块,替换原有的AST定义为包含ast.h:
%{ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "ast.h" extern FILE *yyin; extern FILE *yyout; void yyerror(const char *s); %}
- 修改
lexer.l,在包含parser.tab.h前先包含ast.h:
%{ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "ast.h" #include "parser.tab.h" extern int yylex(); %}
- 重新执行编译命令即可。
方案二:使用Bison的%code requires块(推荐)
Bison的%code requires块中的代码会被自动包含到生成的parser.tab.h中,确保所有依赖该头文件的代码都能访问到AST类型定义:
- 修改
parser.y,将AST类型定义移至%code requires块,原%{ ... %}块保留其他内容:
%code requires { #include <stdio.h> #include <stdlib.h> #include <string.h> typedef enum { NODE_VAR, NODE_ICONST, NODE_ADD, NODE_SUB, NODE_MUL, NODE_DIV } NodeType; typedef struct ASTNode { NodeType type; union { char *sval; int ival; struct { struct ASTNode *left; struct ASTNode *right; } binary; } data; } ASTNode; ASTNode* createVarNode(char *name); ASTNode* createIntNode(int value); ASTNode* createBinaryNode(NodeType type, ASTNode *left, ASTNode *right); void printAST(ASTNode *node); } %{ extern FILE *yyin; extern FILE *yyout; void yyerror(const char *s); %}
lexer.l无需修改,直接重新执行编译命令即可。
内容的提问来源于stack exchange,提问作者JustAGirl
相关产品推荐
相关产品推荐

