I'm trying to develop a basic compiler and I'm using a union for yylval as follows:
%{
#include <string.h>
#include <stdio.h>
struct info {
int line;
/* details unimportant */
};
%}
%union{
char *str;
struct info *ptr;
}
In my lexer definition, I have
%{
#include "parse.tab.h"
%}
But when I compile the generated lexer, I get the following errors:
y.tab.h: unknown type name 'YYSTYPE'.
error: request for a member str in something not a structure or a union.
Do I need to #define YYSTYPE as well?
(I edited the original question to insert enough information from the source files to make the question answerable. Any mistakes in the transcription are my fault and I apologize -- Rici.)
No. If you use a %union declaration, you must not #define YYSTYPE; the bison manual makes this clear.
However, any necessary declarations -- in this case, the declaration of struct info -- must be included in your lexer description file (parse.l) as well. The two generated files are independent of each other, so the fact that struct info is declared in the parser does not make the definition automatically available to the lexer.
In order to avoid repeating the declarations, it is usually a good idea to put them in a separate header file:
file: info.h (added)
#ifndef INFO_H_HEADER_
#define INFO_H_HEADER_
struct info {
int line;
/* details unimportant */
};
// ...
#endif
file: parse.y (now #include's info.h instead of the in-line struct declaration)
%{
#include <stdio.h>
#include <string.h>
#include "info.h"
%}
%union{
char *str;
struct info *ptr;
}
file: parse.l (also #includes info.h)
%{
#include <stdio.h>
#include <string.h>
/* This must come *before* including parse.tab.h */
#include "info.h"
#include "parse.tab.h"
%}
The following is an example of how I use YYSTYPE:
typedef union { // base type filled by lexical analyzer
struct {
int numtype; // classval (type; selects into union below)
union {
int ival; // integer value
long lval; // long value
double dval; // double
} val;
} numval;
unsigned char *sval; // string value
} lex_baseval;
typedef struct { // type returned by lexical analyzer
int lineno;
lex_baseval lexval;
} YYSTYPE;
#define YYSTYPE YYSTYPE
The problem with your linked code is that the %union is inside the %{...%} at the top of your .y file -- which means that yacc just copies it verbatim to the y.tab.c file and does not actually process it.
This manifests most obviously as a syntax error on %union when you try to compile y.tab.c, but also means there's no YYSTYPE definition in y.tab.h, as yacc didn't see the %union so didn't create one.
Related
I'm trying to make a reentrant flex&bison parser but I got this strange error:
too few arguments to function call, expected 5, have 4
I can see that the code generated by Bison looks like this:
static void
yydestruct (const char *yymsg,
yysymbol_kind_t yykind, YYSTYPE *yyvaluep, void *scanner, struct BisonOutput *out)
{ ...some code... }
and
int
yyparse (void *scanner, struct BisonOutput *out)
{
...some code...
yydestruct ("Cleanup: discarding lookahead",
yytoken, &yylval, out); // <--- here void*scanner parameter is clearly missing
...some code...
}
My code is this:
%define api.pure full
%lex-param {void *scanner}
%parse-param {void *scanner, struct BisonOutput *out}
%{
struct BisonOutput{
int out;
};
#include "syntax_parser.h"
#include "lex.yy.h"
#include <stdio.h>
%}
%define api.value.type union
%token <int> NUM
...bunch of other tokens...
%%
...bunch of grammar rules...
%%
... main function and such ...
And Flex code is as follows:
%{
#include "syntax_parser.h"
%}
%option reentrant bison-bridge noyywrap
blanks [ \t\n]+
number [0-9]+
%option noyywrap
%%
... bunch of rules ...
I'm really lost. Why doesn't bison plug scanner into yydestruct despite clearly using it in yyparse?
You are not allowed to put two parameters in a %*-param declaration. The correct way to produce the set of parameters you want is:
%param { void* scanner }
%parse-param { struct BisonOutput* out }
Bison doesn't really parse the code between { and }. All it does is identify the last identifier which it assumes is the name of the parameter. It also assumes that the code is a syntactically-correct declaration of a single parameter, and it is inserted as such in the prototypes. Since it's actually two parameters, it can be inserted without problem into a prototype, but since only one argument is inserted into the calls to the function, these don't match the prototype.
(Really, void* scanner should be yyscan_t scanner, with a prior typedef void* yyscan_t;. But perhaps it is not really better.)
You might also consider putting the declaration of struct BisonOutput into a %code requires (or %code provides) block, so that it is automatically included in the bison-generated header file.
I am building a project that I am trying to organize as follows:
main.c
globals.h
structures.h
FunctionSet1.c, FunctionSet1.h
FunctionSet2.c, FunctionSet2.h
etc.
I thought I could define a structure type in structures.h:
struct type_struct1 {int a,b;}; // define type 'struct type_struct1'
then declare a function1() returning a structure of type type_struct1 in FunctionSet1.h:
#include "structures.h"
struct type_struct1 function1(); // declare function1() that returns a type 'struct type_struct1'
then write function1() in FunctionSet1.c:
#include "FunctionSet1.h"
struct type_struct1 function1() {
struct type_struct1 struct1; // declare struct1 as type 'struct type_struct1'
struct1.a=1;
struct1.b=2;
return struct1;
}
Edit: with the corrected code above, the compiler returns
306 'struct' tag redefined 'type_struct1' structures.h
Is the file set good practice ?
What is the good practice to manage the structures ?
In your example, you declare a structure named type_struct in structure.h, then in FunctionSet1.h the structure that you are returning is type_struct, and in the .c it is called struct1.
So i think that the problem is that struct1 and type_struct are not recognized because they have never been defined ...
However, the organization of your files is fine.
Your general structure looks good. One thing you need to do, as zenith mentioned, is to put include guards into your header files. What that is is a set of #define's that make sure that the contents of the header are not included more that once in a given file. For example:
structures.h:
#ifndef STRUCTURES_H
#define STRUCTURES_H
struct type_struct1{
int a,b;
};
...
// more structs
...
#endif
FunctionSet1.h:
#ifndef FUNCTION_SET_1_H
#define FUNCTION_SET_1_H
#include "structures.h"
struct type_struct1 function1();
...
// more functions in FucntionSet1.c
...
#endif
main.c:
#inlcude <stdio.h>
#include "structures.h"
#include "FunctionSet1.h"
int main(void)
{
struct type_struct1 struct1;
struct1 = function1();
return 0;
}
Here, main.c includes structures.h and FunctionSet1.h, but FunctionSet1.h also includes structures.h. Without the include guards, the contents of structures.h would appear twice in the resulting file after the preprocesser is done. This is probably why you're getting the "tag redefined" error.
The include guards prevent these type of errors from happening. Then you don't have to worry about whether or not a particular header file was included or not. This is particularly important if you're writing a library, where other users may not know the relationship between your header files.
First of all, you have to declare the structure in your file.h (you can use typedef to create an alias)
typedef struct Books
{
char title[50];
int book_id;
} books;
then, you have to include your file.h in your file.c and declare your variable like this
#include "file.h"
int main()
{
books book1;
book1.title = "Harry Potter";
book1.book_id = 54;
}
or like this if you didn't use typedef
#include "file.h"
int main()
{
struct Books book1;
book1.title = "Harry Potter";
book1.book_id = 54;
}
Thank you all.
I read again what you said and found that the code above is now correct.
The error I report is with testing the following main.c
#include "structures.h"
#include "FunctionSet1.h"
void main() {
struct type_struct1 struct2;
struct2=function1();
}
in which structures.h is included again, thus causing the error. Removing the include eliminates the error.
I will now look into header guards to avoid such problems.
Thanks again.
Some lines of my flex file:
%{
#include <stdlib.h>
#include <string.h>
#include "types.h"
#define NO_YY_UNPUT
/* #define YY_NEVER_INTERACTIVE */
extern char *strdup(const char *);
short unsigned int yylineno = 1;
%}
{ID} {
yylval.txt = strdup(yytext);
return ID;
};
\n { ++yylineno; }
My code looks good but I have problem when i want to compile on Ubuntu. In windows everything is okay but on linux I have errors like:
lex.l:10:14: error: expected identifier or ‘(’ before ‘__extension__’
lex.l:12:20: error: conflicting types for ‘yylineno’
lex.c:355:5: note: previous definition of ‘yylineno’ was here
Line 10: extern char *strdup(const char *);
Line 12: short unsigned int yylineno = 1;
strdup is declared in string.h, but it is a Posix interface and you should define an appropriate feature test macro before including any system header:
%top {
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <string.h>
#include "types.h"
}
(Note: Using %top forces the enclosed code to be inserted at the top of the generated C file, in order to provide the guarantee that the feature test macro is defined before any system header.)
I don't know if that works on Windows (and it certainly depends on your compiler and toolchain), so you might need to declare strdup on that platform. If so, make sure you surround the declaration with a preprocessor test for the build environment.)
The error at line 10 is probably the result of strdup being defined as a macro. I'm not sure under what conditions that will happen -- it will be some GNU extension mode -- but defining the Posix feature test macro should prevent it.
As for the error with the type of yylineno, there is a simple solution: don't declare yylineno. It is declared in the code flex generates (and it may be declared as a macro if you ask for a re-entrant -- "pure" -- lexer).
I have a list of checkpoints and then a run a function. I originally built this list in that function, but now I have to build it outside. The problem is that I cannot include checkpoint.h in the class that implements that function because checkpoint.h returns a structure of the type of that class. The initial list was declare in class.c globally. How can I transfer the list created outside into class so I can use it?
So I have this header, turing_machine.h:
#ifndef __TURING_MACHINE__
#define __TURING_MACHINE__
#include "tape.h"
#include "alphabet.h"
#include "symbol_table.h"
...
#endif
and the checkpoint.h header defining the checkpoint_list class:
#ifndef __CHECKPOINT_H__
#define __CHECKPOINT_H__
#include "turing_machine.h"
...
#endif
So I want to send to a function from turing_machine.h a list of structures checkpoint but I can't modify anything because that's how the classes must stay.
I have also turing_machine.c:
#include "turing_machine.h"
#include "checkpoint.h"
#include "symbol_table.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
checkpoint_list *c;
So at the beginning I created in turing_machine that list, c, but now I must create it outside and I have to initialize that list c but I don't know how. I hope this is more clear.
I used the term class wrong; I have just .c and .h files.
Reading between the lines, somewhat, I think your trouble is that you have 'mutually referencing' structures.
The way to work around this is with an incomplete type definition:
typedef struct checkpoint_list checkpoint_list;
You can then use that inside turing_machine.h:
#ifndef TURING_MACHINE_H_INCLUDED
#define TURING_MACHINE_H_INCLUDED
#include "tape.h"
#include "alphabet.h"
#include "symbol_table.h"
typedef struct checkpoint_list checkpoint_list;
typedef struct turing_machine
{
...
} turing_machine;
extern checkpoint_list *tm_function(turing_machine *);
extern turing_machine *tm_create(const char *);
#endif
And, inside checkpoint.h, you can write:
#ifndef CHECKPOINT_H_INCLUDED
#define CHECKPOINT_H_INCLUDED
#include "turing_machine.h"
/* No typedef here in checkpoint.h */
struct checkpoint_list
{
...
};
extern checkpoint_list *cp_function(const char *);
extern turing_machine *cp_machine(checkpoint_list *);
#endif
This technique is recognized and defined by the C standard (C90, let alone C99 or C11).
Note that I've also renamed the include guards; names that start with double underscore are reserved for 'the implementation' (meaning the C compiler and its libraries), and you should not invent and use such names in your own code.
I'm implementing a sql parser in lex and yacc,
in that I use a symbol table which I kept in a separate .h file (sql.h) and in this header file I have some functions declarations.
The definitions of these functions are kept in a .c file (sql.c). Now I have included sql.h in sql.c,
I refer to the symbols and functions from sql.h in both my lex file(1.l) and yacc file(1.y).
The problem is that I'm not able to write a proper makefile for this.
I'm getting errors like multiple declarations.
Where do I include which file and how to write dependencies?
Please help. I have searched for a solution but I'm not getting it.....
Update:
I compile the code like this:
lex 1.l
yacc -d 1.y
gcc lex.yy.c y.tab.c sql.c -ll -ly
I get the following errors after the third command of gcc:
In file included from 1.l:5:
sql.h:17: warning: ‘SQL’ initialized and declared ‘extern’
sql.h:18: warning: ‘SQL_SEL’ initialized and declared ‘extern’
1.l: In function ‘makeTable’:
1.l:80: warning: assignment from incompatible pointer type
In file included from 1.y:7:
sql.h:17: warning: ‘SQL’ initialized and declared ‘extern’
sql.h:18: warning: ‘SQL_SEL’ initialized and declared ‘extern’
sql.c:3: error: redefinition of ‘SQL’
sql.h:15: note: previous definition of ‘SQL’ was here
sql.c:4: error: redefinition of ‘SQL_SEL’
sql.h:16: note: previous definition of ‘SQL_SEL’ was here
sql.h:
#ifndef SQL_H
#define SQL_H
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
struct sym_table {
char *token;
char *value;
struct sym_table *next;
};
struct sym_select {
char **cols;
};
extern struct sym_table *SQL = NULL;
extern struct sym_select *SQL_SEL = NULL;
void addSymbol(char *, char *);
void print(struct sym_table *);
void showTable(struct sym_table *);
void makeTable(struct sym_table *, int);
sql.c:
#include "sql.h"
struct sym_table *SQL = NULL;
struct sym_select *SQL_SEL = NULL;
And the definitions of the functions declared in sql.h
1.l file:
%{
#include <stdio.h>
#include <stdlib.h>
#include "y.tab.h"
#include "sql.h"
int lineno=1;
void makeTable(struct sym_table *, int);
%}
..... and othr lex file
1.y
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern int lineno;
extern void yyerror(char *);
#include "sql.h"
%}
.... and other yacc file data
Can you suggest me some other way to get around this?
Please post your Makefile. As far as i understand there's also a problem with code, not only with Makefile. Or it could be that you try to make 1.o from 1.l and different 1.o from 1.y.
Normally the dependencies should look something like:
1l.o: 1.l sql.h; # lex invocation
1y.o: 1.y sql.h; # bison invocation
sql.o: sql.c sql.h; # cc invocation
prog: 1l.o 1y.o sql.o; # ld invocation
Probably you will also need to depend on tokens' declaration file.
EDIT:
Ah, so probably you need to put the definition of that table into one file, and the declaration into the header. You must first understand the difference between declaration and definition in C. For example if you have the following files:
aaa.h
int arr[]={1};
aaa.c
#include "aaa.h"
bbb.c
#include "aaa.h"
And then you try to cc -o aaa aaa.c bbb.c, you get the multiple definition error. That means, that the actual array must be in one file, and in the header it should be something like extern int arr[];
Update:
You should remove setting to NULL in sql.h. It's only a declaration there, that there is such and such variable somewhere. The actual value is to be assigned in sql.c.
extern struct sym_table *SQL = NULL;
extern struct sym_select *SQL_SEL = NULL;
Remove the initialization = NULL from the header file.