Home > Software engineering >  Why is bison include not applying/extending to union%?
Why is bison include not applying/extending to union%?

Time:11-20

So here is the start of my program. I keep getting the error boolExpr.y:13:2: error: unknown type name 'bool' bool boolean; However when I check the bison generated file, I can see stdbool.h is included at the start of the program executing. I can't figure out how a library can be important but then bool not be recognized. I'm thinking I missed something simple, or I need to reinstall bison or lex. I can include the rest of the program if needed.

I tried to switch it to int boolean; instead of bool boolean; and that fixed the compilation problem, however it still mystifies me. Is there some way to extend a pointer to a struct into %union without getting compile errors? I tried to make a structName * boolean; to replace bool boolean but that kept coming back as undefined wimplicit error as well.

%{
#include "semantics.h"
#include <stdbool.h>
#include "IOMngr.h"
#include <string.h>
extern int yylex(); /* The next token function. */
extern char *yytext; /* The matched token text. */
extern int yyerror(char *s);
extern SymTab *table;
extern SymEntry *entry; 
%}
%union{
 bool boolean;(this is the line # of error)
 char * string;
}
%type <string> Id
%type <boolean> Expr
%type <boolean> Term
%type <boolean> Factor
%token Ident
%token TRUE
%token FALSE
%token OR
%token AND
%%
Prog : StmtSeq {printSymTab();};
StmtSeq : Stmt StmtSeq { };
StmtSeq : { };
Stmt : Id '=' Expr ';' {storeVar($1, $3);};
Expr : Expr OR Term {$$ = doOR($1, $3);};
Expr : Term {$$ = $1;};
Term : Term AND Factor {$$ = doAND($1, $3);};
Term : Factor {$$ = $1;};
Factor : '!' Factor {$$ = doNOT($2);};
Factor : '(' Expr ')' {$$ = $2;};
Factor : Id {$$ = getVal($1);};
Factor : TRUE {$$ = true;};
Factor : FALSE {$$ = false;};
Id : Ident {$$ = strdup(yytext);};
%%
int yyerror(char *s) {
 WriteIndicator(getCurrentColumnNum());
 WriteMessage("Illegal Character in YACC");
 return 1;
}

CodePudding user response:

Ok, silly mistake after all- in my lex file, I had

#include "h4.tab.h"
#include "SymTab.h"
#include <stdbool.h>

but it should have been

#include "SymTab.h"
#include <stdbool.h>
#include "h4.tab.h"

didn't realize include order mattered!

CodePudding user response:

When you use a %union declaration, Bison creates a union type called YYSTYPE which it declares in the generated header file; that type is used in the declaration of yylval, which is also in the generated header file. Putting the declarations in the generated header file means that you don't need to do anything to make yylval and its type YYSTYPE available in your lexical analyser, other than #includeing the bison-generated header file.

That's fine if all the types referred to in the %union declaration are standard C types. But there is a problem if you want to use a type which requires an #included header file, or which you yourself define. Assuming you put the necessary lines in a bison code prologue (%{...}%) before the %union declaration, you won't have a problem compiling your parser, but you will run into a problem in the lexical analyser. When you #include your header file, you will effectively insert the declaration of ´union YYSTYPE´ and that will fail unless all of the referenced types have already been defined.

Of course, you can solve this issue by just copying all the necessary #includes and/or definitions from the .y file to the .l file, making sure that you put the ones needed for the union declaration before the #include of the header file and the ones which require YYSTYPE be defined after the #include. But that violates the principles of good software design; it means that every time you change an #include or declaration in your .y file, you need to think about whether and where you need to make a similar change in your .l file. Fortunately, bison provides a more convenient mechanism.

The ideal would be to arrange for everything needed to be inserted into the generated header file. Then you can just #include "h4.tab.h" in the lexical analyzer, confident that you don't need to do anything else to ensure that needed #includes are present and in the correct order.

To this end, Bison provides a more flexible alternative to %{...}%, the %code directive:

%code [where] {
// code to insert
}

There are a few possible values for where, which are documented in the Bison documentation. Two of these are used to maintain the generated header file:

  • %code requires { ... } inserts the code block in both the header file and the source file, in both cases before the union declaration. This is the code block type you should use for dependencies of the semantic and location types.

  • %code provides { ... } also inserts the code block into both the header and the source file, but this time after the union declaration. You can use this block type if you have some interfaces which themselves refer to YYSTYPE.

You can still use %{...}% to insert code directly into the output source code. But you might want to instead use

* %code { ... }

which, like %{...}%, only inserts the code in the source file. Unlike %{...}%, it inserts the code in a defined place in the source file, after the YYSTYPE and other declarations. This avoids obscure problems with %{...}% blocks, which are sometimes inserted early and sometimes inserted late and therefore can suddenly fail to compile if you change the order of apparently unrelated bison directives.

  • Related