I am super new to FLEX, I'm trying to write a simple FLEX lex file, but for some reason I get the error in the header.
The complete error is:
bash syntax error near unexpected token '('
The command I am running is:
flex sample.lex
OR
flex sample.l
Where am I going wrong here?
%{
union{
int val;
char name [30];
char str [80];
}yylval;
#include <stdio.h>
%}
%%
. ECHO;
%%
int main(int argc, char **argv)
{
if (argc != 2) {
printf("no input file>\n");
exit (1);
}
printf("token lexeme attribute\n");
printf("--------------------------\n");
yyin=fopen(argv[1], "r");
if(yyin!=0)
{ printf("file opened");
fclose(yyin);}
exit (0);
}
int yywrap () { return 1; }
Are you running Flex on the file, and then GCC? I was able to compile this. First, run
flex test.l
This should generate a file name "lex.yy.c", which is C code generated by Flex. This file contains code to scan the input, and the C code in your .l file. Then running
gcc lex.yy.c
should produce an executable "a.out". Running
./a.out test.txt
produced the output you're printing, including "file opened". As was pointed out, main does not have a return type, but I guess my compiler was able to figure it out.
However, even if you can compile this, it looks like you are misunderstanding a few aspects of Flex.
union{
int val;
char name [30];
char str [80];
}yylval;
is a regular C union. Bison's %union declaration is used when a semantic value can have more than one type, and is not the same thing. %union should not be in the .l file.
Also, you need to call yylex() to actually start scanning the input.
Right now, I would suggest going to the Flex manual and doing some of the starter examples: http://westes.github.io/flex/manual/Simple-Examples.html. If you are using Flex and Bison together, you should also go through some of the Bison examples: http://www.gnu.org/software/bison/manual/html_node/Examples.html#Examples
Related
I found it easy to learn about Lex/Flex however learning Yacc/Bison seemed a lot more confusing due to the lack of simple example programs. From my observations, the first example parser introduced to students tends to be a calculator, which is not too beginner-friendly. It was quite hard for me to comprehend how Yacc works simply by looking at complex source code, thus I decided to write my own very simple program which incorporates Lex and Yacc.
test.l:
%{
#include "y.tab.h"
%}
%%
"PRINT" { printf("Returning PRINT\n"); return PRINT; }
"EXIT" { printf("Returning EXIT\n"); return EXIT; }
. ;
[ \t\n] ;
%%
int yywrap(void) { return 1; }
test.y:
%{
int yylex();
#include <stdio.h>
#include <stdlib.h>
//#include "y.tab.h"
%}
%start line
%token PRINT
%token EXIT
%%
line: PRINT {printf("Caught PRINT\n");}
| EXIT {printf("Caught EXIT\n");}
| ;
%%
int main() { yyparse(); }
Compilation:
yacc -d test.y
lex test.l
gcc lex.yy.c y.tab.h -ll
I understand that this program is very simple and there are tons of examples for Yacc, I would like to sincerely assure you that I tried for a couple hours before asking out for some help.
Although I think I got the basics done, I'm unable to figure out why it won't work, please let me know how I could fix it. I suspect that I might be compiling incorrectly. I could also display y.tab.h if necessary. Thank you for your time.
Edit: The goal is simply for the lexer to return the appropriate return value to the yacc parser, and for the yacc parser to "catch" it and print "Caught PRINT" or "Caught EXIT".
Edit 2: My compilation process was indeed incorrect. I would like to thank the person who was helped me understand how to fix the issue.
You shouldn't compile *.h files.
Withgcc y.tab.c lex.yy.c and a provided yyerror definition inside test.y (the bison manual recommends void yyerror (char const *s) { fprintf (stderr, "%s\n", s); }), it should build.
So I'm writing a bison (without lex) parser and now I want to read the input code from file and to write the output to another file.
Searching the stackoverflow for some time I found that this way should be good.
bison.y:
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern FILE *yyin;
int yylex() { return getc(stdin); }
void yyerror(char *s) {
fprintf (stderr, "%s\n", s);
}
int counter = 1;
char filename2[10] = "dest.ll";
FILE *f2;
%}
%name parse
%%
//grammars
%%
int main(int argc, char *argv[]) {
yyin = fopen(argv[1], "r");
if (argc > 2)
f2 = fopen(argv[2], "w");
else
f2 = fopen(filename2, "w");
yyparse();
return 0;
}
Then i compile it this way:
bison bison.y
cc -ly bison.tab.c
And here the result of cc-compilation:
/tmp/ccNqiuhW.o: In function `main':
bison.tab.c:(.text+0x960): multiple definition of `main'
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/liby.a(main.o):(.text.startup+0x0): first defined here
/tmp/ccNqiuhW.o: In function `main':
bison.tab.c:(.text+0x98c): undefined reference to `yyin'
collect2: error: ld returned 1 exit status
The output bison.tab.c file have only 1 main. Ofc int/void main doesn't matter. Can you teach me how to do it correctly?
P.S. By the way, I don't want to spam different posts, and have a little question here. How can I store the string (char *) in $$ in bison? For example, I want to generate a code string after I met the int grammar. I have this error and can't find the answer:
bison.y:94:8: warning: assignment makes integer from pointer without a cast [-Wint-conversion]
INTNUM: NUMBER | DIGIT INTNUM {$$ = "string"};
bison.y: In function ‘yyparse’:
bison.y:28:15: warning: format ‘%s’ expects argument of type ‘char *’, but argument 3 has type ‘int’ [-Wformat=]
PROGRAM: EXPRS { fprintf(f2, "%s: string here %d.\n", $$, counter++) };
will be extremely good if I find the help.
You are linking library liby (linker option -ly). The Bison manual has this to say about it:
The Yacc library contains default implementations of the yyerror and
main functions.
So that's why you have multiple definitions of main. You provide one, and there's one in liby.
Moreover, the docs go on to say that
These default implementations are normally not useful, but POSIX requires them.
(Emphasis added)
You do not need to link liby in order to build a program that includes a bison-generated parser, and normally you should not do so. Instead, provide your own main() and your own yyerror(), both of which you've already done.
Additionally, you are expected to provide a definition of yyin, not just a declaration, whether you link liby or not. To do so, remove the extern keyword from the declaration of yyin in your grammar file.
Your grammar is not complete (there are no rules at all) and the %name directive is not documented and is not recognized by my Bison, but if I add a dummy rule and comment out the %name, in conjunction with the other changes discussed, then bison generates a C source file for me that can be successfully compiled to an executable (without liby).
I am trying to understand lex/yacc and currently I am failing at hello world. I probably messed something up, somewhere, but I can't seem to find it.
Also, I am not experienced with C language or with lex/flex/yacc/bison so this is all new to me.
test.l file;
%option noyywrap
%{
#include <stdio.h>
%}
%%
"hey" printf("hello!");
%%
int main()
{
return 0;
}
I compile this on windows, with the commands;
lex test.l
This returns lex.yy.c file without errors or warnings.
I then compile with;
cc lex.yy.c
Which without errors or warnings, creates the a.exe as supposed too.
When i then run the file with input from another file;
a.exe < input
It returns nothing.
Input file;
"hey"
Any information is welcome, since every single guide I found either creates errors (when literally copy pasted, even after clean install and guided-install) or is simply outdated or listed for "windows" while it uses commands that are non-windows >.<
It's the double quotes in the "hey" in your .l file they actually don't mean "hey" they mean hey so if you change your input file to just say hey rather than "hey" your code should work. If you want to parse " then your rule should be: "\"hey\""
Also lex should auto include stdio.h so you probably don't need it.
LOL you forgot to call yylex();
So:
%option noyywrap
%%
"hey" printf("hello!");
%%
int main()
{
yylex();
return 0;
}
Important subtlety
You will see this behaviour occur and you may not notice it right away but
Your original code will give you and output. The match will occur even with \"hey\" output and you will get:
"hello!"
Notice the "'s.
That's because lex injects a default rule for any character matching to just spit it back out, and because your "hey" rule matches hey and you have "'s around the input the quotes come out in the "hello!"
Your main does nothing - you need to call the lexer.
int main()
{
yylex();
return 0;
}
So we have a tutorial on flex,bison before we start our complation techniques course at university.
The following test should be split into lines and newlines
testtest test data
second line in the data
another line without a trailing newline
This is what my parser should output:
Line: testtest test data
NL
Line: second line in the data
NL
Line: another line without a trailing newline
When im running following
cat test.txt | ./parser
This returns:
LINE: testtest test data
It's a bad: syntax error
This is in my .y file:
%{
#include<stdio.h>
int yylex(); /* Supress C99 warning on OSX */
extern char *yytext; /* Correct for Flex */
unsigned int total;
%}
%token LINE
%token NL
%%
line : LINE {printf("LINE: %s\n", yytext);}
;
newline : NL {printf("NL\n");}
;
And this is in my binary.flex file:
%top{
#define YYSTYPE int
#include "binary.tab.h" /* Token values generated by bison */
}
%option noyywrap
%%
[^\n\r/]+ return LINE;
\n return NL;
%%
So, any ideas to solve this problem ?
PS: This is my .c file
#include<stdio.h>
#include "binary.tab.h"
extern unsigned int total;
int yyerror(char *c)
{
printf("It's a bad: %s\n", c);
return 0;
}
int main(int argc, char **argv)
{
if(!yyparse())
printf("It's a mario time: %d\n",total);
return 0;
}
Your bison grammar recognizes precisely one LINE (without a newline) because the bison grammar recognizes the first non-terminal. Just that, and no more.
If you want to recognize multiples lines, each consisting of a LINE and possibly a NL, you'll need to add a definition for an input consisting of multiple lines, each consisting of ... . I'm not sure why you would use bison for this, though, since the original problem seems easy to solve with just flex.
By the way, if your input file includes a \r character, none of your flex patterns will recognize it (the flex-generated default rule will catch it, but that is almost never what you want). Use %option nodefault so that you get a warning about this sort of error. And react when you see warnings: you will have seen several when you ran bison on your bison file, I'm sure.
I've written a bison parser using flex and c. The parser is compiled without error, but when I run the executable file the main function is not executed (It doesn't print out the first line after the main declaration that is actually a print instruction)
main( int argc, char *argv[] )
{
printf("*** C2P version 1.0 #2015***\n");
extern FILE *yyin;
++argv; --argc;
printf("Open C file %s...",argv[0]);
yyin = fopen( argv[0], "r" );
if (yyin==NULL) {
printf("ERROR file not found %s", argv[0]);
exit(1);
}
yydebug = 1; //enable debug
yyparse();
exit(0);
}
I've used the following commands for compiling:
bison -d c_def.y
flex c_def.l
gcc c_def.tab.h lex.yy.c -o c2p -lfl
This is wrong:
gcc c_def.tab.h lex.yy.c -o c2p -lfl
The bison parser is in the file c_def.tab.c. c_def.tab.h is just the header file containing the token definitions.
So there wouldn't be a main() at all in c2p if it were not for your inclusion of the flex library (-lfl). That library includes a main function which calls the lexer until it returns an end-of-file indicator. (It does not call the parser, which is why your parser is not being called.)
You probably shouldn't use -lfl. Aside from the main() function which you don't need, the only other thing it contains is a fake implementation of yywrap which always returns 1; instead of relying on that, just include the option
%option noyywrap
in your flex definition, and then your lexer won't depend on yywrap at all.