C Parser using lex and yacc - c

I was fiddling with the code for an ANSI C parser given here http://www.lysator.liu.se/c/ANSI-C-grammar-y.html and here http://www.lysator.liu.se/c/ANSI-C-grammar-l.html.
Unfortunately, the code isn't working - I modified it a bit to make it print a message upon successfully parsing an input program, but the message is never printed, even if the input program is in C with no syntax errors. I'd be glad if anyone can help me out here.
EDIT:
Just to clarify - I was only testing a publicly available lex + yacc program on a simple input C program that prints "Hello World!". The links are present above. Please just open them to see the code.

It looks like the Yacc file just checks that your input program is correct (by printing an error if not), but it does nothing else.
Add some semantic actions (some code to execute when a rule has been matched), between curly braces just after the rules. See http://dinosaur.compilertools.net/bison/bison_4.html#SEC11
You can start by printing something when a rule is matched, but if you want to build a C compiler, you'll have to build an AST.
EDIT
You also need to add a main method which calls the parser. Just add
void main() {
yyparse();
}
at the end of the yacc file.
The parser will read the inputs from stdin. So, if you're using Linux or MacOSX, you can type
./parser < helloworld.c
or for Windows
parser < helloworld.c
Actually, the parser prints the input file if it is correct.

Related

Linker error while using lex to compile simple print file. have newest version of macOS 13.1 and xcode installed

I'm trying to run a simple progam in flex that reads the string "hello world" and prints "Goodbye"
here is the file:
%%
"hello world" printf("Goodbye\n");
. ;
%%
the commands are
% flex ex1.l
% gcc lex.yy.c -ll
Error message:
ld: warning: object file (/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib/libl.a(libmain.o)) was built for newer macOS version (13.1) than being linked (13.0)
I have redownloaded the newest version of Xcode and have the updated macOS. I'm not sure what I can try to get this error code to go away.
I have also ran
% CMAKE_OSX_DEPLOYMENT_TARGET 13.0
to try and force the link to V13.0 without success.
The lex library, which the linker will use if given the -ll command-line flag, is supposed to be a convenience to make it easier to write quick and dirty (f)lex programs. If your compiler toolchain installation is OK, then it is a small convenience, but it seems like it's pretty easy to get the installation wrong, and since no-one seems to bother documenting the details of toolchain installation, it's hard to debug configuration issues unless you have lots of experience. That makes it a lot less convenient.
You could use this is as a learning experience in configuring your compilation environment, a skill which you will certainly find useful. But if you just want to get on with flex, it's really easy to avoid the need to use of the lex library.
The lex library consists of exactly two things, neither of which are necessary.
First, it contains a definition of yywrap(). The generated lexer calls yywrap() when it encounters the end of an input file. If yywrap returns 0, the lexer assumes that you have done something which will allow the lexer to continue reading input. That's actually not a very common use case, because most parsers just read one input file from beginning to end, and then finish. So a good default is to write a version of yywrap() which always returns 1, in which case the lexer will return an end-of-file token (0), and that should cause the lexer's caller to stop calling the lexer. The lex library includes the definition of precisely that simple default implementation:
int yywrap() { return 1; }
So you could include that code in your flex file, but a better solution is to tell flex to omit the yywrap() call and just assume that end-of-file means that there is no more input. Which you do by inserting the following declaration in your Flex prologue (not in the %{...%} code section):
%option noyywrap
I always recommend using a few more options:
%option noinput nounput noyywrap nodefault
The first two of those suppress the generation of the input() and unput() functions, so that you don't get "Unused function" warnings when you compile. Or better said, so that you wouldn't get warnings if you requested warnings when you compiled. But you should always request warnings. (And you should read them and act on them.) See the sample build instructions at the end of this answer.
The last option, nodefault, causes flex to produce a warning if there is any input which could trigger the automatic default action. The automatic default is to write the unmatched input to stdout and do nothing else, which is practically never what you want to do with unmatched input. Even if you wanted to ignore all unmatched input, which is a good way of ignoring programming errors, you'd very rarely want to print unmatched input to the output.
As it happens, your code will trigger this warning if you add the nodefault option, because you used . as your fallback pattern. . in (f)lex matches anything other than a newline character, and nothing in your program matches a newline, so the newline will go unmatched. Which means it will be echoed to standard output. Instead, you should use .|\n so that your default pattern also matches a newline. (Alternatively, with flex, you can use the s pattern flag, which causes . to really match anything: (?s:.).)
The other thing that the lex library contains is a default definition of main(). It's somewhat interesting that this is even possible. It works because the linker only includes functions from a library if the functions are not defined in the object files being linked. And, in C, main() really acts like an ordinary function. So if you link with a library which defines main(), that main program will be used whenever you don't define main() in your source code. That can be handy for debugging, but it's not really recommended in production code.
The particular main() function which is included in -ll just calls yylex() repeatedly until it returns an end-of-file token (0):
int main() {
while (yylex() != 0) { }
return 0;
}
So instead of relying on the lex library, just add those four lines at the end of your lexer definition, after the second %%.
If you apply both of these suggestions, you will end up with:
%option noinput nounput noyywrap nodefault
%{
/* So that `printf` is declared */
#include <stdio.h>
%}
%%
"hello world" printf("Goodbye\n");
.|\n ;
%%
int main() {
while (yylex() != 0) { }
return 0;
}
You can then build it without the -ll flag. But you should always build with compiler warnings enabled, and personally I think that using the default executable name a.out is bad style:
% flex ex1.l
% gcc -Wall -o ex1 lex.yy.c

Frama-c: save plugin analysis results in c file

I'am new in frama-c. So I apologize in advance for my question.
I would like to make a plugin that will modify the source code, clone some functions, insert some functions calls and I would like my plugin to generate a second file that will contain the modified version of the input file.
I would like to know if it is possible to generate a new file c with frama-c. For example, the results of the Sparecode and Semantic constant folding plugins are displayed on the terminal directly and not in a file. So I would like to know if Frama-c has the function to write to a file instead of sending the result of the analysis to the standard output.
Of course we can redirect the output of frama-c to a file.c for example, but in this case, for the plugin scf for example, the results of value is there and I found that frama-c replaces for example the "for" loops by while.
But what I would like is that frama-c can generate a file that will contain my original code plus the modifications that I would have inserted.
I looked in the directory src / kernel_services / ast_printing but I have not really found functions that can guide me.
Thanks.
On the command line, option -ocode <file> indicates that any subsequent -print will be done in <file> instead of the standard output (use -ocode "" after that if you want to print on stdout again). Note that -print prints the code corresponding to the current project. You can use -then-on <prj> to change the project you're interested in. More information is of course available in the user manual.
All of this is of course available programmatically. In particular, File.pretty_ast by defaults pretty-prints (i.e. output a C program) the AST of the current project on stdout, but takes two optional argument for changing the project or the formatter to which the output should be done.

Syntax error near unexpected token '('

As a beginner, I am trying to write a simple c program to learn and execute the "write" function.
I am trying to execute a simple c program simple_write.c
#include <unistd.h>
#include <stdlib.h>
int main()
{
if ((write(1, “Here is some data\n”, 18)) != 18)
write(2, “A write error has occurred on file descriptor 1\n”,46);
exit(0);
}
I also execute chmod +x simple_write.c
But when i execute ./simple_write.c, it gives me syntax error near unexpected token '('
Couldn't figure out why this happens ??
P.S: The expected output is:-
$ ./simple_write
Here is some data
$
You did
$ chmod +x simple_write.c
$ ./simple_write.c
when you should have done
$ cc simple_write.c -o simple_write
$ chmod +x simple_write # On second thought, you probably don’t need this.
$ ./simple_write
In words: compile the program to create an executable simple_write
(without .c) file, and then run that. 
What you did was attempt to execute your C source code file
as a shell script.
Notes:
The simple_write file will be a binary file. 
Do not look at it with tools meant for text files
(e.g., cat, less, or text editors such as gedit).
cc is the historical name for the C compiler. 
If you get cc: not found (or something equivalent),
try the command again with gcc (GNU C compiler). 
If that doesn’t work,
If you’re on a shared system (e.g., school or library),
ask a system administrator how to compile a C program.
If you’re on your personal computer (i.e., you’re the administrator),
you will need to install the compiler yourself (or get a friend to do it). 
There’s lots of guidance written about this; just search for it.
When you get to writing more complicated programs,
you are going to want to use
make simple_write
which has the advantages of
being able to orchestrate a multi-step build,
which is typical for complex programs, and
it knows the standard ways of compiling programs on that system
(for example, it will probably “know” whether to use cc or gcc).
And, in fact, you should be able to use the above command now. 
This may (or may not) simplify your life.
P.S. Now that this question is on Stack Overflow,
I’m allowed to talk about the programming aspect of it. 
It looks to me like it should compile, but
The first write line has more parentheses than it needs.
if (write(1, "Here is some data\n", 18) != 18)
should work.
In the second write line,
I count the string as being 48 characters long, not 46.
By the way, do you know how to make the first write fail,
so the second one will execute?  Try
./simple_write >&-
You cannot execute C source code in Linux (or other systems) directly.
C is a language that requires compilation to binary format.
You need to install C compiler (the actual procedure differs depending on your system), compile your program and only then you can execute it.
Currently it was interpreted by shell. The first two lines starting with # were ignored as comments. The third line caused a syntax error.
Ok,
I got what i was doing wrong.
These are the steps that I took to get my problem corrected:-
$ gedit simple_write.c
Write the code into this file and save it (with .c extension).
$ make simple_write
$ ./simple_write
And I got the desired output.
Thanks!!

multiple definition of main first defined here

I'm new to programming and currently I'm learning C programming. I'm writing codes on the code blocks and in it using GCC compiler. When I create a new project, (as you know it creates main.c file with it) and due to that I'm not able to compile another file in that project.
File 1:
#include<stdio.h>
int main()
{
int a,b,c,d;
printf("Enter three numbers\n");
scanf("%d%d%d",&a,&b,&c);
d=a;
if(b>d)
d=b;
if(c>d)
d=c;
printf("\n The maximum of three numbers is %d",d);
}
File 2: main.c
#include <stdio.h>
int main()
{
printf("Hello world!\n");
return 0;
}
When I compile the first programme, it shows the following error:
multiple definition of 'main'
first defined here
I've searched every where I could and I'm not able to solve this. In one of the answers here on stack overflow, someone had suggested to write this in
(Project->Build options...->Linker settings (tab))
-Wl,--allow-multiple-definition
When I wrote it, there were no errors. But it wasn't able to run my File 1 and instead, it runs that main.c file. Even when I close the main.c file, it opens there again and runs main.c file which gives the output "Hello World!".
Initially when I was using code blocks there were no such errors. I don't know why this is happening and I've not much knowledge about compilers.
As noted in comments you can only have one main function.
So when you start a new project you need to replace the main.c file with the main.c file you want to use. Or you can edit the 'hello world' main.c program.
When you start a new project in code::blocks you can get a new directory with a simple program that prints 'Hello World'. This file is usually main.c. You need to edit this file or replace it. The reason that code::blocks puts this simple main.c program in the new project is so that you can compile it and test your system without having to write a new program.
Some computer languages allow you to use the same function name for different functions ( which are identified by their parameters and sometimes return types ). That's called overloading. C does not allow this. Functions in C must have unique names.
The main() function is a special one in C as it is used as the standard entry point for applications. That is, the main() function will be called first and your application should start and (typically) end in that function.
As a beginner I would suggest you avoid automated editor features that create and build projects for you. You will miss out on learning how things work doing that. Use an editor to start from empty files and learn how they all connect and how to use the compiler from the command line. The command line is something every beginner should start from, IMO.
It may be harder to learn, but it will give you a much better feel for what is going on.
I guess what you maybe trying to do is have multiple sandbox "gists" that you may wanna run all as their own main function. If that is the case, then just close your project and open the files directly. As long as they are not in a project, they will run fine.

How to use bin2h?

I'm trying to use bin2h to convert a font file (font.ttf) into a C file but it won't work.
Can someone please tell me the syntax to save the output to a text file?
I've been trying to figure this out but nothing is working, and it's driving me insane. I'm really frustrated because I know the tool is working (I got it to work like a year ago) but I can't remember how I used it.
The example syntax on that site doesn't really help...
Please
Thanks to Lightness Races in Orbit's comment below I finally got the syntax right!
bin2h -cz font < font.ttf > output.h
That's working, thanks
Perhaps you are looking at the usage example on the website and not realising that it is a program that you execute from shell? It is not a line of C code.
So if you want to use this from a C program, you will need to execute it through a function like system or exec. However, since its output is a line of C code, you'd be better off running it from within your build script to create a C script, that you'd then link in to the rest of your program.
Example (in C++ as my C is rusty — port to C as required):
Source code for main.cpp
#include <iostream>
#include "eula.h"
int main()
{
std::cout << std::string(eula, eula_size) << std::endl;
}
Build commands
$ bin2h -cz eula < eula.txt > eula.h
$ g++ main.cpp -o myProgram
Execution command
$ ./myProgram
I would just write my own.
Here's the algorithm:
Open the source code file as text output.
Open the font file as binary input.
Write the array declaration to the output file, something like:
static const unsigned char font[] =
{
While the font file is not empty do:
Read unsigned char from font file, using binary read methods.
Output the unsigned char, in text format, to the source file.
end-while
Write the ending brace and semicolon to the source file.

Resources