Error: request for member " " in something not a structure or union (Yacc)
Error: request for member " " in something not a structure or union (Yacc)
我正在尝试制作一个 c-minus 编译器,但我必须制作一个抽象语法树和一个符号 Table。还要处理错误是否有可能在没有抽象语法树的情况下进行错误处理?
这是我在终端中的输出:
syntan.y: In function ‘yyparse’:
syntan.y:70:64: warning: assignment to ‘ASTnode *’ {aka ‘struct ASTnodetype *’} from incompatible pointer type ‘int *’ [-Wincompatible-pointer-types]
70 | program: declaration_list { prog = ; }
| ^
syntan.y:73:76: error: request for member ‘left’ in something not a structure or union
73 | declaration_list: declaration_list declaration { -> left = ; $$ = ; }
| ^~
syntan.y:86:36: error: ‘VOIDDEC’ undeclared (first use in this function)
86 | if ( != VOIDDEC && != INTDEC)
| ^~~~~~~
syntan.y:86:36: note: each undeclared identifier is reported only once for each function it appears in
yacc 文件
%{
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "y.tab.h"
#include "asttree.h"
#include "symboltable.h"
void yyerror(const char *s);
extern int yylex(void);
extern int yyparse(void);
extern char *yytext;
extern FILE *yyin;
char filename[50];
static int level = 0;
static int offset = 0;
static int goffset = 0;
static int maxoffset = 0;
void yyerror(const char* s);
extern int yylineno;
%}
%union
{
int intv;
char *string;
ASTnode *node;
enum OPERATORS op;
};
%start program
%token<intv>T_NUM
%token IF WHILE ELSE
%token RETURN INT VOID
%token GREATEQ LESS SMALLEQ EQUALITY NOTEQ BIGGER
%token TIMES DIVIDE PLUS MINUS EQUAL QUESTIONM COMMA
%token LBRAC RBRAC LPAR RPAR LCURLY RCURLY
%token<string>T_ID
%left PLUS MINUS
%left TIMES DIVIDE
%left LPAR RPAR
%right ELSE
%type<node> declaration_list declaration var_declaration
%type<node> program
%type<node> fun_declaration additive_expression
%type<node> params param_list param
%type<node> compound_stmt local_declarations statement_list statement
%type<node> expression_stmt selection_stmt iteration_stmt return_stmt
%type<node> expression var simple_expression term factor call args arg_list
%type<op> relop addop mulop type_specifier
%%
program: declaration_list { prog = ; }
;
declaration_list: declaration_list declaration { -> left = ; $$ = ; }
| declaration { $$ = ; }
;
declaration: var_declaration { $$ = ; }
| fun_declaration { $$ = ; }
;
var_declaration: type_specifier T_ID QUESTIONM
{
if(Search(, level, 0))
yyerror("Redefined variable declaration");
if ( != VOIDDEC && != INTDEC)
yyerror("Invalid type specifier");
$$ = ASTCreateNode(VARDEC);
$$ -> name = ;
/* we use the op to determine its type while printing*/
$$ -> op = ;
$$ -> symbol = Insert(, , 0, level, 1, offset, NULL);
$$ -> isType = ;
offset += 1;
if(offset > maxoffset)
maxoffset = offset;
}
| type_specifier T_ID LBRAC T_NUM RBRAC QUESTIONM
{
if(Search(, level, 0))
yyerror("Redefined variable declaration");
$$ = ASTCreateNode(VARDEC);
$$ -> name = ;
$$ -> op = ;
$$ -> value = ;
$$ -> symbol = Insert(, , 2, level, , offset, NULL);
$$ -> isType = ;
offset += ;
if (offset > maxoffset)
maxoffset = offset;
}
;
type_specifier: INT { $$ = INTDEC; }
| VOID { $$ = VOIDDEC; }
;
fun_declaration: type_specifier T_ID LPAR
{
if(Search(, level, 0))
yyerror("Redefined function declaration");
Insert(, , 1, level, 1, 0, NULL);
goffset = offset;
offset = 2;
if(offset > maxoffset)
maxoffset = offset;
}
params
{
(Search(, 0, 0)) -> fparms = ;
}
RPAR compound_stmt
{
$$ = ASTCreateNode(FUNCTIONDEC);
$$ -> name = ;
/* we use the op to determine its type while printing*/
$$ -> op = ;
/* s1 links to the params which can be void
or a paramList */
$$ -> s1 = ;
/* right links to the compund statement,
called a BLOCK in the enumerated type */
$$ -> right = ;
/*get the symbtab entry we made earlier*/
$$ -> symbol = Search(, 0, 0);
/*Remove symbols put in, in the function call*/
offset -= Delete(1);
level = 0;
$$ -> value = maxoffset;
//we change this in the symbol table because it is not used
//anywhere else for functions. We have access to this
//in calls, so we can use it to determine where the
//stack pointer is going to have to be
$$ -> symbol -> mysize = maxoffset;
/*change the offset back to the global offset*/
offset = goffset;
maxoffset = 0;
}
;
params: param_list { $$ = ; }
| VOID { $$ = NULL; }
;
param_list: param_list COMMA param
{
-> left = ;
$$ = ;
}
| param { $$ = ; }
;
param: type_specifier T_ID
{
if(Search(, level, 0))
yyerror("Redefined variable declaration");
$$ = ASTCreateNode(PARAM);
$$ -> name = ;
/* we use the op to determine its type while printing*/
$$ -> op = ;
/* if value is 0 it is not an array, used for printing */
$$ -> value = 0;
/*inherit the type*/
$$ -> isType = ;
$$ -> symbol = Insert(, , 0, level+1, 1, offset, NULL);
offset += 1;
if(offset > maxoffset)
maxoffset = offset;
}
| type_specifier T_ID LBRAC RBRAC
{
if(Search(, level, 0))
yyerror("Redefined variable declaration");
$$ = ASTCreateNode(PARAM);
$$ -> name = ;
/* we use the op to determine its type while printing*/
$$ -> op = ;
/* there was an array param */
$$ -> value = 1;
/*inherit the type*/
$$ -> isType = ;
/*2 is used for IsAFunc to show its an array ref*/
$$ -> symbol = Insert(, , 2, level+1, 1, offset, NULL);
offset += 1;
if(offset > maxoffset)
maxoffset = offset;
}
;
compound_stmt: LCURLY
{ level++; }
local_declarations statement_list RCURLY
{
$$ = ASTCreateNode(BLOCK);
if( == NULL )
$$ -> right = ;
else {
ASTattachleft(, );
$$ -> right = ;
}
offset -= Delete(level);
level--;
}
;
local_declarations: local_declarations var_declaration
{
if( != NULL)
{
-> left = ;
$$ = ;
}
else
$$ = ;
}
| { $$ = NULL; }
;
statement_list: statement_list statement
{
if( != NULL )
{
-> left = ;
$$ = ;
}
else
$$ = ;
}
| { $$ = NULL; }
;
statement: expression_stmt { $$ = ; }
| compound_stmt { $$ = ; }
| selection_stmt { $$ = ; }
| iteration_stmt { $$ = ; }
| return_stmt { $$ = ; }
;
expression_stmt: expression QUESTIONM
{
$$ = ASTCreateNode(EXPRSTMT);
$$ -> right = ;
$$ -> isType = -> isType;
}
| QUESTIONM { $$ = NULL; }
;
selection_stmt: IF LPAR expression RPAR statement
{
$$ = ASTCreateNode(IFSTMT);
$$ -> right = ;
$$ -> s1 = ;
}
| IF LPAR expression RPAR statement ELSE statement
{
$$ = ASTCreateNode(IFSTMT);
$$ -> right = ;
$$ -> s1 = ;
$$ -> s2 = ;
}
;
iteration_stmt: WHILE LPAR expression RPAR statement
{
$$ = ASTCreateNode(ITERSTMT);
$$ -> right = ;
$$ -> s1 = ;
}
;
return_stmt: RETURN QUESTIONM { $$ = ASTCreateNode(RETURNSTMT); }
| RETURN expression QUESTIONM
{
$$ = ASTCreateNode(RETURNSTMT);
$$ -> s2 = ;
}
;
expression: var EQUAL expression
{
if (( -> isType != -> isType) || ( -> isType == VOIDDEC))
yyerror("Incompatible types in assignment");
$$ = ASTCreateNode(ASSIGN);
/* hold the link to the var node*/
$$ -> right = ;
/* hold the link to the expression statement*/
$$ -> s1 = ;
/*inherit the type, already check for equivalence so can just use */
$$ -> isType = -> isType;
$$ -> name = CreateTemp();
$$ -> symbol = Insert($$ -> name, $$ -> isType, 0, level, 1, offset, NULL);
offset += 1;
if(offset > maxoffset)
maxoffset = offset;
}
| simple_expression { $$ = ; }
;
var: T_ID
{
struct SymbTab * p;
if ((p=Search(,level,1)) != NULL)
{
$$ = ASTCreateNode(IDENT);
$$-> name = ;
$$-> symbol =p;
/*give the node op Type, based on SymbTab*/
$$->isType=p->Type;
if (p->IsAFunc == 2)
yyerror("Variable is an array");
}
else
yyerror("Undefined variable");
}
| T_ID LBRAC expression RBRAC
{
struct SymbTab * p;
if ((p=Search(,level,1)) != NULL)
{
$$ = ASTCreateNode(IDENT);
$$ -> name = ;
/* hold expression inside of array reference */
$$ -> right = ;
$$ -> symbol = p;
/*capital Type is enum op*/
$$ -> isType = p -> Type;
if (p->IsAFunc != 2)
yyerror("Variable is not an array");
}
else
yyerror("Undefined variable");
}
;
simple_expression: additive_expression relop additive_expression
{
if (( -> isType != -> isType) || ( -> isType == VOIDDEC))
yyerror("Type mismatch or void in simpleExpression");
$$ = ASTCreateNode(EXPR);
$$ -> op = ;
$$ -> left = ;
$$ -> right = ;
/*inherit the type, already check for equivalence so can just use */
$$ -> isType = -> isType;
$$ -> name = CreateTemp();
$$ -> symbol = Insert($$ -> name, $$ -> isType, 0, level, 1, offset, NULL);
offset += 1;
if(offset > maxoffset)
maxoffset = offset;
}
| additive_expression { $$ = ; }
;
relop: BIGGER { $$ = BIGGER; }
| LESS { $$ = LESS; }
| SMALLEQ { $$ = SMALLEQ; }
| EQUALITY { $$ = EQUAL; }
| NOTEQ { $$ = NOTEQ; }
| GREATEQ { $$ = GREATEQ; }
;
additive_expression: additive_expression addop term
{
if (( -> isType != -> isType) || ( -> isType == VOIDDEC))
yyerror("Type mismatch or void in additive exp");
$$ = ASTCreateNode(EXPR);
$$ -> op = ;
$$ -> left = ;
$$ -> right = ;
/*inherit the type, already check for equivalence so can just use */
$$ -> isType = -> isType;
$$ -> name = CreateTemp();
$$ -> symbol = Insert($$ -> name, $$ -> isType, 0, level, 1, offset, NULL);
offset += 1;
if(offset > maxoffset)
maxoffset = offset;
}
| term { $$ = ; }
;
addop: PLUS { $$ = PLUS; }
| MINUS { $$ = MINUS; }
;
term: term mulop factor
{
if (( -> isType != -> isType) || ( -> isType == VOIDDEC))
yyerror("Type mismatch or void in term/factor exp");
$$ = ASTCreateNode(EXPR);
$$ -> op = ;
$$ -> left = ;
$$ -> right = ;
/*inherit the type, already check for equivalence so can just use */
$$ -> isType = -> isType;
$$ -> name = CreateTemp();
$$ -> symbol = Insert($$ -> name, $$ -> isType, 0, level, 1, offset, NULL);
offset += 1;
if(offset > maxoffset)
maxoffset = offset;
}
| factor { $$ = ; }
;
mulop: TIMES { $$ = TIMES; }
| DIVIDE { $$ = DIVIDE; }
;
factor: LPAR expression RPAR { $$ = ; }
| var { $$ = ; }
| call { $$ = ; }
| T_NUM
{
$$ = ASTCreateNode(NUMBER);
$$ -> value = ;
/*numbers are always ints here*/
$$ -> isType = INTDEC;
}
;
call: T_ID LPAR args RPAR
{
struct SymbTab * p;
if ((p = Search(, 0, 1)) != NULL)
{ /*make sure symbol is a function*/
if(p -> IsAFunc != 1)
yyerror("Is a variable, but was called as function");
if (compareFormals(p -> fparms, ) != 1)
yyerror("Wrong type of arguments");
$$ = ASTCreateNode(CALLSTMT);
/* hold the link to args in right*/
$$ -> right = ;
$$ -> name = ;
$$ -> symbol = p;
$$ -> isType = p -> Type;
}
else
yyerror("Call to undefined function");
}
;
args: arg_list { $$ = ; }
| { $$ = NULL; }
;
arg_list: arg_list COMMA expression
{
$$ = ASTCreateNode(ARGLIST);
$$ -> left = ;
$$ -> right = ;
}
| expression
{
$$ = ASTCreateNode(ARGLIST);
$$ -> right = ;
}
;
%%
** AST 文件**
#include "asttree.h"
int lineCounter = 0;
int labelCounter = 0;
int tempCounter = 0;
ASTnode *ASTCreateNode(enum ASTtype mytype)
{
ASTnode * p;
p = (ASTnode *)malloc(sizeof(ASTnode));
p -> type = mytype;
p -> left = NULL;
p -> right = NULL;
p -> s1 = NULL;
p -> s2 = NULL;
p -> value = 0;
p -> name = NULL;
p -> str = NULL;
p -> symbol = NULL;
p -> isType = null;
return(p);
}
/* attach q to the left most part of p */
void ASTattachleft(ASTnode* p,ASTnode* q)
{
while (p -> left != NULL)
p = p -> left;
p -> left = q; /*add on the left side of the tree*/
}
/*
* Printing Tabbing
*/
void PT(int howmany)
{
int i;
for (i = 0; i < howmany; i++)
printf(" ");
}
/* AST PRINT */
void ASTprint(int level, ASTnode* p)
{
if (p == NULL )
return;
else
{
PT(level);
switch (p->type)
{
case VARDEC :
printf("Variable "); //one per ast node type
if ((p -> op) == INTDEC)
printf("INT ");
if (p -> op == VOIDDEC)
printf("VOID ");
printf("%s\n", p -> name);
if (p -> value > 0)
{//is an array
printf("[%d]\n", p -> value);
}
lineCounter++;
break;
case FUNCTIONDEC:
if (p -> op == INTDEC)
printf("INT ");
if (p -> op == VOIDDEC)
printf("VOID ");
printf("FUNCTION %s \n", p -> name);
if (p -> s1 == NULL)
{
PT(level + 2);
printf( "(VOID)\n" );
}
else
{
PT(level + 2);
printf("( \n");
ASTprint(level + 2, p -> s1);
PT(level + 2);
printf(") \n");
}
ASTprint(level + 2,p -> right);
break;
case EXPR: printf("EXPR ");
if (p -> name != NULL)
printf(" %s = ", p->name);
ASTnode* node1 = p -> right;
ASTnode* node2 = p -> left;
switch (p -> op)
{
case PLUS:
printf("+");
break;
case MINUS:
printf("-");
break;
case TIMES:
printf("*");
break;
case DIVIDE:
printf("/");
break;
case SMALLEQ:
printf("<=");
break;
case LESS:
printf("<");
break;
case BIGGER:
printf(">");
break;
case GREATEQ:
printf(">=");
break;
case NOTEQ:
printf("!=");
break;
case EQUAL:
printf("==");
break;
case INTDEC:
case VOIDDEC:
case null:
break;
}
printf("\n");
ASTprint(level + 1, p -> left);
ASTprint(level + 1, p -> right);
break;
case RETURNSTMT:
printf("Return statement\n");
ASTprint(level + 1, p -> right);
break;
case IDENT:
printf("IDENTIFIER %s\n", p->name);
if (p -> right != NULL)
{
PT(level);
printf("Array reference [\n");
ASTprint(level + 1, p -> right);
PT(level);
printf("] end array\n");
}
break;
case BLOCK:
printf("compound_stmt\n");
ASTprint(level + 1, p -> right);
break;
case ASSIGN:
printf("Assignment STATEMENT\n");
ASTprint(level + 1, p -> right);
ASTprint(level + 1, p -> s1);
break;
case NUMBER:
printf("NUMBER with value %d\n", p->value);
break;
case ITERSTMT:
printf("WHILE STATEMENT\n");
ASTprint(level + 1, p -> right);
printf("\n");
ASTprint(level + 1, p -> s1);
printf("\n");
break;
case PARAM:
printf("PARAMETER ");
printf(" %s ", p -> name);
if(p -> value == -1)
printf("[]");
printf("\n");
break;
case IFSTMT:
printf("IF STATEMENT\n");
ASTprint(level + 1, p -> right);
printf("\n");
ASTprint(level + 1, p -> s1);
printf("\n");
if(p -> s2 != NULL)
{
PT(level);
printf("ELSE \n");
ASTprint(level + 2, p -> s2);
}
break;
case CALLSTMT:
printf("Function Call %s\n" , p ->name);
if (p -> right != NULL)
{
ASTprint(level + 2, p -> right);
printf("\n");
} else {
PT(level + 2);
printf("(VOID)\n");
}
break;
case ARGLIST:
printf("ARG\n");
ASTnode* node4 = p -> right;
ASTprint(level + 1, p -> right);
break;
case EXPRSTMT:
printf("Expression Statement\n");
ASTnode* node3 = p -> right;
ASTprint(level + 1, p -> right);
break;
default: printf("Unknown type in ASTprint\n");
break;
}
if (p -> type != EXPR)
ASTprint(level, p -> left);
}
}
/*
* COMPAREFORMALS
* Used to compare parms declared to the ones used to call
*/
int compareFormals(ASTnode * p, ASTnode *q)
{
if((p == NULL) && (q == NULL))
return(1); //they were both void
else if ((p == NULL) || (q == NULL))
return (0); //one is void, already checked for both so p!=q
else if(p -> isType == q -> right -> isType)
compareFormals(p -> left, q -> left); //check the next param
else
return(0);
}
任何建议都会有帮助!
尽管问题中粘贴了数百行代码,但我不确定是否真的足够继续下去,特别是因为您既没有包含收到的所有错误消息,也没有包含头文件.所以这更像是一个猜测。在编写大量代码之前尝试编译代码通常是个好主意,特别是如果您将被要求提供一个 minimal 可重现的示例。但这都是题外话。
我在你的语法文件中注意到,就在开头,你的包含:
#include "y.tab.h"
#include "asttree.h"
#include "symboltable.h"
第一个是错误的。这是 Bison 生成的头文件,Bison 将把该文件中的所有内容包含到生成的 C 文件中。所以你不需要 #include "y.tab.h"
,而且,它可能是你大部分错误的原因,因为它被包含得太早了。问题是 ASTNode
是(我假设)在 asttree.h
中定义的,并且从上面的代码片段可以清楚地看出,在处理 y.tab.h
时 asttree.h
尚未包含在内。那行不通,因为语义类型是在 y.tab.h
中声明的;声明将类似于:
union YYSTYPE
{
int intv;
char *string;
ASTnode *node;
enum OPERATORS op;
};
这要求 ASTnode
已经声明。但事实并非如此,所以我很确定这会产生错误,即使你不记得使用 -Wall
进行编译(你应该这样做;Bison 不会生成生成警告的代码) .由于此时尚未声明 [=18=] 并且编译器希望能够继续尝试编译,因此必须使 node
成为指向 某物的指针 ;显然,它使用了 int
。这意味着稍后当您尝试使用一个类型假定为 ASTnode*
的变量时,编译器会将该变量视为 int*
,当然这使得无法引用该成员该变量指向的对象,因为 int
不是联合或结构,如错误消息所述。此外,您不能将(假定的)int*
分配给 prog
,因为(我猜)prog
是在 ASTnode
声明的程序的一部分中声明的是可见的,所以它实际上是一个指向 ASTnode
.
的指针
当您从编译中收到大量错误消息时,从一开始就开始修复通常是个好主意;在某些时候,编译器的错误恢复将开始变得无用,之后的错误消息可能只是人为因素。当您尝试在自己的编译器中实现错误恢复时,您很快就会看到它是如何工作的。
最重要的是,您应该从解析器文件中删除 #include "y.tab.h"
。它只在词法分析器中需要。我怀疑这是否是唯一的错误,但它可能会帮助您推进项目。
我正在尝试制作一个 c-minus 编译器,但我必须制作一个抽象语法树和一个符号 Table。还要处理错误是否有可能在没有抽象语法树的情况下进行错误处理? 这是我在终端中的输出:
syntan.y: In function ‘yyparse’:
syntan.y:70:64: warning: assignment to ‘ASTnode *’ {aka ‘struct ASTnodetype *’} from incompatible pointer type ‘int *’ [-Wincompatible-pointer-types]
70 | program: declaration_list { prog = ; }
| ^
syntan.y:73:76: error: request for member ‘left’ in something not a structure or union
73 | declaration_list: declaration_list declaration { -> left = ; $$ = ; }
| ^~
syntan.y:86:36: error: ‘VOIDDEC’ undeclared (first use in this function)
86 | if ( != VOIDDEC && != INTDEC)
| ^~~~~~~
syntan.y:86:36: note: each undeclared identifier is reported only once for each function it appears in
yacc 文件
%{
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "y.tab.h"
#include "asttree.h"
#include "symboltable.h"
void yyerror(const char *s);
extern int yylex(void);
extern int yyparse(void);
extern char *yytext;
extern FILE *yyin;
char filename[50];
static int level = 0;
static int offset = 0;
static int goffset = 0;
static int maxoffset = 0;
void yyerror(const char* s);
extern int yylineno;
%}
%union
{
int intv;
char *string;
ASTnode *node;
enum OPERATORS op;
};
%start program
%token<intv>T_NUM
%token IF WHILE ELSE
%token RETURN INT VOID
%token GREATEQ LESS SMALLEQ EQUALITY NOTEQ BIGGER
%token TIMES DIVIDE PLUS MINUS EQUAL QUESTIONM COMMA
%token LBRAC RBRAC LPAR RPAR LCURLY RCURLY
%token<string>T_ID
%left PLUS MINUS
%left TIMES DIVIDE
%left LPAR RPAR
%right ELSE
%type<node> declaration_list declaration var_declaration
%type<node> program
%type<node> fun_declaration additive_expression
%type<node> params param_list param
%type<node> compound_stmt local_declarations statement_list statement
%type<node> expression_stmt selection_stmt iteration_stmt return_stmt
%type<node> expression var simple_expression term factor call args arg_list
%type<op> relop addop mulop type_specifier
%%
program: declaration_list { prog = ; }
;
declaration_list: declaration_list declaration { -> left = ; $$ = ; }
| declaration { $$ = ; }
;
declaration: var_declaration { $$ = ; }
| fun_declaration { $$ = ; }
;
var_declaration: type_specifier T_ID QUESTIONM
{
if(Search(, level, 0))
yyerror("Redefined variable declaration");
if ( != VOIDDEC && != INTDEC)
yyerror("Invalid type specifier");
$$ = ASTCreateNode(VARDEC);
$$ -> name = ;
/* we use the op to determine its type while printing*/
$$ -> op = ;
$$ -> symbol = Insert(, , 0, level, 1, offset, NULL);
$$ -> isType = ;
offset += 1;
if(offset > maxoffset)
maxoffset = offset;
}
| type_specifier T_ID LBRAC T_NUM RBRAC QUESTIONM
{
if(Search(, level, 0))
yyerror("Redefined variable declaration");
$$ = ASTCreateNode(VARDEC);
$$ -> name = ;
$$ -> op = ;
$$ -> value = ;
$$ -> symbol = Insert(, , 2, level, , offset, NULL);
$$ -> isType = ;
offset += ;
if (offset > maxoffset)
maxoffset = offset;
}
;
type_specifier: INT { $$ = INTDEC; }
| VOID { $$ = VOIDDEC; }
;
fun_declaration: type_specifier T_ID LPAR
{
if(Search(, level, 0))
yyerror("Redefined function declaration");
Insert(, , 1, level, 1, 0, NULL);
goffset = offset;
offset = 2;
if(offset > maxoffset)
maxoffset = offset;
}
params
{
(Search(, 0, 0)) -> fparms = ;
}
RPAR compound_stmt
{
$$ = ASTCreateNode(FUNCTIONDEC);
$$ -> name = ;
/* we use the op to determine its type while printing*/
$$ -> op = ;
/* s1 links to the params which can be void
or a paramList */
$$ -> s1 = ;
/* right links to the compund statement,
called a BLOCK in the enumerated type */
$$ -> right = ;
/*get the symbtab entry we made earlier*/
$$ -> symbol = Search(, 0, 0);
/*Remove symbols put in, in the function call*/
offset -= Delete(1);
level = 0;
$$ -> value = maxoffset;
//we change this in the symbol table because it is not used
//anywhere else for functions. We have access to this
//in calls, so we can use it to determine where the
//stack pointer is going to have to be
$$ -> symbol -> mysize = maxoffset;
/*change the offset back to the global offset*/
offset = goffset;
maxoffset = 0;
}
;
params: param_list { $$ = ; }
| VOID { $$ = NULL; }
;
param_list: param_list COMMA param
{
-> left = ;
$$ = ;
}
| param { $$ = ; }
;
param: type_specifier T_ID
{
if(Search(, level, 0))
yyerror("Redefined variable declaration");
$$ = ASTCreateNode(PARAM);
$$ -> name = ;
/* we use the op to determine its type while printing*/
$$ -> op = ;
/* if value is 0 it is not an array, used for printing */
$$ -> value = 0;
/*inherit the type*/
$$ -> isType = ;
$$ -> symbol = Insert(, , 0, level+1, 1, offset, NULL);
offset += 1;
if(offset > maxoffset)
maxoffset = offset;
}
| type_specifier T_ID LBRAC RBRAC
{
if(Search(, level, 0))
yyerror("Redefined variable declaration");
$$ = ASTCreateNode(PARAM);
$$ -> name = ;
/* we use the op to determine its type while printing*/
$$ -> op = ;
/* there was an array param */
$$ -> value = 1;
/*inherit the type*/
$$ -> isType = ;
/*2 is used for IsAFunc to show its an array ref*/
$$ -> symbol = Insert(, , 2, level+1, 1, offset, NULL);
offset += 1;
if(offset > maxoffset)
maxoffset = offset;
}
;
compound_stmt: LCURLY
{ level++; }
local_declarations statement_list RCURLY
{
$$ = ASTCreateNode(BLOCK);
if( == NULL )
$$ -> right = ;
else {
ASTattachleft(, );
$$ -> right = ;
}
offset -= Delete(level);
level--;
}
;
local_declarations: local_declarations var_declaration
{
if( != NULL)
{
-> left = ;
$$ = ;
}
else
$$ = ;
}
| { $$ = NULL; }
;
statement_list: statement_list statement
{
if( != NULL )
{
-> left = ;
$$ = ;
}
else
$$ = ;
}
| { $$ = NULL; }
;
statement: expression_stmt { $$ = ; }
| compound_stmt { $$ = ; }
| selection_stmt { $$ = ; }
| iteration_stmt { $$ = ; }
| return_stmt { $$ = ; }
;
expression_stmt: expression QUESTIONM
{
$$ = ASTCreateNode(EXPRSTMT);
$$ -> right = ;
$$ -> isType = -> isType;
}
| QUESTIONM { $$ = NULL; }
;
selection_stmt: IF LPAR expression RPAR statement
{
$$ = ASTCreateNode(IFSTMT);
$$ -> right = ;
$$ -> s1 = ;
}
| IF LPAR expression RPAR statement ELSE statement
{
$$ = ASTCreateNode(IFSTMT);
$$ -> right = ;
$$ -> s1 = ;
$$ -> s2 = ;
}
;
iteration_stmt: WHILE LPAR expression RPAR statement
{
$$ = ASTCreateNode(ITERSTMT);
$$ -> right = ;
$$ -> s1 = ;
}
;
return_stmt: RETURN QUESTIONM { $$ = ASTCreateNode(RETURNSTMT); }
| RETURN expression QUESTIONM
{
$$ = ASTCreateNode(RETURNSTMT);
$$ -> s2 = ;
}
;
expression: var EQUAL expression
{
if (( -> isType != -> isType) || ( -> isType == VOIDDEC))
yyerror("Incompatible types in assignment");
$$ = ASTCreateNode(ASSIGN);
/* hold the link to the var node*/
$$ -> right = ;
/* hold the link to the expression statement*/
$$ -> s1 = ;
/*inherit the type, already check for equivalence so can just use */
$$ -> isType = -> isType;
$$ -> name = CreateTemp();
$$ -> symbol = Insert($$ -> name, $$ -> isType, 0, level, 1, offset, NULL);
offset += 1;
if(offset > maxoffset)
maxoffset = offset;
}
| simple_expression { $$ = ; }
;
var: T_ID
{
struct SymbTab * p;
if ((p=Search(,level,1)) != NULL)
{
$$ = ASTCreateNode(IDENT);
$$-> name = ;
$$-> symbol =p;
/*give the node op Type, based on SymbTab*/
$$->isType=p->Type;
if (p->IsAFunc == 2)
yyerror("Variable is an array");
}
else
yyerror("Undefined variable");
}
| T_ID LBRAC expression RBRAC
{
struct SymbTab * p;
if ((p=Search(,level,1)) != NULL)
{
$$ = ASTCreateNode(IDENT);
$$ -> name = ;
/* hold expression inside of array reference */
$$ -> right = ;
$$ -> symbol = p;
/*capital Type is enum op*/
$$ -> isType = p -> Type;
if (p->IsAFunc != 2)
yyerror("Variable is not an array");
}
else
yyerror("Undefined variable");
}
;
simple_expression: additive_expression relop additive_expression
{
if (( -> isType != -> isType) || ( -> isType == VOIDDEC))
yyerror("Type mismatch or void in simpleExpression");
$$ = ASTCreateNode(EXPR);
$$ -> op = ;
$$ -> left = ;
$$ -> right = ;
/*inherit the type, already check for equivalence so can just use */
$$ -> isType = -> isType;
$$ -> name = CreateTemp();
$$ -> symbol = Insert($$ -> name, $$ -> isType, 0, level, 1, offset, NULL);
offset += 1;
if(offset > maxoffset)
maxoffset = offset;
}
| additive_expression { $$ = ; }
;
relop: BIGGER { $$ = BIGGER; }
| LESS { $$ = LESS; }
| SMALLEQ { $$ = SMALLEQ; }
| EQUALITY { $$ = EQUAL; }
| NOTEQ { $$ = NOTEQ; }
| GREATEQ { $$ = GREATEQ; }
;
additive_expression: additive_expression addop term
{
if (( -> isType != -> isType) || ( -> isType == VOIDDEC))
yyerror("Type mismatch or void in additive exp");
$$ = ASTCreateNode(EXPR);
$$ -> op = ;
$$ -> left = ;
$$ -> right = ;
/*inherit the type, already check for equivalence so can just use */
$$ -> isType = -> isType;
$$ -> name = CreateTemp();
$$ -> symbol = Insert($$ -> name, $$ -> isType, 0, level, 1, offset, NULL);
offset += 1;
if(offset > maxoffset)
maxoffset = offset;
}
| term { $$ = ; }
;
addop: PLUS { $$ = PLUS; }
| MINUS { $$ = MINUS; }
;
term: term mulop factor
{
if (( -> isType != -> isType) || ( -> isType == VOIDDEC))
yyerror("Type mismatch or void in term/factor exp");
$$ = ASTCreateNode(EXPR);
$$ -> op = ;
$$ -> left = ;
$$ -> right = ;
/*inherit the type, already check for equivalence so can just use */
$$ -> isType = -> isType;
$$ -> name = CreateTemp();
$$ -> symbol = Insert($$ -> name, $$ -> isType, 0, level, 1, offset, NULL);
offset += 1;
if(offset > maxoffset)
maxoffset = offset;
}
| factor { $$ = ; }
;
mulop: TIMES { $$ = TIMES; }
| DIVIDE { $$ = DIVIDE; }
;
factor: LPAR expression RPAR { $$ = ; }
| var { $$ = ; }
| call { $$ = ; }
| T_NUM
{
$$ = ASTCreateNode(NUMBER);
$$ -> value = ;
/*numbers are always ints here*/
$$ -> isType = INTDEC;
}
;
call: T_ID LPAR args RPAR
{
struct SymbTab * p;
if ((p = Search(, 0, 1)) != NULL)
{ /*make sure symbol is a function*/
if(p -> IsAFunc != 1)
yyerror("Is a variable, but was called as function");
if (compareFormals(p -> fparms, ) != 1)
yyerror("Wrong type of arguments");
$$ = ASTCreateNode(CALLSTMT);
/* hold the link to args in right*/
$$ -> right = ;
$$ -> name = ;
$$ -> symbol = p;
$$ -> isType = p -> Type;
}
else
yyerror("Call to undefined function");
}
;
args: arg_list { $$ = ; }
| { $$ = NULL; }
;
arg_list: arg_list COMMA expression
{
$$ = ASTCreateNode(ARGLIST);
$$ -> left = ;
$$ -> right = ;
}
| expression
{
$$ = ASTCreateNode(ARGLIST);
$$ -> right = ;
}
;
%%
** AST 文件**
#include "asttree.h"
int lineCounter = 0;
int labelCounter = 0;
int tempCounter = 0;
ASTnode *ASTCreateNode(enum ASTtype mytype)
{
ASTnode * p;
p = (ASTnode *)malloc(sizeof(ASTnode));
p -> type = mytype;
p -> left = NULL;
p -> right = NULL;
p -> s1 = NULL;
p -> s2 = NULL;
p -> value = 0;
p -> name = NULL;
p -> str = NULL;
p -> symbol = NULL;
p -> isType = null;
return(p);
}
/* attach q to the left most part of p */
void ASTattachleft(ASTnode* p,ASTnode* q)
{
while (p -> left != NULL)
p = p -> left;
p -> left = q; /*add on the left side of the tree*/
}
/*
* Printing Tabbing
*/
void PT(int howmany)
{
int i;
for (i = 0; i < howmany; i++)
printf(" ");
}
/* AST PRINT */
void ASTprint(int level, ASTnode* p)
{
if (p == NULL )
return;
else
{
PT(level);
switch (p->type)
{
case VARDEC :
printf("Variable "); //one per ast node type
if ((p -> op) == INTDEC)
printf("INT ");
if (p -> op == VOIDDEC)
printf("VOID ");
printf("%s\n", p -> name);
if (p -> value > 0)
{//is an array
printf("[%d]\n", p -> value);
}
lineCounter++;
break;
case FUNCTIONDEC:
if (p -> op == INTDEC)
printf("INT ");
if (p -> op == VOIDDEC)
printf("VOID ");
printf("FUNCTION %s \n", p -> name);
if (p -> s1 == NULL)
{
PT(level + 2);
printf( "(VOID)\n" );
}
else
{
PT(level + 2);
printf("( \n");
ASTprint(level + 2, p -> s1);
PT(level + 2);
printf(") \n");
}
ASTprint(level + 2,p -> right);
break;
case EXPR: printf("EXPR ");
if (p -> name != NULL)
printf(" %s = ", p->name);
ASTnode* node1 = p -> right;
ASTnode* node2 = p -> left;
switch (p -> op)
{
case PLUS:
printf("+");
break;
case MINUS:
printf("-");
break;
case TIMES:
printf("*");
break;
case DIVIDE:
printf("/");
break;
case SMALLEQ:
printf("<=");
break;
case LESS:
printf("<");
break;
case BIGGER:
printf(">");
break;
case GREATEQ:
printf(">=");
break;
case NOTEQ:
printf("!=");
break;
case EQUAL:
printf("==");
break;
case INTDEC:
case VOIDDEC:
case null:
break;
}
printf("\n");
ASTprint(level + 1, p -> left);
ASTprint(level + 1, p -> right);
break;
case RETURNSTMT:
printf("Return statement\n");
ASTprint(level + 1, p -> right);
break;
case IDENT:
printf("IDENTIFIER %s\n", p->name);
if (p -> right != NULL)
{
PT(level);
printf("Array reference [\n");
ASTprint(level + 1, p -> right);
PT(level);
printf("] end array\n");
}
break;
case BLOCK:
printf("compound_stmt\n");
ASTprint(level + 1, p -> right);
break;
case ASSIGN:
printf("Assignment STATEMENT\n");
ASTprint(level + 1, p -> right);
ASTprint(level + 1, p -> s1);
break;
case NUMBER:
printf("NUMBER with value %d\n", p->value);
break;
case ITERSTMT:
printf("WHILE STATEMENT\n");
ASTprint(level + 1, p -> right);
printf("\n");
ASTprint(level + 1, p -> s1);
printf("\n");
break;
case PARAM:
printf("PARAMETER ");
printf(" %s ", p -> name);
if(p -> value == -1)
printf("[]");
printf("\n");
break;
case IFSTMT:
printf("IF STATEMENT\n");
ASTprint(level + 1, p -> right);
printf("\n");
ASTprint(level + 1, p -> s1);
printf("\n");
if(p -> s2 != NULL)
{
PT(level);
printf("ELSE \n");
ASTprint(level + 2, p -> s2);
}
break;
case CALLSTMT:
printf("Function Call %s\n" , p ->name);
if (p -> right != NULL)
{
ASTprint(level + 2, p -> right);
printf("\n");
} else {
PT(level + 2);
printf("(VOID)\n");
}
break;
case ARGLIST:
printf("ARG\n");
ASTnode* node4 = p -> right;
ASTprint(level + 1, p -> right);
break;
case EXPRSTMT:
printf("Expression Statement\n");
ASTnode* node3 = p -> right;
ASTprint(level + 1, p -> right);
break;
default: printf("Unknown type in ASTprint\n");
break;
}
if (p -> type != EXPR)
ASTprint(level, p -> left);
}
}
/*
* COMPAREFORMALS
* Used to compare parms declared to the ones used to call
*/
int compareFormals(ASTnode * p, ASTnode *q)
{
if((p == NULL) && (q == NULL))
return(1); //they were both void
else if ((p == NULL) || (q == NULL))
return (0); //one is void, already checked for both so p!=q
else if(p -> isType == q -> right -> isType)
compareFormals(p -> left, q -> left); //check the next param
else
return(0);
}
任何建议都会有帮助!
尽管问题中粘贴了数百行代码,但我不确定是否真的足够继续下去,特别是因为您既没有包含收到的所有错误消息,也没有包含头文件.所以这更像是一个猜测。在编写大量代码之前尝试编译代码通常是个好主意,特别是如果您将被要求提供一个 minimal 可重现的示例。但这都是题外话。
我在你的语法文件中注意到,就在开头,你的包含:
#include "y.tab.h"
#include "asttree.h"
#include "symboltable.h"
第一个是错误的。这是 Bison 生成的头文件,Bison 将把该文件中的所有内容包含到生成的 C 文件中。所以你不需要 #include "y.tab.h"
,而且,它可能是你大部分错误的原因,因为它被包含得太早了。问题是 ASTNode
是(我假设)在 asttree.h
中定义的,并且从上面的代码片段可以清楚地看出,在处理 y.tab.h
时 asttree.h
尚未包含在内。那行不通,因为语义类型是在 y.tab.h
中声明的;声明将类似于:
union YYSTYPE
{
int intv;
char *string;
ASTnode *node;
enum OPERATORS op;
};
这要求 ASTnode
已经声明。但事实并非如此,所以我很确定这会产生错误,即使你不记得使用 -Wall
进行编译(你应该这样做;Bison 不会生成生成警告的代码) .由于此时尚未声明 [=18=] 并且编译器希望能够继续尝试编译,因此必须使 node
成为指向 某物的指针 ;显然,它使用了 int
。这意味着稍后当您尝试使用一个类型假定为 ASTnode*
的变量时,编译器会将该变量视为 int*
,当然这使得无法引用该成员该变量指向的对象,因为 int
不是联合或结构,如错误消息所述。此外,您不能将(假定的)int*
分配给 prog
,因为(我猜)prog
是在 ASTnode
声明的程序的一部分中声明的是可见的,所以它实际上是一个指向 ASTnode
.
当您从编译中收到大量错误消息时,从一开始就开始修复通常是个好主意;在某些时候,编译器的错误恢复将开始变得无用,之后的错误消息可能只是人为因素。当您尝试在自己的编译器中实现错误恢复时,您很快就会看到它是如何工作的。
最重要的是,您应该从解析器文件中删除 #include "y.tab.h"
。它只在词法分析器中需要。我怀疑这是否是唯一的错误,但它可能会帮助您推进项目。