Compiler Sources
Source files in ANSI C for a compiler for a large subset of C.
There is no doubt that there must be some things that I forgot about,
and even a few bugs, but it does work. It was developed under
FreeBSD, but uses nothing specific, so should work equally under
any system supporting C.
Recommended Procedure: create a subdirectory to contain
only the compiler sourse files, and download everything into it. I have
changed the file names so that they all end in ".txt". This should prevent
your software from trying to do anything strange with them. After
downloading, change any file name that ends in "c.txt" to end in ".c"
and any that ends in "h.txt" to ".h" (for example, cgc.txt and cgh.txt
should be changed to cg.c and cg.h).
The files are as follows:
When you have all the files, compile each one separately, using
the command (for example) cc -c io.c This way, when you
make a
change, you will only have to recompile the single changed file.
When you have compiled all the files, link together the object files
with the command cc *.o -o comp This will only
work if you have all the
files in a subdirectory with nothing else. Otherwise you will have to list
all the .o files separately: cc io.o la.o pa.o sa.o cg.o main.o -o
comp
Run the compiler by typing comp (which will expect you to type
a C program, or to read one from a file, comp filename.
The compiler produces a file called a.asm containing the
assembly code that it generates. To actually run the generated code,
you must also download and compile the assembler and machine emulator:
When those four or five files have been downloaded, compile them
independently with these commands: cc as.c -o assem
and cc ex.c -o execute. Do not use the -c
flag to produce an object (.o) file, because it will get mixed in
with all the other object files and cause millions of errors when
you recompile the compiler with cc *.o -o comp.
Once your compiler
has produced an assembly code file (a.asm), you should look at it first
to make sure it seems to be more-or-less OK. Then the command assem
will assemble it. The assembler automatically looks for a file called
a.asm and creates a pretend xeecutable file called a.exe.
To run it, just type the command execute. The emulator automatically
load a file called a.exe and runs it.
If you want to debug
or trace the execution of a program, execute can take up to two options:
execute -trace runs the program, printing every
instruction before it is executed, together with the first few things
on the stack. execute -step does the same as -trace
plus it waits for input before executing each instruction, allowing the
user to inspect the contents of memory before continuing. If you run
a program without the -step option and it gets stuck in a loop,
typing control-C will turn the step option on.
Naturally, I didn't implement the whole C library. The compiler I've
provided understands exactly five library functions: printint(i),
printfloat(f), printstring(s), i=readint(),
and f=readfloat(). The print functions take one parameter of
the obvious type, print it on standard output, and return nothing. The
read functions
take no parameters, read a value of the obvious type for standard input,
and return that value. You do not need to declare these functions,
just use them.
Note that the slightly modified syntax used by this compiler
requires that every declaration, even of a function with its body,
must be terminated by a semicolon (for example:
int f() { x=1; };) which would be wrong in
standard C. You do not see the output produced for a declaration until
the first symbol following that declaration has been accepted,
so if you are using the system interactively, you might like to enter
another extra semicolon after each function.