Bison/Yacc error: field has incomplete type
up vote
-1
down vote
favorite
I'm trying to make a Cminus compiler and specifically trying to create an AST for it.
In my step3.fl file
%option noyywrap
%{
/* Definitions and statements */
#include "step3.tab.h"
//extern YYSTYPE yylval;
YYSTYPE yylval;
%}
ID {letter}{letter}*
NUM {digit}{digit}*
letter [a-zA-Z]
digit [0-9]
%option noinput nounput
%option yylineno
%option noyywrap
%%
"if" { return T_IF; }
"else" { return T_ELSE; }
"int" { return T_INT; }
"return" { return T_RETURN; }
"void" { return T_VOID; }
"while" { return T_WHILE; }
"+" { return yytext[0]; }
"-" { return yytext[0]; }
"*" { return yytext[0]; }
"/" { return yytext[0]; }
">" { return T_GREAT; }
">=" { return T_GREATEQ; }
"<" { return T_SMALL; }
"<=" { return T_SMALLEQ; }
"==" { return T_COMPARE; }
"!=" { return T_NOTEQ; }
"=" { return yytext[0]; }
";" { return yytext[0]; }
"," { return yytext[0]; }
"(" { return yytext[0]; }
")" { return yytext[0]; }
"[" { return yytext[0]; }
"]" { return yytext[0]; }
"{" { return yytext[0]; }
"}" { return yytext[0]; }
{ID} { yylval.string=strdup(yytext); return T_ID; }
{NUM} { yylval.value=atoi((const char *)yytext); return T_NUM; }
%%
In my step3.y file:
%{
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include "ast.h"
#include "symtable.h"
static int level=0;
static int offset=0;
static int goffset=0;
static int maxoffset=0;
extern int yylex();
extern int yyparse();
extern char *yytext;
extern FILE *yyin;
void yyerror(const char* s);
extern int yylineno;
%}
%start program
%union {
int value;
char *string;
struct ASTnode * node;
enum OPERATORS op;
}
%right "then" T_ELSE
%token T_IF T_ELSE T_INT T_RETURN T_VOID T_WHILE
T_GREAT T_GREATEQ T_SMALL T_SMALLEQ T_NOTEQ T_COMPARE
%token <value> T_NUM
%token <string> T_ID
%type <node> declaration-list declaration var-declaration fun-declaration params
%type <node> param-list param compound-stmt local-declarations statement-list statement expression-stmt
%type <node> selection-stmt iteration-stmt return-stmt expression
%type <node> var simple-expression additive-expression term factor
%type <node> call args arg-list
%type <op> relop addop mulop type-specifier
%%
program:
declaration-list {prog=$1;}
;
declaration-list:
declaration-list declaration { $1->left = $2; $$ = $1; }
| declaration { $$ = $1; }
;
declaration:
var-declaration { $$ = $1; }
| fun-declaration { $$ = $1; }
;
var-declaration:
type-specifier T_ID';'
{
/* search symbol table for ID
insert if not found, then add the pointer from
insertion into the ASTnode to have reference
to the symbol table entry */
if(Search($2,level,0))
{
fprintf(stderr,"ntThe name %s exists at level %d ",$2,level);
fprintf(stderr,"already in the symbol tablen");
fprintf(stderr,"tDuplicate can.t be inserted(found in search)");
yyerror(" ");
exit(1);
}
$$=ASTCreateNode(VARDEC);
$$->name=$2;
/* we use the op to determine its type while printing*/
$$->op=$1;
$$->symbol=Insert($2,$1,0,level,1,offset,NULL);
$$->isType=$1;
offset += 1;
if(offset > maxoffset)
maxoffset = offset;
}
| type-specifier T_ID'['T_NUM']' ';'
{ /* search for symbol, if we find it error*/
if(Search($2,level,0))
{
fprintf(stderr,"ntThe name %s exists at level %d ",$2,level);
fprintf(stderr,"already in the symbol tablen");
fprintf(stderr,"tDuplicate can.t be inserted(found in search)");
yyerror(" ");
exit(1);
}
$$=ASTCreateNode(VARDEC);
$$->name=$2;
/* we use the op to determine its type while printing*/
$$->op=$1;
/* value links to the NUM nod to store the dimension*/
$$->value=$4;
$$->symbol=Insert($2,$1,2,level,$4,offset,NULL);
$$->isType=$1;
offset += $4;
if (offset>maxoffset)
maxoffset = offset;
}
;
type-specifier: T_INT { $$ = INTDEC; }
| T_VOID { $$ = VOIDDEC; }
;
fun-declaration:
type-specifier T_ID '('
{ /*name already used, cant make new dec*/
if(Search($2,level,0))
{
yyerror($2);
yyerror("Name already used ");
exit(1);
}
Insert($2,$1,1,level,1,0,NULL);
goffset=offset;
offset=2;
if(offset>maxoffset)
maxoffset = offset;
}
params
{ /*need the formal params to compare later */
(Search($2,0,0))->fparms = $5;
}
')' compound-stmt
{
$$=ASTCreateNode(FUNCTIONDEC);
$$->name=$2;
/* we use the op to determine its type while printing*/
$$->op=$1;
/* s1 links to the params which can be void
or a paramList */
$$->s1=$5;
/* right links to the compund statement,
called a BLOCK in the enumerated type */
$$->right=$8;
/*get the symbtab entry we made earlier*/
$$->symbol=Search($2,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
{ /* params found */
$$ = $1;
}
| T_VOID
{ /* no params */
$$ = NULL;
}
;
param-list:
param-list',' param
{ /* attach the param to the list */
$1->left=$3;
$$ = $1;
}
| param { $$ = $1; }
;
param:
type-specifier T_ID
{ /*dont want overlap between params and vars*/
if(Search($2,level,0))
{
yyerror($2);
yyerror("tDuplicate can.t be inserted(found in search)");
exit(1);
}
$$ = ASTCreateNode(PARAM);
$$->name=$2;
/* we use the op to determine its type while printing*/
$$->op=$1;
/* if value is 0 it is not an array, used for printing */
$$->value=0;
/*inherit the type*/
$$->isType=$1;
$$->symbol=Insert($2,$1,0,level+1,1,offset,NULL);
offset+=1;
if(offset>maxoffset)
maxoffset = offset;
}
| type-specifier T_ID'['']'
{
if(Search($2,level,0))
{
yyerror($2);
yyerror("tDuplicate can.t be inserted(found in search)");
exit(1);
}
$$ = ASTCreateNode(PARAM);
$$->name=$2;
/* we use the op to determine its type while printing*/
$$->op=$1;
/* there was an array param */
$$->value=1;
/*inherit the type*/
$$->isType=$1;
/*2 is used for IsAFunc to show its an array ref*/
$$->symbol=Insert($2,$1,2,level+1,1,offset,NULL);
offset+=1;
if(offset>maxoffset)
maxoffset = offset;
}
;
compound-stmt:
'{' { level++; } local-declarations statement-list '}'
{
$$=ASTCreateNode(BLOCK);
if($3 == NULL) /*dont add decls if null*/
$$->right=$4;
else {
/* add the stmtList to the end of the localDecls
and then make the link to the right of BLOCK
be the whole decls and stmtList*/
ASTattachleft($3,$4);
$$->right=$3;
}
/*delete the old symbols from this block so they can
be used in a different block later on*/
offset -=Delete(level);
level--;
}
;
local-declarations:
local-declarations var-declaration
{ /*check for null, if not attach it*/
if($1 != NULL){
$1->left=$2;
$$=$1;
}
else
$$=$2;
}
| { $$ = NULL; }
;
statement-list:
statement-list statement
{ /*check for null, if not attch it*/
if($1 != NULL) {
$1->left=$2;
$$=$1;
}
else
$$=$2;
}
| { $$ = NULL; }
;
statement:
expression-stmt
{ /*everything here is just the simplification to general stmt
to be put into a stmtList above */
$$ = $1;
}
| compound-stmt
{
$$ = $1;
}
| selection-stmt
{
$$ = $1;
}
| iteration-stmt
{
$$ = $1;
}
| return-stmt
{
$$ = $1;
}
;
expression-stmt:
expression ';'
{
$$=ASTCreateNode(EXPRSTMT);
$$->right=$1;
$$->isType=$1->isType;
}
| ';' { $$ = NULL; }
;
selection-stmt:
T_IF '('expression')' statement %prec "then"
{
$$ = ASTCreateNode(IFSTMT);
/* right is the expression to be evaluated*/
$$->right=$3;
/* s1 is link to statment (it can be a block)*/
$$->s1=$5;
}
| T_IF '('expression')' statement T_ELSE statement
{
$$ = ASTCreateNode(IFSTMT);
/* right is the expression to be evaluated*/
$$->right=$3;
/* s1 is link to statment (it can be a block)*/
$$->s1=$5;
/* s2 holds the link to the else statment (can be a block)*/
$$->s2=$7;
}
;
iteration-stmt:
T_WHILE '('expression')' statement
{
$$ = ASTCreateNode(ITERSTMT);
/* right holds expression to be evaluated*/
$$->right=$3;
/* s1 holds the stmt to execute, can be block*/
$$->s1=$5;
}
;
return-stmt:
T_RETURN ';' {$$ = ASTCreateNode(RETURNSTMT);}
| T_RETURN expression';'
{
$$ = ASTCreateNode(RETURNSTMT);
/*expression to return*/
$$->s2=$2;
}
;
expression:
var '=' expression
{
/*we dont have to check both for void because if only one
is void there will be a type mismatch, otherwise they are
the same. So if one is void the other is also*/
if (($1->isType != $3->isType) || ($1->isType == VOIDDEC))
{
yyerror("Type mismatch or void in Assignment");
exit(1);
}
$$=ASTCreateNode(ASSIGN);
/* hold the link to the var node*/
$$->right=$1;
/* hold the link to the expression statement*/
$$->s1=$3;
/*inherit the type, already check for equivalence
so can just use $1*/
$$->isType=$1->isType;
$$->name=CreateTemp();
$$->symbol=Insert($$->name,$$->isType,0,level,1,offset,NULL);
offset+=1;
if(offset>maxoffset)
maxoffset = offset;
}
| simple-expression {$$ = $1;}
;
var:
T_ID
{
struct SymbTab * p;
if ((p=Search($1,level,1)) != NULL)
{
$$ = ASTCreateNode(IDENT);
$$->name=$1;
$$->symbol=p;
/*give the node op Type, based on SymbTab*/
$$->isType=p->Type;
if (p->IsAFunc == 2)
{
yyerror($1);
yyerror("Variable is an array, syntax error");
}
}
else
{
yyerror($1);
yyerror("undeclared variable used");
exit(1);
}
}
| T_ID '['expression']'
{
struct SymbTab * p;
if ((p=Search($1,level,1)) != NULL)
{
$$ = ASTCreateNode(IDENT);
$$->name=$1;
/* hold expression inside of array reference */
$$->right=$3;
$$->symbol=p;
/*capital Type is enum op*/
$$->isType=p->Type;
if (p->IsAFunc != 2)
{
yyerror($1);
yyerror("Variable is not an array, syntax error");
}
}
else
{
yyerror($1);
yyerror("undeclared variable used");
exit(1);
}
}
;
simple-expression:
additive-expression relop additive-expression
{ /* must ensure it is left recursive, to work properly */
/*we dont have to check both for void because if only one
is void there will be a type mismatch, otherwise they are
the same. So if one is void the other is also*/
if (($1->isType != $3->isType) || ($1->isType == VOIDDEC))
{
yyerror("Type mismatch or void in simpleExpression");
exit(1);
}
$$ = ASTCreateNode(EXPR);
$$->op=$2;
$$->left=$1;
$$->right=$3;
/*inherit the type, already check for equivalence
so can just use $1*/
$$->isType=$1->isType;
$$->name=CreateTemp();
$$->symbol=Insert($$->name,$$->isType,0,level,1,offset,NULL);
offset+=1;
if(offset>maxoffset)
maxoffset = offset;
}
| additive-expression {$$ = $1;}
;
relop:
T_SMALLEQ { $$=LESSTHANEQUAL; }
| T_SMALL { $$=LESSTHAN; }
| T_GREAT { $$=GREATERTHAN; }
| T_GREATEQ { $$=GREATERTHANEQUAL; }
| T_COMPARE { $$=EQUAL; }
| T_NOTEQ { $$=NOTEQUAL; }
;
additive-expression:
additive-expression addop term
{ /* must ensure it is left recursive, to work properly */
/*we dont have to check both for void because if only one
is void there will be a type mismatch, otherwise they are
the same. So if one is void the other is also*/
if (($1->isType != $3->isType) || ($1->isType == VOIDDEC))
{
yyerror("Type mismatch or void in additive exp");
exit(1);
}
$$ = ASTCreateNode(EXPR);
$$->op=$2;
$$->left=$1;
$$->right=$3;
/*inherit the type, already check for equivalence
so can just use $1*/
$$->isType=$1->isType;
$$->name=CreateTemp();
$$->symbol=Insert($$->name,$$->isType,0,level,1,offset,NULL);
offset+=1;
if(offset>maxoffset)
maxoffset = offset;
}
| term {$$ = $1;}
;
addop:
'+' { $$ = PLUS; }
| '-' { $$ = MINUS; }
;
term:
term mulop factor
{ /* must ensure it is left recursive, to work properly */
/*we dont have to check both for void because if only one
is void there will be a type mismatch, otherwise they are
the same. So if one is void the other is also*/
if (($1->isType != $3->isType) || ($1->isType == VOIDDEC))
{
yyerror("Type mismatch or void in term/factor exp");
exit(1);
}
$$ = ASTCreateNode(EXPR);
$$->op=$2;
$$->left=$1;
$$->right=$3;
/*inherit the type, already check for equivalence
so can just use $1*/
$$->isType=$1->isType;
$$->name=CreateTemp();
$$->symbol=Insert($$->name,$$->isType,0,level,1,offset,NULL);
offset+=1;
if(offset>maxoffset)
maxoffset = offset;
}
| factor {$$ = $1;}
;
mulop:
'*' { $$ = TIMES; }
| '/' { $$ = DIVIDE; }
;
factor:
'('expression')' {$$ = $2;}
| var { $$ = $1; }
| call { $$ = $1; }
| T_NUM
{
$$=ASTCreateNode(NUMBER);
$$->value=$1;
/*numbers are always ints here*/
$$->isType=INTDEC;
}
;
call:
T_ID '('args')'
{
struct SymbTab * p;
if ((p=Search($1,0,1)) != NULL)
{ /*make sure symbol is a function*/
if(p->IsAFunc != 1)
{
yyerror($1);
yyerror("Is a variable, but was called as function");
exit(1);
}
/*have to make sure we are calling with right params*/
$$=ASTCreateNode(CALLSTMT);
/* hold the link to args in right*/
$$->right=$3;
$$->name=$1;
$$->symbol=p;
$$->isType=p->Type;
}
else
{
yyerror($1);
yyerror("Function not defined in symbol table");
exit(1);
}
}
;
args:
arg-list { $$ = $1; }
| { $$ = NULL; }
;
arg-list:
arg-list',' expression
{ /*attach the expressions to the tree in order
the use of the argList is handled above */
$$=ASTCreateNode(ARGLIST);
$$->left=$3;
$$->right=$1;
}
| expression
{
$$=ASTCreateNode(ARGLIST);
$$->right=$1;
}
;
%%
int main(int argc, char *argv) {
if (argc == 2)
yyin = fopen(argv[1], "r");
else {
printf("No files - Exitn");
exit(1);
}
Display();
yyparse();
ASTprint(0, prog);
return 0;
}
void yyerror(const char* s) {
//fprintf(stderr, "%s-:%d %sn", filename, yylineno, s);
fprintf (stderr,"%s On Line: %dn", s, yylineno);
}
In my ast.h file
#ifndef ASTH
#define ASTH
#include <stdio.h>
#include <malloc.h>
/* define the enumerated types for the AST. THis is used to tell us what
sort of production rule we came across */
/* this is a partial list of NODE types for the ASTNode */
enum ASTtype {
PROGRAM,
VARDEC,
ARGLIST,
IDENT,
BLOCK,
NUMBER,
ASSIGN,
EXPRSTMT,
FUNCTIONDEC,
CALLSTMT,
EXPR,
IFSTMT,
ITERSTMT,
RETURNSTMT,
PARAM,
STRINGNODE
};
enum OPERATORS {
PLUS,
MINUS,
TIMES,
DIVIDE,
LESSTHANEQUAL,
LESSTHAN,
GREATERTHAN,
GREATERTHANEQUAL,
EQUAL,
NOTEQUAL,
INTDEC,
VOIDDEC,
STRINGDEC,
null
};
/* define a type AST node which will hold pointers to AST structs that will
allow us to represent the parsed code
*/
struct ASTnode
{
enum ASTtype type;
enum OPERATORS op;
enum OPERATORS isType;
char * name;
char * str;
int value;
struct SymbTab * symbol;
struct ASTnode *left,*right; /* left is usually the connector for statements */
struct ASTnode *s1,*s2 ; /* used for holding IF and WHILE components -- not very descriptive */
};
struct ASTnode *prog;
//prototypes
struct ASTnode *ASTCreateNode(enum ASTtype mytype);
void ASTattachleft(struct ASTnode *p, struct ASTnode *q);
void ASTprint(int level, struct ASTnode *p);
#endif /* of ASTH */
When I try to compile using these commands:
bison -d step3.y
flex step3.fl
gcc step3.tab.c lex.yy.c -lfl -o a.out
It gives me the following error:
In file included from step3.fl:15:0:
step3.y:39:17: error: field ‘op’ has incomplete type
enum OPERATORS op;
I've looked all over the internet and couldn't find a possibly fix. Can anyone help me with this one?
Thanks in advance.
enums bison yacc c-minus-minus
add a comment |
up vote
-1
down vote
favorite
I'm trying to make a Cminus compiler and specifically trying to create an AST for it.
In my step3.fl file
%option noyywrap
%{
/* Definitions and statements */
#include "step3.tab.h"
//extern YYSTYPE yylval;
YYSTYPE yylval;
%}
ID {letter}{letter}*
NUM {digit}{digit}*
letter [a-zA-Z]
digit [0-9]
%option noinput nounput
%option yylineno
%option noyywrap
%%
"if" { return T_IF; }
"else" { return T_ELSE; }
"int" { return T_INT; }
"return" { return T_RETURN; }
"void" { return T_VOID; }
"while" { return T_WHILE; }
"+" { return yytext[0]; }
"-" { return yytext[0]; }
"*" { return yytext[0]; }
"/" { return yytext[0]; }
">" { return T_GREAT; }
">=" { return T_GREATEQ; }
"<" { return T_SMALL; }
"<=" { return T_SMALLEQ; }
"==" { return T_COMPARE; }
"!=" { return T_NOTEQ; }
"=" { return yytext[0]; }
";" { return yytext[0]; }
"," { return yytext[0]; }
"(" { return yytext[0]; }
")" { return yytext[0]; }
"[" { return yytext[0]; }
"]" { return yytext[0]; }
"{" { return yytext[0]; }
"}" { return yytext[0]; }
{ID} { yylval.string=strdup(yytext); return T_ID; }
{NUM} { yylval.value=atoi((const char *)yytext); return T_NUM; }
%%
In my step3.y file:
%{
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include "ast.h"
#include "symtable.h"
static int level=0;
static int offset=0;
static int goffset=0;
static int maxoffset=0;
extern int yylex();
extern int yyparse();
extern char *yytext;
extern FILE *yyin;
void yyerror(const char* s);
extern int yylineno;
%}
%start program
%union {
int value;
char *string;
struct ASTnode * node;
enum OPERATORS op;
}
%right "then" T_ELSE
%token T_IF T_ELSE T_INT T_RETURN T_VOID T_WHILE
T_GREAT T_GREATEQ T_SMALL T_SMALLEQ T_NOTEQ T_COMPARE
%token <value> T_NUM
%token <string> T_ID
%type <node> declaration-list declaration var-declaration fun-declaration params
%type <node> param-list param compound-stmt local-declarations statement-list statement expression-stmt
%type <node> selection-stmt iteration-stmt return-stmt expression
%type <node> var simple-expression additive-expression term factor
%type <node> call args arg-list
%type <op> relop addop mulop type-specifier
%%
program:
declaration-list {prog=$1;}
;
declaration-list:
declaration-list declaration { $1->left = $2; $$ = $1; }
| declaration { $$ = $1; }
;
declaration:
var-declaration { $$ = $1; }
| fun-declaration { $$ = $1; }
;
var-declaration:
type-specifier T_ID';'
{
/* search symbol table for ID
insert if not found, then add the pointer from
insertion into the ASTnode to have reference
to the symbol table entry */
if(Search($2,level,0))
{
fprintf(stderr,"ntThe name %s exists at level %d ",$2,level);
fprintf(stderr,"already in the symbol tablen");
fprintf(stderr,"tDuplicate can.t be inserted(found in search)");
yyerror(" ");
exit(1);
}
$$=ASTCreateNode(VARDEC);
$$->name=$2;
/* we use the op to determine its type while printing*/
$$->op=$1;
$$->symbol=Insert($2,$1,0,level,1,offset,NULL);
$$->isType=$1;
offset += 1;
if(offset > maxoffset)
maxoffset = offset;
}
| type-specifier T_ID'['T_NUM']' ';'
{ /* search for symbol, if we find it error*/
if(Search($2,level,0))
{
fprintf(stderr,"ntThe name %s exists at level %d ",$2,level);
fprintf(stderr,"already in the symbol tablen");
fprintf(stderr,"tDuplicate can.t be inserted(found in search)");
yyerror(" ");
exit(1);
}
$$=ASTCreateNode(VARDEC);
$$->name=$2;
/* we use the op to determine its type while printing*/
$$->op=$1;
/* value links to the NUM nod to store the dimension*/
$$->value=$4;
$$->symbol=Insert($2,$1,2,level,$4,offset,NULL);
$$->isType=$1;
offset += $4;
if (offset>maxoffset)
maxoffset = offset;
}
;
type-specifier: T_INT { $$ = INTDEC; }
| T_VOID { $$ = VOIDDEC; }
;
fun-declaration:
type-specifier T_ID '('
{ /*name already used, cant make new dec*/
if(Search($2,level,0))
{
yyerror($2);
yyerror("Name already used ");
exit(1);
}
Insert($2,$1,1,level,1,0,NULL);
goffset=offset;
offset=2;
if(offset>maxoffset)
maxoffset = offset;
}
params
{ /*need the formal params to compare later */
(Search($2,0,0))->fparms = $5;
}
')' compound-stmt
{
$$=ASTCreateNode(FUNCTIONDEC);
$$->name=$2;
/* we use the op to determine its type while printing*/
$$->op=$1;
/* s1 links to the params which can be void
or a paramList */
$$->s1=$5;
/* right links to the compund statement,
called a BLOCK in the enumerated type */
$$->right=$8;
/*get the symbtab entry we made earlier*/
$$->symbol=Search($2,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
{ /* params found */
$$ = $1;
}
| T_VOID
{ /* no params */
$$ = NULL;
}
;
param-list:
param-list',' param
{ /* attach the param to the list */
$1->left=$3;
$$ = $1;
}
| param { $$ = $1; }
;
param:
type-specifier T_ID
{ /*dont want overlap between params and vars*/
if(Search($2,level,0))
{
yyerror($2);
yyerror("tDuplicate can.t be inserted(found in search)");
exit(1);
}
$$ = ASTCreateNode(PARAM);
$$->name=$2;
/* we use the op to determine its type while printing*/
$$->op=$1;
/* if value is 0 it is not an array, used for printing */
$$->value=0;
/*inherit the type*/
$$->isType=$1;
$$->symbol=Insert($2,$1,0,level+1,1,offset,NULL);
offset+=1;
if(offset>maxoffset)
maxoffset = offset;
}
| type-specifier T_ID'['']'
{
if(Search($2,level,0))
{
yyerror($2);
yyerror("tDuplicate can.t be inserted(found in search)");
exit(1);
}
$$ = ASTCreateNode(PARAM);
$$->name=$2;
/* we use the op to determine its type while printing*/
$$->op=$1;
/* there was an array param */
$$->value=1;
/*inherit the type*/
$$->isType=$1;
/*2 is used for IsAFunc to show its an array ref*/
$$->symbol=Insert($2,$1,2,level+1,1,offset,NULL);
offset+=1;
if(offset>maxoffset)
maxoffset = offset;
}
;
compound-stmt:
'{' { level++; } local-declarations statement-list '}'
{
$$=ASTCreateNode(BLOCK);
if($3 == NULL) /*dont add decls if null*/
$$->right=$4;
else {
/* add the stmtList to the end of the localDecls
and then make the link to the right of BLOCK
be the whole decls and stmtList*/
ASTattachleft($3,$4);
$$->right=$3;
}
/*delete the old symbols from this block so they can
be used in a different block later on*/
offset -=Delete(level);
level--;
}
;
local-declarations:
local-declarations var-declaration
{ /*check for null, if not attach it*/
if($1 != NULL){
$1->left=$2;
$$=$1;
}
else
$$=$2;
}
| { $$ = NULL; }
;
statement-list:
statement-list statement
{ /*check for null, if not attch it*/
if($1 != NULL) {
$1->left=$2;
$$=$1;
}
else
$$=$2;
}
| { $$ = NULL; }
;
statement:
expression-stmt
{ /*everything here is just the simplification to general stmt
to be put into a stmtList above */
$$ = $1;
}
| compound-stmt
{
$$ = $1;
}
| selection-stmt
{
$$ = $1;
}
| iteration-stmt
{
$$ = $1;
}
| return-stmt
{
$$ = $1;
}
;
expression-stmt:
expression ';'
{
$$=ASTCreateNode(EXPRSTMT);
$$->right=$1;
$$->isType=$1->isType;
}
| ';' { $$ = NULL; }
;
selection-stmt:
T_IF '('expression')' statement %prec "then"
{
$$ = ASTCreateNode(IFSTMT);
/* right is the expression to be evaluated*/
$$->right=$3;
/* s1 is link to statment (it can be a block)*/
$$->s1=$5;
}
| T_IF '('expression')' statement T_ELSE statement
{
$$ = ASTCreateNode(IFSTMT);
/* right is the expression to be evaluated*/
$$->right=$3;
/* s1 is link to statment (it can be a block)*/
$$->s1=$5;
/* s2 holds the link to the else statment (can be a block)*/
$$->s2=$7;
}
;
iteration-stmt:
T_WHILE '('expression')' statement
{
$$ = ASTCreateNode(ITERSTMT);
/* right holds expression to be evaluated*/
$$->right=$3;
/* s1 holds the stmt to execute, can be block*/
$$->s1=$5;
}
;
return-stmt:
T_RETURN ';' {$$ = ASTCreateNode(RETURNSTMT);}
| T_RETURN expression';'
{
$$ = ASTCreateNode(RETURNSTMT);
/*expression to return*/
$$->s2=$2;
}
;
expression:
var '=' expression
{
/*we dont have to check both for void because if only one
is void there will be a type mismatch, otherwise they are
the same. So if one is void the other is also*/
if (($1->isType != $3->isType) || ($1->isType == VOIDDEC))
{
yyerror("Type mismatch or void in Assignment");
exit(1);
}
$$=ASTCreateNode(ASSIGN);
/* hold the link to the var node*/
$$->right=$1;
/* hold the link to the expression statement*/
$$->s1=$3;
/*inherit the type, already check for equivalence
so can just use $1*/
$$->isType=$1->isType;
$$->name=CreateTemp();
$$->symbol=Insert($$->name,$$->isType,0,level,1,offset,NULL);
offset+=1;
if(offset>maxoffset)
maxoffset = offset;
}
| simple-expression {$$ = $1;}
;
var:
T_ID
{
struct SymbTab * p;
if ((p=Search($1,level,1)) != NULL)
{
$$ = ASTCreateNode(IDENT);
$$->name=$1;
$$->symbol=p;
/*give the node op Type, based on SymbTab*/
$$->isType=p->Type;
if (p->IsAFunc == 2)
{
yyerror($1);
yyerror("Variable is an array, syntax error");
}
}
else
{
yyerror($1);
yyerror("undeclared variable used");
exit(1);
}
}
| T_ID '['expression']'
{
struct SymbTab * p;
if ((p=Search($1,level,1)) != NULL)
{
$$ = ASTCreateNode(IDENT);
$$->name=$1;
/* hold expression inside of array reference */
$$->right=$3;
$$->symbol=p;
/*capital Type is enum op*/
$$->isType=p->Type;
if (p->IsAFunc != 2)
{
yyerror($1);
yyerror("Variable is not an array, syntax error");
}
}
else
{
yyerror($1);
yyerror("undeclared variable used");
exit(1);
}
}
;
simple-expression:
additive-expression relop additive-expression
{ /* must ensure it is left recursive, to work properly */
/*we dont have to check both for void because if only one
is void there will be a type mismatch, otherwise they are
the same. So if one is void the other is also*/
if (($1->isType != $3->isType) || ($1->isType == VOIDDEC))
{
yyerror("Type mismatch or void in simpleExpression");
exit(1);
}
$$ = ASTCreateNode(EXPR);
$$->op=$2;
$$->left=$1;
$$->right=$3;
/*inherit the type, already check for equivalence
so can just use $1*/
$$->isType=$1->isType;
$$->name=CreateTemp();
$$->symbol=Insert($$->name,$$->isType,0,level,1,offset,NULL);
offset+=1;
if(offset>maxoffset)
maxoffset = offset;
}
| additive-expression {$$ = $1;}
;
relop:
T_SMALLEQ { $$=LESSTHANEQUAL; }
| T_SMALL { $$=LESSTHAN; }
| T_GREAT { $$=GREATERTHAN; }
| T_GREATEQ { $$=GREATERTHANEQUAL; }
| T_COMPARE { $$=EQUAL; }
| T_NOTEQ { $$=NOTEQUAL; }
;
additive-expression:
additive-expression addop term
{ /* must ensure it is left recursive, to work properly */
/*we dont have to check both for void because if only one
is void there will be a type mismatch, otherwise they are
the same. So if one is void the other is also*/
if (($1->isType != $3->isType) || ($1->isType == VOIDDEC))
{
yyerror("Type mismatch or void in additive exp");
exit(1);
}
$$ = ASTCreateNode(EXPR);
$$->op=$2;
$$->left=$1;
$$->right=$3;
/*inherit the type, already check for equivalence
so can just use $1*/
$$->isType=$1->isType;
$$->name=CreateTemp();
$$->symbol=Insert($$->name,$$->isType,0,level,1,offset,NULL);
offset+=1;
if(offset>maxoffset)
maxoffset = offset;
}
| term {$$ = $1;}
;
addop:
'+' { $$ = PLUS; }
| '-' { $$ = MINUS; }
;
term:
term mulop factor
{ /* must ensure it is left recursive, to work properly */
/*we dont have to check both for void because if only one
is void there will be a type mismatch, otherwise they are
the same. So if one is void the other is also*/
if (($1->isType != $3->isType) || ($1->isType == VOIDDEC))
{
yyerror("Type mismatch or void in term/factor exp");
exit(1);
}
$$ = ASTCreateNode(EXPR);
$$->op=$2;
$$->left=$1;
$$->right=$3;
/*inherit the type, already check for equivalence
so can just use $1*/
$$->isType=$1->isType;
$$->name=CreateTemp();
$$->symbol=Insert($$->name,$$->isType,0,level,1,offset,NULL);
offset+=1;
if(offset>maxoffset)
maxoffset = offset;
}
| factor {$$ = $1;}
;
mulop:
'*' { $$ = TIMES; }
| '/' { $$ = DIVIDE; }
;
factor:
'('expression')' {$$ = $2;}
| var { $$ = $1; }
| call { $$ = $1; }
| T_NUM
{
$$=ASTCreateNode(NUMBER);
$$->value=$1;
/*numbers are always ints here*/
$$->isType=INTDEC;
}
;
call:
T_ID '('args')'
{
struct SymbTab * p;
if ((p=Search($1,0,1)) != NULL)
{ /*make sure symbol is a function*/
if(p->IsAFunc != 1)
{
yyerror($1);
yyerror("Is a variable, but was called as function");
exit(1);
}
/*have to make sure we are calling with right params*/
$$=ASTCreateNode(CALLSTMT);
/* hold the link to args in right*/
$$->right=$3;
$$->name=$1;
$$->symbol=p;
$$->isType=p->Type;
}
else
{
yyerror($1);
yyerror("Function not defined in symbol table");
exit(1);
}
}
;
args:
arg-list { $$ = $1; }
| { $$ = NULL; }
;
arg-list:
arg-list',' expression
{ /*attach the expressions to the tree in order
the use of the argList is handled above */
$$=ASTCreateNode(ARGLIST);
$$->left=$3;
$$->right=$1;
}
| expression
{
$$=ASTCreateNode(ARGLIST);
$$->right=$1;
}
;
%%
int main(int argc, char *argv) {
if (argc == 2)
yyin = fopen(argv[1], "r");
else {
printf("No files - Exitn");
exit(1);
}
Display();
yyparse();
ASTprint(0, prog);
return 0;
}
void yyerror(const char* s) {
//fprintf(stderr, "%s-:%d %sn", filename, yylineno, s);
fprintf (stderr,"%s On Line: %dn", s, yylineno);
}
In my ast.h file
#ifndef ASTH
#define ASTH
#include <stdio.h>
#include <malloc.h>
/* define the enumerated types for the AST. THis is used to tell us what
sort of production rule we came across */
/* this is a partial list of NODE types for the ASTNode */
enum ASTtype {
PROGRAM,
VARDEC,
ARGLIST,
IDENT,
BLOCK,
NUMBER,
ASSIGN,
EXPRSTMT,
FUNCTIONDEC,
CALLSTMT,
EXPR,
IFSTMT,
ITERSTMT,
RETURNSTMT,
PARAM,
STRINGNODE
};
enum OPERATORS {
PLUS,
MINUS,
TIMES,
DIVIDE,
LESSTHANEQUAL,
LESSTHAN,
GREATERTHAN,
GREATERTHANEQUAL,
EQUAL,
NOTEQUAL,
INTDEC,
VOIDDEC,
STRINGDEC,
null
};
/* define a type AST node which will hold pointers to AST structs that will
allow us to represent the parsed code
*/
struct ASTnode
{
enum ASTtype type;
enum OPERATORS op;
enum OPERATORS isType;
char * name;
char * str;
int value;
struct SymbTab * symbol;
struct ASTnode *left,*right; /* left is usually the connector for statements */
struct ASTnode *s1,*s2 ; /* used for holding IF and WHILE components -- not very descriptive */
};
struct ASTnode *prog;
//prototypes
struct ASTnode *ASTCreateNode(enum ASTtype mytype);
void ASTattachleft(struct ASTnode *p, struct ASTnode *q);
void ASTprint(int level, struct ASTnode *p);
#endif /* of ASTH */
When I try to compile using these commands:
bison -d step3.y
flex step3.fl
gcc step3.tab.c lex.yy.c -lfl -o a.out
It gives me the following error:
In file included from step3.fl:15:0:
step3.y:39:17: error: field ‘op’ has incomplete type
enum OPERATORS op;
I've looked all over the internet and couldn't find a possibly fix. Can anyone help me with this one?
Thanks in advance.
enums bison yacc c-minus-minus
Please include enough code in your question to reproduce the problem. From the error message, I assume your lexer includesstep3.tab.h
, correct? And I further assumestep3.y
includesast.h
- if so, in which section? Also: in your compilation steps, isfile
actually a "stand in" forstep3
or do you have multiple.y
and.fl
files and the error is coming from different ones than the ones you are compiling?
– sepp2k
Nov 4 at 14:22
@sepp2k You are correct. I've edited my question to include more code.
– PiguFilms
Nov 4 at 14:44
add a comment |
up vote
-1
down vote
favorite
up vote
-1
down vote
favorite
I'm trying to make a Cminus compiler and specifically trying to create an AST for it.
In my step3.fl file
%option noyywrap
%{
/* Definitions and statements */
#include "step3.tab.h"
//extern YYSTYPE yylval;
YYSTYPE yylval;
%}
ID {letter}{letter}*
NUM {digit}{digit}*
letter [a-zA-Z]
digit [0-9]
%option noinput nounput
%option yylineno
%option noyywrap
%%
"if" { return T_IF; }
"else" { return T_ELSE; }
"int" { return T_INT; }
"return" { return T_RETURN; }
"void" { return T_VOID; }
"while" { return T_WHILE; }
"+" { return yytext[0]; }
"-" { return yytext[0]; }
"*" { return yytext[0]; }
"/" { return yytext[0]; }
">" { return T_GREAT; }
">=" { return T_GREATEQ; }
"<" { return T_SMALL; }
"<=" { return T_SMALLEQ; }
"==" { return T_COMPARE; }
"!=" { return T_NOTEQ; }
"=" { return yytext[0]; }
";" { return yytext[0]; }
"," { return yytext[0]; }
"(" { return yytext[0]; }
")" { return yytext[0]; }
"[" { return yytext[0]; }
"]" { return yytext[0]; }
"{" { return yytext[0]; }
"}" { return yytext[0]; }
{ID} { yylval.string=strdup(yytext); return T_ID; }
{NUM} { yylval.value=atoi((const char *)yytext); return T_NUM; }
%%
In my step3.y file:
%{
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include "ast.h"
#include "symtable.h"
static int level=0;
static int offset=0;
static int goffset=0;
static int maxoffset=0;
extern int yylex();
extern int yyparse();
extern char *yytext;
extern FILE *yyin;
void yyerror(const char* s);
extern int yylineno;
%}
%start program
%union {
int value;
char *string;
struct ASTnode * node;
enum OPERATORS op;
}
%right "then" T_ELSE
%token T_IF T_ELSE T_INT T_RETURN T_VOID T_WHILE
T_GREAT T_GREATEQ T_SMALL T_SMALLEQ T_NOTEQ T_COMPARE
%token <value> T_NUM
%token <string> T_ID
%type <node> declaration-list declaration var-declaration fun-declaration params
%type <node> param-list param compound-stmt local-declarations statement-list statement expression-stmt
%type <node> selection-stmt iteration-stmt return-stmt expression
%type <node> var simple-expression additive-expression term factor
%type <node> call args arg-list
%type <op> relop addop mulop type-specifier
%%
program:
declaration-list {prog=$1;}
;
declaration-list:
declaration-list declaration { $1->left = $2; $$ = $1; }
| declaration { $$ = $1; }
;
declaration:
var-declaration { $$ = $1; }
| fun-declaration { $$ = $1; }
;
var-declaration:
type-specifier T_ID';'
{
/* search symbol table for ID
insert if not found, then add the pointer from
insertion into the ASTnode to have reference
to the symbol table entry */
if(Search($2,level,0))
{
fprintf(stderr,"ntThe name %s exists at level %d ",$2,level);
fprintf(stderr,"already in the symbol tablen");
fprintf(stderr,"tDuplicate can.t be inserted(found in search)");
yyerror(" ");
exit(1);
}
$$=ASTCreateNode(VARDEC);
$$->name=$2;
/* we use the op to determine its type while printing*/
$$->op=$1;
$$->symbol=Insert($2,$1,0,level,1,offset,NULL);
$$->isType=$1;
offset += 1;
if(offset > maxoffset)
maxoffset = offset;
}
| type-specifier T_ID'['T_NUM']' ';'
{ /* search for symbol, if we find it error*/
if(Search($2,level,0))
{
fprintf(stderr,"ntThe name %s exists at level %d ",$2,level);
fprintf(stderr,"already in the symbol tablen");
fprintf(stderr,"tDuplicate can.t be inserted(found in search)");
yyerror(" ");
exit(1);
}
$$=ASTCreateNode(VARDEC);
$$->name=$2;
/* we use the op to determine its type while printing*/
$$->op=$1;
/* value links to the NUM nod to store the dimension*/
$$->value=$4;
$$->symbol=Insert($2,$1,2,level,$4,offset,NULL);
$$->isType=$1;
offset += $4;
if (offset>maxoffset)
maxoffset = offset;
}
;
type-specifier: T_INT { $$ = INTDEC; }
| T_VOID { $$ = VOIDDEC; }
;
fun-declaration:
type-specifier T_ID '('
{ /*name already used, cant make new dec*/
if(Search($2,level,0))
{
yyerror($2);
yyerror("Name already used ");
exit(1);
}
Insert($2,$1,1,level,1,0,NULL);
goffset=offset;
offset=2;
if(offset>maxoffset)
maxoffset = offset;
}
params
{ /*need the formal params to compare later */
(Search($2,0,0))->fparms = $5;
}
')' compound-stmt
{
$$=ASTCreateNode(FUNCTIONDEC);
$$->name=$2;
/* we use the op to determine its type while printing*/
$$->op=$1;
/* s1 links to the params which can be void
or a paramList */
$$->s1=$5;
/* right links to the compund statement,
called a BLOCK in the enumerated type */
$$->right=$8;
/*get the symbtab entry we made earlier*/
$$->symbol=Search($2,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
{ /* params found */
$$ = $1;
}
| T_VOID
{ /* no params */
$$ = NULL;
}
;
param-list:
param-list',' param
{ /* attach the param to the list */
$1->left=$3;
$$ = $1;
}
| param { $$ = $1; }
;
param:
type-specifier T_ID
{ /*dont want overlap between params and vars*/
if(Search($2,level,0))
{
yyerror($2);
yyerror("tDuplicate can.t be inserted(found in search)");
exit(1);
}
$$ = ASTCreateNode(PARAM);
$$->name=$2;
/* we use the op to determine its type while printing*/
$$->op=$1;
/* if value is 0 it is not an array, used for printing */
$$->value=0;
/*inherit the type*/
$$->isType=$1;
$$->symbol=Insert($2,$1,0,level+1,1,offset,NULL);
offset+=1;
if(offset>maxoffset)
maxoffset = offset;
}
| type-specifier T_ID'['']'
{
if(Search($2,level,0))
{
yyerror($2);
yyerror("tDuplicate can.t be inserted(found in search)");
exit(1);
}
$$ = ASTCreateNode(PARAM);
$$->name=$2;
/* we use the op to determine its type while printing*/
$$->op=$1;
/* there was an array param */
$$->value=1;
/*inherit the type*/
$$->isType=$1;
/*2 is used for IsAFunc to show its an array ref*/
$$->symbol=Insert($2,$1,2,level+1,1,offset,NULL);
offset+=1;
if(offset>maxoffset)
maxoffset = offset;
}
;
compound-stmt:
'{' { level++; } local-declarations statement-list '}'
{
$$=ASTCreateNode(BLOCK);
if($3 == NULL) /*dont add decls if null*/
$$->right=$4;
else {
/* add the stmtList to the end of the localDecls
and then make the link to the right of BLOCK
be the whole decls and stmtList*/
ASTattachleft($3,$4);
$$->right=$3;
}
/*delete the old symbols from this block so they can
be used in a different block later on*/
offset -=Delete(level);
level--;
}
;
local-declarations:
local-declarations var-declaration
{ /*check for null, if not attach it*/
if($1 != NULL){
$1->left=$2;
$$=$1;
}
else
$$=$2;
}
| { $$ = NULL; }
;
statement-list:
statement-list statement
{ /*check for null, if not attch it*/
if($1 != NULL) {
$1->left=$2;
$$=$1;
}
else
$$=$2;
}
| { $$ = NULL; }
;
statement:
expression-stmt
{ /*everything here is just the simplification to general stmt
to be put into a stmtList above */
$$ = $1;
}
| compound-stmt
{
$$ = $1;
}
| selection-stmt
{
$$ = $1;
}
| iteration-stmt
{
$$ = $1;
}
| return-stmt
{
$$ = $1;
}
;
expression-stmt:
expression ';'
{
$$=ASTCreateNode(EXPRSTMT);
$$->right=$1;
$$->isType=$1->isType;
}
| ';' { $$ = NULL; }
;
selection-stmt:
T_IF '('expression')' statement %prec "then"
{
$$ = ASTCreateNode(IFSTMT);
/* right is the expression to be evaluated*/
$$->right=$3;
/* s1 is link to statment (it can be a block)*/
$$->s1=$5;
}
| T_IF '('expression')' statement T_ELSE statement
{
$$ = ASTCreateNode(IFSTMT);
/* right is the expression to be evaluated*/
$$->right=$3;
/* s1 is link to statment (it can be a block)*/
$$->s1=$5;
/* s2 holds the link to the else statment (can be a block)*/
$$->s2=$7;
}
;
iteration-stmt:
T_WHILE '('expression')' statement
{
$$ = ASTCreateNode(ITERSTMT);
/* right holds expression to be evaluated*/
$$->right=$3;
/* s1 holds the stmt to execute, can be block*/
$$->s1=$5;
}
;
return-stmt:
T_RETURN ';' {$$ = ASTCreateNode(RETURNSTMT);}
| T_RETURN expression';'
{
$$ = ASTCreateNode(RETURNSTMT);
/*expression to return*/
$$->s2=$2;
}
;
expression:
var '=' expression
{
/*we dont have to check both for void because if only one
is void there will be a type mismatch, otherwise they are
the same. So if one is void the other is also*/
if (($1->isType != $3->isType) || ($1->isType == VOIDDEC))
{
yyerror("Type mismatch or void in Assignment");
exit(1);
}
$$=ASTCreateNode(ASSIGN);
/* hold the link to the var node*/
$$->right=$1;
/* hold the link to the expression statement*/
$$->s1=$3;
/*inherit the type, already check for equivalence
so can just use $1*/
$$->isType=$1->isType;
$$->name=CreateTemp();
$$->symbol=Insert($$->name,$$->isType,0,level,1,offset,NULL);
offset+=1;
if(offset>maxoffset)
maxoffset = offset;
}
| simple-expression {$$ = $1;}
;
var:
T_ID
{
struct SymbTab * p;
if ((p=Search($1,level,1)) != NULL)
{
$$ = ASTCreateNode(IDENT);
$$->name=$1;
$$->symbol=p;
/*give the node op Type, based on SymbTab*/
$$->isType=p->Type;
if (p->IsAFunc == 2)
{
yyerror($1);
yyerror("Variable is an array, syntax error");
}
}
else
{
yyerror($1);
yyerror("undeclared variable used");
exit(1);
}
}
| T_ID '['expression']'
{
struct SymbTab * p;
if ((p=Search($1,level,1)) != NULL)
{
$$ = ASTCreateNode(IDENT);
$$->name=$1;
/* hold expression inside of array reference */
$$->right=$3;
$$->symbol=p;
/*capital Type is enum op*/
$$->isType=p->Type;
if (p->IsAFunc != 2)
{
yyerror($1);
yyerror("Variable is not an array, syntax error");
}
}
else
{
yyerror($1);
yyerror("undeclared variable used");
exit(1);
}
}
;
simple-expression:
additive-expression relop additive-expression
{ /* must ensure it is left recursive, to work properly */
/*we dont have to check both for void because if only one
is void there will be a type mismatch, otherwise they are
the same. So if one is void the other is also*/
if (($1->isType != $3->isType) || ($1->isType == VOIDDEC))
{
yyerror("Type mismatch or void in simpleExpression");
exit(1);
}
$$ = ASTCreateNode(EXPR);
$$->op=$2;
$$->left=$1;
$$->right=$3;
/*inherit the type, already check for equivalence
so can just use $1*/
$$->isType=$1->isType;
$$->name=CreateTemp();
$$->symbol=Insert($$->name,$$->isType,0,level,1,offset,NULL);
offset+=1;
if(offset>maxoffset)
maxoffset = offset;
}
| additive-expression {$$ = $1;}
;
relop:
T_SMALLEQ { $$=LESSTHANEQUAL; }
| T_SMALL { $$=LESSTHAN; }
| T_GREAT { $$=GREATERTHAN; }
| T_GREATEQ { $$=GREATERTHANEQUAL; }
| T_COMPARE { $$=EQUAL; }
| T_NOTEQ { $$=NOTEQUAL; }
;
additive-expression:
additive-expression addop term
{ /* must ensure it is left recursive, to work properly */
/*we dont have to check both for void because if only one
is void there will be a type mismatch, otherwise they are
the same. So if one is void the other is also*/
if (($1->isType != $3->isType) || ($1->isType == VOIDDEC))
{
yyerror("Type mismatch or void in additive exp");
exit(1);
}
$$ = ASTCreateNode(EXPR);
$$->op=$2;
$$->left=$1;
$$->right=$3;
/*inherit the type, already check for equivalence
so can just use $1*/
$$->isType=$1->isType;
$$->name=CreateTemp();
$$->symbol=Insert($$->name,$$->isType,0,level,1,offset,NULL);
offset+=1;
if(offset>maxoffset)
maxoffset = offset;
}
| term {$$ = $1;}
;
addop:
'+' { $$ = PLUS; }
| '-' { $$ = MINUS; }
;
term:
term mulop factor
{ /* must ensure it is left recursive, to work properly */
/*we dont have to check both for void because if only one
is void there will be a type mismatch, otherwise they are
the same. So if one is void the other is also*/
if (($1->isType != $3->isType) || ($1->isType == VOIDDEC))
{
yyerror("Type mismatch or void in term/factor exp");
exit(1);
}
$$ = ASTCreateNode(EXPR);
$$->op=$2;
$$->left=$1;
$$->right=$3;
/*inherit the type, already check for equivalence
so can just use $1*/
$$->isType=$1->isType;
$$->name=CreateTemp();
$$->symbol=Insert($$->name,$$->isType,0,level,1,offset,NULL);
offset+=1;
if(offset>maxoffset)
maxoffset = offset;
}
| factor {$$ = $1;}
;
mulop:
'*' { $$ = TIMES; }
| '/' { $$ = DIVIDE; }
;
factor:
'('expression')' {$$ = $2;}
| var { $$ = $1; }
| call { $$ = $1; }
| T_NUM
{
$$=ASTCreateNode(NUMBER);
$$->value=$1;
/*numbers are always ints here*/
$$->isType=INTDEC;
}
;
call:
T_ID '('args')'
{
struct SymbTab * p;
if ((p=Search($1,0,1)) != NULL)
{ /*make sure symbol is a function*/
if(p->IsAFunc != 1)
{
yyerror($1);
yyerror("Is a variable, but was called as function");
exit(1);
}
/*have to make sure we are calling with right params*/
$$=ASTCreateNode(CALLSTMT);
/* hold the link to args in right*/
$$->right=$3;
$$->name=$1;
$$->symbol=p;
$$->isType=p->Type;
}
else
{
yyerror($1);
yyerror("Function not defined in symbol table");
exit(1);
}
}
;
args:
arg-list { $$ = $1; }
| { $$ = NULL; }
;
arg-list:
arg-list',' expression
{ /*attach the expressions to the tree in order
the use of the argList is handled above */
$$=ASTCreateNode(ARGLIST);
$$->left=$3;
$$->right=$1;
}
| expression
{
$$=ASTCreateNode(ARGLIST);
$$->right=$1;
}
;
%%
int main(int argc, char *argv) {
if (argc == 2)
yyin = fopen(argv[1], "r");
else {
printf("No files - Exitn");
exit(1);
}
Display();
yyparse();
ASTprint(0, prog);
return 0;
}
void yyerror(const char* s) {
//fprintf(stderr, "%s-:%d %sn", filename, yylineno, s);
fprintf (stderr,"%s On Line: %dn", s, yylineno);
}
In my ast.h file
#ifndef ASTH
#define ASTH
#include <stdio.h>
#include <malloc.h>
/* define the enumerated types for the AST. THis is used to tell us what
sort of production rule we came across */
/* this is a partial list of NODE types for the ASTNode */
enum ASTtype {
PROGRAM,
VARDEC,
ARGLIST,
IDENT,
BLOCK,
NUMBER,
ASSIGN,
EXPRSTMT,
FUNCTIONDEC,
CALLSTMT,
EXPR,
IFSTMT,
ITERSTMT,
RETURNSTMT,
PARAM,
STRINGNODE
};
enum OPERATORS {
PLUS,
MINUS,
TIMES,
DIVIDE,
LESSTHANEQUAL,
LESSTHAN,
GREATERTHAN,
GREATERTHANEQUAL,
EQUAL,
NOTEQUAL,
INTDEC,
VOIDDEC,
STRINGDEC,
null
};
/* define a type AST node which will hold pointers to AST structs that will
allow us to represent the parsed code
*/
struct ASTnode
{
enum ASTtype type;
enum OPERATORS op;
enum OPERATORS isType;
char * name;
char * str;
int value;
struct SymbTab * symbol;
struct ASTnode *left,*right; /* left is usually the connector for statements */
struct ASTnode *s1,*s2 ; /* used for holding IF and WHILE components -- not very descriptive */
};
struct ASTnode *prog;
//prototypes
struct ASTnode *ASTCreateNode(enum ASTtype mytype);
void ASTattachleft(struct ASTnode *p, struct ASTnode *q);
void ASTprint(int level, struct ASTnode *p);
#endif /* of ASTH */
When I try to compile using these commands:
bison -d step3.y
flex step3.fl
gcc step3.tab.c lex.yy.c -lfl -o a.out
It gives me the following error:
In file included from step3.fl:15:0:
step3.y:39:17: error: field ‘op’ has incomplete type
enum OPERATORS op;
I've looked all over the internet and couldn't find a possibly fix. Can anyone help me with this one?
Thanks in advance.
enums bison yacc c-minus-minus
I'm trying to make a Cminus compiler and specifically trying to create an AST for it.
In my step3.fl file
%option noyywrap
%{
/* Definitions and statements */
#include "step3.tab.h"
//extern YYSTYPE yylval;
YYSTYPE yylval;
%}
ID {letter}{letter}*
NUM {digit}{digit}*
letter [a-zA-Z]
digit [0-9]
%option noinput nounput
%option yylineno
%option noyywrap
%%
"if" { return T_IF; }
"else" { return T_ELSE; }
"int" { return T_INT; }
"return" { return T_RETURN; }
"void" { return T_VOID; }
"while" { return T_WHILE; }
"+" { return yytext[0]; }
"-" { return yytext[0]; }
"*" { return yytext[0]; }
"/" { return yytext[0]; }
">" { return T_GREAT; }
">=" { return T_GREATEQ; }
"<" { return T_SMALL; }
"<=" { return T_SMALLEQ; }
"==" { return T_COMPARE; }
"!=" { return T_NOTEQ; }
"=" { return yytext[0]; }
";" { return yytext[0]; }
"," { return yytext[0]; }
"(" { return yytext[0]; }
")" { return yytext[0]; }
"[" { return yytext[0]; }
"]" { return yytext[0]; }
"{" { return yytext[0]; }
"}" { return yytext[0]; }
{ID} { yylval.string=strdup(yytext); return T_ID; }
{NUM} { yylval.value=atoi((const char *)yytext); return T_NUM; }
%%
In my step3.y file:
%{
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include "ast.h"
#include "symtable.h"
static int level=0;
static int offset=0;
static int goffset=0;
static int maxoffset=0;
extern int yylex();
extern int yyparse();
extern char *yytext;
extern FILE *yyin;
void yyerror(const char* s);
extern int yylineno;
%}
%start program
%union {
int value;
char *string;
struct ASTnode * node;
enum OPERATORS op;
}
%right "then" T_ELSE
%token T_IF T_ELSE T_INT T_RETURN T_VOID T_WHILE
T_GREAT T_GREATEQ T_SMALL T_SMALLEQ T_NOTEQ T_COMPARE
%token <value> T_NUM
%token <string> T_ID
%type <node> declaration-list declaration var-declaration fun-declaration params
%type <node> param-list param compound-stmt local-declarations statement-list statement expression-stmt
%type <node> selection-stmt iteration-stmt return-stmt expression
%type <node> var simple-expression additive-expression term factor
%type <node> call args arg-list
%type <op> relop addop mulop type-specifier
%%
program:
declaration-list {prog=$1;}
;
declaration-list:
declaration-list declaration { $1->left = $2; $$ = $1; }
| declaration { $$ = $1; }
;
declaration:
var-declaration { $$ = $1; }
| fun-declaration { $$ = $1; }
;
var-declaration:
type-specifier T_ID';'
{
/* search symbol table for ID
insert if not found, then add the pointer from
insertion into the ASTnode to have reference
to the symbol table entry */
if(Search($2,level,0))
{
fprintf(stderr,"ntThe name %s exists at level %d ",$2,level);
fprintf(stderr,"already in the symbol tablen");
fprintf(stderr,"tDuplicate can.t be inserted(found in search)");
yyerror(" ");
exit(1);
}
$$=ASTCreateNode(VARDEC);
$$->name=$2;
/* we use the op to determine its type while printing*/
$$->op=$1;
$$->symbol=Insert($2,$1,0,level,1,offset,NULL);
$$->isType=$1;
offset += 1;
if(offset > maxoffset)
maxoffset = offset;
}
| type-specifier T_ID'['T_NUM']' ';'
{ /* search for symbol, if we find it error*/
if(Search($2,level,0))
{
fprintf(stderr,"ntThe name %s exists at level %d ",$2,level);
fprintf(stderr,"already in the symbol tablen");
fprintf(stderr,"tDuplicate can.t be inserted(found in search)");
yyerror(" ");
exit(1);
}
$$=ASTCreateNode(VARDEC);
$$->name=$2;
/* we use the op to determine its type while printing*/
$$->op=$1;
/* value links to the NUM nod to store the dimension*/
$$->value=$4;
$$->symbol=Insert($2,$1,2,level,$4,offset,NULL);
$$->isType=$1;
offset += $4;
if (offset>maxoffset)
maxoffset = offset;
}
;
type-specifier: T_INT { $$ = INTDEC; }
| T_VOID { $$ = VOIDDEC; }
;
fun-declaration:
type-specifier T_ID '('
{ /*name already used, cant make new dec*/
if(Search($2,level,0))
{
yyerror($2);
yyerror("Name already used ");
exit(1);
}
Insert($2,$1,1,level,1,0,NULL);
goffset=offset;
offset=2;
if(offset>maxoffset)
maxoffset = offset;
}
params
{ /*need the formal params to compare later */
(Search($2,0,0))->fparms = $5;
}
')' compound-stmt
{
$$=ASTCreateNode(FUNCTIONDEC);
$$->name=$2;
/* we use the op to determine its type while printing*/
$$->op=$1;
/* s1 links to the params which can be void
or a paramList */
$$->s1=$5;
/* right links to the compund statement,
called a BLOCK in the enumerated type */
$$->right=$8;
/*get the symbtab entry we made earlier*/
$$->symbol=Search($2,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
{ /* params found */
$$ = $1;
}
| T_VOID
{ /* no params */
$$ = NULL;
}
;
param-list:
param-list',' param
{ /* attach the param to the list */
$1->left=$3;
$$ = $1;
}
| param { $$ = $1; }
;
param:
type-specifier T_ID
{ /*dont want overlap between params and vars*/
if(Search($2,level,0))
{
yyerror($2);
yyerror("tDuplicate can.t be inserted(found in search)");
exit(1);
}
$$ = ASTCreateNode(PARAM);
$$->name=$2;
/* we use the op to determine its type while printing*/
$$->op=$1;
/* if value is 0 it is not an array, used for printing */
$$->value=0;
/*inherit the type*/
$$->isType=$1;
$$->symbol=Insert($2,$1,0,level+1,1,offset,NULL);
offset+=1;
if(offset>maxoffset)
maxoffset = offset;
}
| type-specifier T_ID'['']'
{
if(Search($2,level,0))
{
yyerror($2);
yyerror("tDuplicate can.t be inserted(found in search)");
exit(1);
}
$$ = ASTCreateNode(PARAM);
$$->name=$2;
/* we use the op to determine its type while printing*/
$$->op=$1;
/* there was an array param */
$$->value=1;
/*inherit the type*/
$$->isType=$1;
/*2 is used for IsAFunc to show its an array ref*/
$$->symbol=Insert($2,$1,2,level+1,1,offset,NULL);
offset+=1;
if(offset>maxoffset)
maxoffset = offset;
}
;
compound-stmt:
'{' { level++; } local-declarations statement-list '}'
{
$$=ASTCreateNode(BLOCK);
if($3 == NULL) /*dont add decls if null*/
$$->right=$4;
else {
/* add the stmtList to the end of the localDecls
and then make the link to the right of BLOCK
be the whole decls and stmtList*/
ASTattachleft($3,$4);
$$->right=$3;
}
/*delete the old symbols from this block so they can
be used in a different block later on*/
offset -=Delete(level);
level--;
}
;
local-declarations:
local-declarations var-declaration
{ /*check for null, if not attach it*/
if($1 != NULL){
$1->left=$2;
$$=$1;
}
else
$$=$2;
}
| { $$ = NULL; }
;
statement-list:
statement-list statement
{ /*check for null, if not attch it*/
if($1 != NULL) {
$1->left=$2;
$$=$1;
}
else
$$=$2;
}
| { $$ = NULL; }
;
statement:
expression-stmt
{ /*everything here is just the simplification to general stmt
to be put into a stmtList above */
$$ = $1;
}
| compound-stmt
{
$$ = $1;
}
| selection-stmt
{
$$ = $1;
}
| iteration-stmt
{
$$ = $1;
}
| return-stmt
{
$$ = $1;
}
;
expression-stmt:
expression ';'
{
$$=ASTCreateNode(EXPRSTMT);
$$->right=$1;
$$->isType=$1->isType;
}
| ';' { $$ = NULL; }
;
selection-stmt:
T_IF '('expression')' statement %prec "then"
{
$$ = ASTCreateNode(IFSTMT);
/* right is the expression to be evaluated*/
$$->right=$3;
/* s1 is link to statment (it can be a block)*/
$$->s1=$5;
}
| T_IF '('expression')' statement T_ELSE statement
{
$$ = ASTCreateNode(IFSTMT);
/* right is the expression to be evaluated*/
$$->right=$3;
/* s1 is link to statment (it can be a block)*/
$$->s1=$5;
/* s2 holds the link to the else statment (can be a block)*/
$$->s2=$7;
}
;
iteration-stmt:
T_WHILE '('expression')' statement
{
$$ = ASTCreateNode(ITERSTMT);
/* right holds expression to be evaluated*/
$$->right=$3;
/* s1 holds the stmt to execute, can be block*/
$$->s1=$5;
}
;
return-stmt:
T_RETURN ';' {$$ = ASTCreateNode(RETURNSTMT);}
| T_RETURN expression';'
{
$$ = ASTCreateNode(RETURNSTMT);
/*expression to return*/
$$->s2=$2;
}
;
expression:
var '=' expression
{
/*we dont have to check both for void because if only one
is void there will be a type mismatch, otherwise they are
the same. So if one is void the other is also*/
if (($1->isType != $3->isType) || ($1->isType == VOIDDEC))
{
yyerror("Type mismatch or void in Assignment");
exit(1);
}
$$=ASTCreateNode(ASSIGN);
/* hold the link to the var node*/
$$->right=$1;
/* hold the link to the expression statement*/
$$->s1=$3;
/*inherit the type, already check for equivalence
so can just use $1*/
$$->isType=$1->isType;
$$->name=CreateTemp();
$$->symbol=Insert($$->name,$$->isType,0,level,1,offset,NULL);
offset+=1;
if(offset>maxoffset)
maxoffset = offset;
}
| simple-expression {$$ = $1;}
;
var:
T_ID
{
struct SymbTab * p;
if ((p=Search($1,level,1)) != NULL)
{
$$ = ASTCreateNode(IDENT);
$$->name=$1;
$$->symbol=p;
/*give the node op Type, based on SymbTab*/
$$->isType=p->Type;
if (p->IsAFunc == 2)
{
yyerror($1);
yyerror("Variable is an array, syntax error");
}
}
else
{
yyerror($1);
yyerror("undeclared variable used");
exit(1);
}
}
| T_ID '['expression']'
{
struct SymbTab * p;
if ((p=Search($1,level,1)) != NULL)
{
$$ = ASTCreateNode(IDENT);
$$->name=$1;
/* hold expression inside of array reference */
$$->right=$3;
$$->symbol=p;
/*capital Type is enum op*/
$$->isType=p->Type;
if (p->IsAFunc != 2)
{
yyerror($1);
yyerror("Variable is not an array, syntax error");
}
}
else
{
yyerror($1);
yyerror("undeclared variable used");
exit(1);
}
}
;
simple-expression:
additive-expression relop additive-expression
{ /* must ensure it is left recursive, to work properly */
/*we dont have to check both for void because if only one
is void there will be a type mismatch, otherwise they are
the same. So if one is void the other is also*/
if (($1->isType != $3->isType) || ($1->isType == VOIDDEC))
{
yyerror("Type mismatch or void in simpleExpression");
exit(1);
}
$$ = ASTCreateNode(EXPR);
$$->op=$2;
$$->left=$1;
$$->right=$3;
/*inherit the type, already check for equivalence
so can just use $1*/
$$->isType=$1->isType;
$$->name=CreateTemp();
$$->symbol=Insert($$->name,$$->isType,0,level,1,offset,NULL);
offset+=1;
if(offset>maxoffset)
maxoffset = offset;
}
| additive-expression {$$ = $1;}
;
relop:
T_SMALLEQ { $$=LESSTHANEQUAL; }
| T_SMALL { $$=LESSTHAN; }
| T_GREAT { $$=GREATERTHAN; }
| T_GREATEQ { $$=GREATERTHANEQUAL; }
| T_COMPARE { $$=EQUAL; }
| T_NOTEQ { $$=NOTEQUAL; }
;
additive-expression:
additive-expression addop term
{ /* must ensure it is left recursive, to work properly */
/*we dont have to check both for void because if only one
is void there will be a type mismatch, otherwise they are
the same. So if one is void the other is also*/
if (($1->isType != $3->isType) || ($1->isType == VOIDDEC))
{
yyerror("Type mismatch or void in additive exp");
exit(1);
}
$$ = ASTCreateNode(EXPR);
$$->op=$2;
$$->left=$1;
$$->right=$3;
/*inherit the type, already check for equivalence
so can just use $1*/
$$->isType=$1->isType;
$$->name=CreateTemp();
$$->symbol=Insert($$->name,$$->isType,0,level,1,offset,NULL);
offset+=1;
if(offset>maxoffset)
maxoffset = offset;
}
| term {$$ = $1;}
;
addop:
'+' { $$ = PLUS; }
| '-' { $$ = MINUS; }
;
term:
term mulop factor
{ /* must ensure it is left recursive, to work properly */
/*we dont have to check both for void because if only one
is void there will be a type mismatch, otherwise they are
the same. So if one is void the other is also*/
if (($1->isType != $3->isType) || ($1->isType == VOIDDEC))
{
yyerror("Type mismatch or void in term/factor exp");
exit(1);
}
$$ = ASTCreateNode(EXPR);
$$->op=$2;
$$->left=$1;
$$->right=$3;
/*inherit the type, already check for equivalence
so can just use $1*/
$$->isType=$1->isType;
$$->name=CreateTemp();
$$->symbol=Insert($$->name,$$->isType,0,level,1,offset,NULL);
offset+=1;
if(offset>maxoffset)
maxoffset = offset;
}
| factor {$$ = $1;}
;
mulop:
'*' { $$ = TIMES; }
| '/' { $$ = DIVIDE; }
;
factor:
'('expression')' {$$ = $2;}
| var { $$ = $1; }
| call { $$ = $1; }
| T_NUM
{
$$=ASTCreateNode(NUMBER);
$$->value=$1;
/*numbers are always ints here*/
$$->isType=INTDEC;
}
;
call:
T_ID '('args')'
{
struct SymbTab * p;
if ((p=Search($1,0,1)) != NULL)
{ /*make sure symbol is a function*/
if(p->IsAFunc != 1)
{
yyerror($1);
yyerror("Is a variable, but was called as function");
exit(1);
}
/*have to make sure we are calling with right params*/
$$=ASTCreateNode(CALLSTMT);
/* hold the link to args in right*/
$$->right=$3;
$$->name=$1;
$$->symbol=p;
$$->isType=p->Type;
}
else
{
yyerror($1);
yyerror("Function not defined in symbol table");
exit(1);
}
}
;
args:
arg-list { $$ = $1; }
| { $$ = NULL; }
;
arg-list:
arg-list',' expression
{ /*attach the expressions to the tree in order
the use of the argList is handled above */
$$=ASTCreateNode(ARGLIST);
$$->left=$3;
$$->right=$1;
}
| expression
{
$$=ASTCreateNode(ARGLIST);
$$->right=$1;
}
;
%%
int main(int argc, char *argv) {
if (argc == 2)
yyin = fopen(argv[1], "r");
else {
printf("No files - Exitn");
exit(1);
}
Display();
yyparse();
ASTprint(0, prog);
return 0;
}
void yyerror(const char* s) {
//fprintf(stderr, "%s-:%d %sn", filename, yylineno, s);
fprintf (stderr,"%s On Line: %dn", s, yylineno);
}
In my ast.h file
#ifndef ASTH
#define ASTH
#include <stdio.h>
#include <malloc.h>
/* define the enumerated types for the AST. THis is used to tell us what
sort of production rule we came across */
/* this is a partial list of NODE types for the ASTNode */
enum ASTtype {
PROGRAM,
VARDEC,
ARGLIST,
IDENT,
BLOCK,
NUMBER,
ASSIGN,
EXPRSTMT,
FUNCTIONDEC,
CALLSTMT,
EXPR,
IFSTMT,
ITERSTMT,
RETURNSTMT,
PARAM,
STRINGNODE
};
enum OPERATORS {
PLUS,
MINUS,
TIMES,
DIVIDE,
LESSTHANEQUAL,
LESSTHAN,
GREATERTHAN,
GREATERTHANEQUAL,
EQUAL,
NOTEQUAL,
INTDEC,
VOIDDEC,
STRINGDEC,
null
};
/* define a type AST node which will hold pointers to AST structs that will
allow us to represent the parsed code
*/
struct ASTnode
{
enum ASTtype type;
enum OPERATORS op;
enum OPERATORS isType;
char * name;
char * str;
int value;
struct SymbTab * symbol;
struct ASTnode *left,*right; /* left is usually the connector for statements */
struct ASTnode *s1,*s2 ; /* used for holding IF and WHILE components -- not very descriptive */
};
struct ASTnode *prog;
//prototypes
struct ASTnode *ASTCreateNode(enum ASTtype mytype);
void ASTattachleft(struct ASTnode *p, struct ASTnode *q);
void ASTprint(int level, struct ASTnode *p);
#endif /* of ASTH */
When I try to compile using these commands:
bison -d step3.y
flex step3.fl
gcc step3.tab.c lex.yy.c -lfl -o a.out
It gives me the following error:
In file included from step3.fl:15:0:
step3.y:39:17: error: field ‘op’ has incomplete type
enum OPERATORS op;
I've looked all over the internet and couldn't find a possibly fix. Can anyone help me with this one?
Thanks in advance.
enums bison yacc c-minus-minus
enums bison yacc c-minus-minus
edited Nov 4 at 14:44
asked Nov 4 at 9:45
PiguFilms
61118
61118
Please include enough code in your question to reproduce the problem. From the error message, I assume your lexer includesstep3.tab.h
, correct? And I further assumestep3.y
includesast.h
- if so, in which section? Also: in your compilation steps, isfile
actually a "stand in" forstep3
or do you have multiple.y
and.fl
files and the error is coming from different ones than the ones you are compiling?
– sepp2k
Nov 4 at 14:22
@sepp2k You are correct. I've edited my question to include more code.
– PiguFilms
Nov 4 at 14:44
add a comment |
Please include enough code in your question to reproduce the problem. From the error message, I assume your lexer includesstep3.tab.h
, correct? And I further assumestep3.y
includesast.h
- if so, in which section? Also: in your compilation steps, isfile
actually a "stand in" forstep3
or do you have multiple.y
and.fl
files and the error is coming from different ones than the ones you are compiling?
– sepp2k
Nov 4 at 14:22
@sepp2k You are correct. I've edited my question to include more code.
– PiguFilms
Nov 4 at 14:44
Please include enough code in your question to reproduce the problem. From the error message, I assume your lexer includes
step3.tab.h
, correct? And I further assume step3.y
includes ast.h
- if so, in which section? Also: in your compilation steps, is file
actually a "stand in" for step3
or do you have multiple .y
and .fl
files and the error is coming from different ones than the ones you are compiling?– sepp2k
Nov 4 at 14:22
Please include enough code in your question to reproduce the problem. From the error message, I assume your lexer includes
step3.tab.h
, correct? And I further assume step3.y
includes ast.h
- if so, in which section? Also: in your compilation steps, is file
actually a "stand in" for step3
or do you have multiple .y
and .fl
files and the error is coming from different ones than the ones you are compiling?– sepp2k
Nov 4 at 14:22
@sepp2k You are correct. I've edited my question to include more code.
– PiguFilms
Nov 4 at 14:44
@sepp2k You are correct. I've edited my question to include more code.
– PiguFilms
Nov 4 at 14:44
add a comment |
2 Answers
2
active
oldest
votes
up vote
1
down vote
Code inside %{ }
will only be included in the generated .c file, not the generated header file. So when your lexer includes the header file (and doesn't previously include ast.h
), you get the union, but not the contents of ast.h
, so enum OPERATORS
is an incomplete type because the compiler hasn't seen the definition of OPERATORS
.
In Bison it is generally preferable to use %code
over %{ }
as it gives you more control over where the code is included. In your case, you'll want to include ast.h
in the %code requires
section. From the docs:
requires
- Language(s): C, C++
- Purpose: This is the best place to write dependency code required for YYSTYPE and YYLTYPE. In other words, it’s the best place to define types referenced in %union directives. If you use #define to override Bison’s default YYSTYPE and YYLTYPE definitions, then it is also the best place. However you should rather %define api.value.type and api.location.type.
- Location(s): The parser header file and the parser implementation file before the Bison-generated YYSTYPE and YYLTYPE definitions.
So that would be:
%code requires {
#include "ast.h"
}
That just generated a lot of errors pastebin.com/dGj1k3mB
– PiguFilms
Nov 4 at 15:05
1
@PiguFilms I'm pretty sure, the change didn't cause those errors. You just haven't gotten to the linking step before. Anyway, those errors seem to be unrelated and should be a topic for another question (which should then include the relevant information, such as where those functions are defined and whether and how you're linking the appropriate compilation units).
– sepp2k
Nov 4 at 15:12
add a comment |
up vote
0
down vote
The problem is that you're missing #include "ast.h"
in your step3.fl file. It should be just before the #include "step3.tab.h"
line.
Unfortunately, that didn't work.
– PiguFilms
yesterday
add a comment |
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
Code inside %{ }
will only be included in the generated .c file, not the generated header file. So when your lexer includes the header file (and doesn't previously include ast.h
), you get the union, but not the contents of ast.h
, so enum OPERATORS
is an incomplete type because the compiler hasn't seen the definition of OPERATORS
.
In Bison it is generally preferable to use %code
over %{ }
as it gives you more control over where the code is included. In your case, you'll want to include ast.h
in the %code requires
section. From the docs:
requires
- Language(s): C, C++
- Purpose: This is the best place to write dependency code required for YYSTYPE and YYLTYPE. In other words, it’s the best place to define types referenced in %union directives. If you use #define to override Bison’s default YYSTYPE and YYLTYPE definitions, then it is also the best place. However you should rather %define api.value.type and api.location.type.
- Location(s): The parser header file and the parser implementation file before the Bison-generated YYSTYPE and YYLTYPE definitions.
So that would be:
%code requires {
#include "ast.h"
}
That just generated a lot of errors pastebin.com/dGj1k3mB
– PiguFilms
Nov 4 at 15:05
1
@PiguFilms I'm pretty sure, the change didn't cause those errors. You just haven't gotten to the linking step before. Anyway, those errors seem to be unrelated and should be a topic for another question (which should then include the relevant information, such as where those functions are defined and whether and how you're linking the appropriate compilation units).
– sepp2k
Nov 4 at 15:12
add a comment |
up vote
1
down vote
Code inside %{ }
will only be included in the generated .c file, not the generated header file. So when your lexer includes the header file (and doesn't previously include ast.h
), you get the union, but not the contents of ast.h
, so enum OPERATORS
is an incomplete type because the compiler hasn't seen the definition of OPERATORS
.
In Bison it is generally preferable to use %code
over %{ }
as it gives you more control over where the code is included. In your case, you'll want to include ast.h
in the %code requires
section. From the docs:
requires
- Language(s): C, C++
- Purpose: This is the best place to write dependency code required for YYSTYPE and YYLTYPE. In other words, it’s the best place to define types referenced in %union directives. If you use #define to override Bison’s default YYSTYPE and YYLTYPE definitions, then it is also the best place. However you should rather %define api.value.type and api.location.type.
- Location(s): The parser header file and the parser implementation file before the Bison-generated YYSTYPE and YYLTYPE definitions.
So that would be:
%code requires {
#include "ast.h"
}
That just generated a lot of errors pastebin.com/dGj1k3mB
– PiguFilms
Nov 4 at 15:05
1
@PiguFilms I'm pretty sure, the change didn't cause those errors. You just haven't gotten to the linking step before. Anyway, those errors seem to be unrelated and should be a topic for another question (which should then include the relevant information, such as where those functions are defined and whether and how you're linking the appropriate compilation units).
– sepp2k
Nov 4 at 15:12
add a comment |
up vote
1
down vote
up vote
1
down vote
Code inside %{ }
will only be included in the generated .c file, not the generated header file. So when your lexer includes the header file (and doesn't previously include ast.h
), you get the union, but not the contents of ast.h
, so enum OPERATORS
is an incomplete type because the compiler hasn't seen the definition of OPERATORS
.
In Bison it is generally preferable to use %code
over %{ }
as it gives you more control over where the code is included. In your case, you'll want to include ast.h
in the %code requires
section. From the docs:
requires
- Language(s): C, C++
- Purpose: This is the best place to write dependency code required for YYSTYPE and YYLTYPE. In other words, it’s the best place to define types referenced in %union directives. If you use #define to override Bison’s default YYSTYPE and YYLTYPE definitions, then it is also the best place. However you should rather %define api.value.type and api.location.type.
- Location(s): The parser header file and the parser implementation file before the Bison-generated YYSTYPE and YYLTYPE definitions.
So that would be:
%code requires {
#include "ast.h"
}
Code inside %{ }
will only be included in the generated .c file, not the generated header file. So when your lexer includes the header file (and doesn't previously include ast.h
), you get the union, but not the contents of ast.h
, so enum OPERATORS
is an incomplete type because the compiler hasn't seen the definition of OPERATORS
.
In Bison it is generally preferable to use %code
over %{ }
as it gives you more control over where the code is included. In your case, you'll want to include ast.h
in the %code requires
section. From the docs:
requires
- Language(s): C, C++
- Purpose: This is the best place to write dependency code required for YYSTYPE and YYLTYPE. In other words, it’s the best place to define types referenced in %union directives. If you use #define to override Bison’s default YYSTYPE and YYLTYPE definitions, then it is also the best place. However you should rather %define api.value.type and api.location.type.
- Location(s): The parser header file and the parser implementation file before the Bison-generated YYSTYPE and YYLTYPE definitions.
So that would be:
%code requires {
#include "ast.h"
}
answered Nov 4 at 14:58
sepp2k
288k36592604
288k36592604
That just generated a lot of errors pastebin.com/dGj1k3mB
– PiguFilms
Nov 4 at 15:05
1
@PiguFilms I'm pretty sure, the change didn't cause those errors. You just haven't gotten to the linking step before. Anyway, those errors seem to be unrelated and should be a topic for another question (which should then include the relevant information, such as where those functions are defined and whether and how you're linking the appropriate compilation units).
– sepp2k
Nov 4 at 15:12
add a comment |
That just generated a lot of errors pastebin.com/dGj1k3mB
– PiguFilms
Nov 4 at 15:05
1
@PiguFilms I'm pretty sure, the change didn't cause those errors. You just haven't gotten to the linking step before. Anyway, those errors seem to be unrelated and should be a topic for another question (which should then include the relevant information, such as where those functions are defined and whether and how you're linking the appropriate compilation units).
– sepp2k
Nov 4 at 15:12
That just generated a lot of errors pastebin.com/dGj1k3mB
– PiguFilms
Nov 4 at 15:05
That just generated a lot of errors pastebin.com/dGj1k3mB
– PiguFilms
Nov 4 at 15:05
1
1
@PiguFilms I'm pretty sure, the change didn't cause those errors. You just haven't gotten to the linking step before. Anyway, those errors seem to be unrelated and should be a topic for another question (which should then include the relevant information, such as where those functions are defined and whether and how you're linking the appropriate compilation units).
– sepp2k
Nov 4 at 15:12
@PiguFilms I'm pretty sure, the change didn't cause those errors. You just haven't gotten to the linking step before. Anyway, those errors seem to be unrelated and should be a topic for another question (which should then include the relevant information, such as where those functions are defined and whether and how you're linking the appropriate compilation units).
– sepp2k
Nov 4 at 15:12
add a comment |
up vote
0
down vote
The problem is that you're missing #include "ast.h"
in your step3.fl file. It should be just before the #include "step3.tab.h"
line.
Unfortunately, that didn't work.
– PiguFilms
yesterday
add a comment |
up vote
0
down vote
The problem is that you're missing #include "ast.h"
in your step3.fl file. It should be just before the #include "step3.tab.h"
line.
Unfortunately, that didn't work.
– PiguFilms
yesterday
add a comment |
up vote
0
down vote
up vote
0
down vote
The problem is that you're missing #include "ast.h"
in your step3.fl file. It should be just before the #include "step3.tab.h"
line.
The problem is that you're missing #include "ast.h"
in your step3.fl file. It should be just before the #include "step3.tab.h"
line.
answered Nov 4 at 20:50
Chris Dodd
79.3k678157
79.3k678157
Unfortunately, that didn't work.
– PiguFilms
yesterday
add a comment |
Unfortunately, that didn't work.
– PiguFilms
yesterday
Unfortunately, that didn't work.
– PiguFilms
yesterday
Unfortunately, that didn't work.
– PiguFilms
yesterday
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53139484%2fbison-yacc-error-field-has-incomplete-type%23new-answer', 'question_page');
}
);
Post as a guest
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Please include enough code in your question to reproduce the problem. From the error message, I assume your lexer includes
step3.tab.h
, correct? And I further assumestep3.y
includesast.h
- if so, in which section? Also: in your compilation steps, isfile
actually a "stand in" forstep3
or do you have multiple.y
and.fl
files and the error is coming from different ones than the ones you are compiling?– sepp2k
Nov 4 at 14:22
@sepp2k You are correct. I've edited my question to include more code.
– PiguFilms
Nov 4 at 14:44