Dennis Cook, Scott Glenn Hopwood, Christopher Fraser,
Lab Assistant and Ex-President Leroy, who has retired
to surf, rob banks and jump out of aeroplanes
The C compiler works in a similar fashion to the Pascal compiler, and can be used to compile single or multiple files. The default C compiler compiles ``traditional'' C, the language defined in the first edition of The C Programming Language (1st Ed.) by Kernighan and Ritchie. See the section on the GNU C Compiler (gcc) for a description of how to compile programs written in ANSI C.
The command for invoking the C compiler is
cc options files
where again, the executable is placed in a file in the current directory and called a.out.
For example, if you have a simple C program in a file called hello.c which looks like this
#include <stdio.h>
main()
{
printf("Hello.\n");
}
...you would compile and run it like this...
sally% cc hello.c sally% a.out Hello. sally% _
As usual, cc reports nothing if the compilation is successful. When it comes to reporting errors, the C compiler tends to be less helpful than the Pascal compiler, but still indicates line numbers, for example
sally% cat hello.c
#include <stdio.h>
main()
{
printf(Hello.\n");
}
sally% cc hello.c
"hello.c", line 5: Hello undefined
"hello.c", line 5: illegal character: '\'
"hello.c", line 5: n undefined
"hello.c", line 5: newline in string or char constant
"hello.c", line 6: syntax error at or near string ");?
sally% _
The C compiler works on multiple files in much the same way as the Pascal compiler. Like the Pascal compiler, you just specify the names of the files on the command line. For example, if your source code were in two files, called square.c and sqr.c, your compilation would look something like this:
sally% cat square.c
#include <stdio.h>
main()
{
int i;
char buf[80];
extern int sqr();
printf("Enter a number: ");
i = atoi(fgets(buf, 80, stdin));
printf("%d * %d = %d\n", i, i, sqr(i));
}
sally% cat sqr.c
int sqr(i)
int i;
{
return i * i;
}
sally% cc square.c sqr.c
square.c:
sqr.c:
Linking:
sally% a.out
Enter a number: 6
6 * 6 = 36
sally% _
Error messages for unresolved external linkages are the same as those generated by the Pascal compiler, as both compilers call ld to link the object files to form an executable.
The standard name of the executable, as you will have noticed, is ``a.out'' -- this can be changed by using the -o option. You might type cc square.c sqr.c -o Square in the above example to generate an executable which could be run with the command Square.
A utility called make exists which allows the user to maintain, update and regenerate object and executable files in a far more elaborate and time-saving fashion. See the manual entry or the Compiling Unix Software chapter for more information.
The other C compiler available on the system is a public domain system provided by the Free Software Foundation, called gcc. This compiler will compile both traditional and ANSI C programs, is invoked by the command gcc, and behaves in a more or less similar fashion to cc. See Kernighan and Ritchie, 1988 for a description of ANSI C and the differences between it and traditional C.
Executables produced by the C compiler have the same lack of run-time support as those produced by Pascal; most trivial errors, especially illegal subscripts will be ignored unless they interfere with the operating system, whereupon they produce core dumps.
A number of debuggers are available for work
with C programs, including dbx,
which functions in the same manner as it does for
Pascal programs
.
There is also an all-singing, all-dancing,
X Windows based debugger called ups;
for further information on this,
see the comprehensive manual entry.
Again, it helps if you compile your C programs
with the -g flag,
to produce debugging information.
The Free Software Foundation C++ compiler, g++, has been installed on the SoCS machines. Consult the manual entry. There's also Borland C++ 4.0 on the 386 PCs on level 2, as long as those dweebs playing DooM and Street Fighter haven't deleted it again.
COBOL? Here's a nice picture instead:
This is what you're really looking in this section for, isn't it? It's a problem really, because Eiffel changes almost every year into something completely strange and unknown, making all manuals out of date, and all the writers of such manuals very rich, because everyone needs the new ones.
Let's see what we can do. In 1996, you could do the following things with
Eiffel compilations
.
This means you can't run thing quickly and easily, but will be in for a
compile which takes an hour or so
...To compile at this nascent stage of your life, you have to
type eifstart when in the directory with your thing.e files
and your Ace file. The Ace file acts much as a Makefile
does
.
After a bit of churning for a which, you'll get some response from the computer. Probably error messages. You'll have to fix those syntax errors and try again, but at least, after one success, you can use...
files, and put them in a directory
called EIFGEN. It will also have created a file called melted.eif.
You can now compile Eiffel programmes using eif. It's much faster than using eifstart, because it doesn't bother to regenerate the files in EIFGEN, it uses the files already there. It also uses the file called melted.eif. There's occassionally another file with the .eif extension generated. Don't delete this one either.
If eif doesn't work, you've probably deleted some necessary file, or
Eiffel's corrupted them, you'll have to clean up your work and use
eifstart again. You can do this by deleting the *.eif files
and the EIFGEN directory
.
An alternative way to clean up is to use...
This does everything I've mentioned above, but maybe cleaner. It may find
little files you don't want that are lurking in corners. It works quite
well, but it's slow. Deleting manually is faster if there's a big load on the
system
.
Use it. Or don't, if you think you know what you're doing. Just don't come running to us when you stuff it up.
in the course of 1996.
Ask your tutor.
The Pascal compiler can be used to compile Pascal programs in single files, as well as large programs in multiple files. Before running the Pascal compiler, you will need to have the directory /usr/lang in your PATH environment variable.
Assuming you have a program in a single file, the command to compile it is pc filename, which leaves an executable file called a.out, which you can run by typing a.out at the command line. For example, if you have a program in a file called hello.p, which looks like...
program hello(input,output);
begin
writeln('Hello.')
end.
...you compile it and run it like this...
sally% pc hello.p sally% a.out Hello. sally%
No messages from the compiler indicate a clean compile. If your program were to contain an error, for example...
program hello_with_error(input,output);
begin
writeln(Hello.')
end.
...the Pascal compiler will indicate with various abusive messages, along the lines of...
sally% pc hello.p
Fri Mar 5 14:52:56 1993 hello.p:
4 writeln(Hello.')
E ------------------------^--- Unmatched ' for string
E ------------------^--- Undefined record
E ------------------------^--- Expected identifier
e ------------------------^--- Replaced character with a ')'
In program hello:
E - Hello undefined on line 4
Compilation failed
sally% _
But what does this all mean? When the compiler finds an error, it prints out the line and its number, and then lists any errors below. Errors marked with a lower case e are minor errors, while errors marked with a capital E are Big Ones, from which your compilation Will Not Recover. In each case, the compiler will point at the position on the line where it thinks things went wrong.
You will note that the a.out file is quite large
;
for the simple program presented here,
it was around 112 blocks.
To save disk space,
you should always delete executable files as soon as
you've finished with them.
When you're dealing with very large programs, you may find it easier to split them across several files. In order to compile several files, just specify them all on the command line. For example if you have a file called square.p containing
(* File square.p *)
program square_a_number(input,output);
function square(var n: integer): integer; extern;
var i : integer;
begin
write('Enter a number: ');
readln(i);
writeln(i, ' squared = ', square(i))
end.
...and the file containing the function square is called sqr.p and looks like this...
(* File sqr.p *)
function square(i : integer): integer;
begin
square := i * i
end;
...you can compile like this...
sally% pc square.p sqr.p square.p: sqr.p: Linking: sally% _
If you declare a procedure or function to be external, but fail to actually define it, your compilation will fail. For example, if you were to try and compile the previous example by just compiling the file square.p you'll get this mess...
sally% pc square.p ld: Undefined symbol _square Compilation failed sally% _
The message you get is from ld, the link driver which links together separately compiled files.
Occasionally, program will contain errors serious enough
to cause them to abort, or ``crash''.
Unfortunately, the Pascal compiler does not generate particularly
robust executable files;
errors will not generally be detected until the program starts
interfering with the operating system,
typically by trying to access a memory location outside
it's own segment
.
When it does crash, it copies the area of memory it was
working with into a file called core in the current directory;
this is what the message Core Dumped means.
The core file is dumped in the hope that the user
can use it to carry out some form of autopsy and find out
why it died
.
Trouble is, while the core files produced by the executables from the various C compilers are useful, the ones produced from Pascal executables are generally about as much use as a sense of tact is for a drag queen. At this point a debugger becomes useful.
dbx is a fairly simple debugger that will work on executables produced by just about any compiler. In order to use it effectively, compile your Pascal programs with the -g flag, i.e. pc -g thing.p This tells the compiler to generate a symbol table for use by dbx and any other debuggers; amongst other things it associates memory addresses with variable names, and with actual lines of code in the source files.
To run dbx, type dbx filename, where filename is the name of your executable file, usually a.out. It will then load the executable, and give you a (dbx) prompt. At this point, the easiest way to see where you program crashed is to type run. For example, assuming our program looked this...
program stuff_up(input,output);
var a : array [1..10] of integer;
i : integer;
begin
i := 10;
repeat
a[i] := 1;
i := i - 1
until i = 10
end.
...the session might look something like this...
sally% pc -g stuffup.p
sally% a.out
Bus error (core dumped)
sally% dbx a.out
Reading symbolic information...
Read 259 symbols
program terminated by signal BUS (alignment error)
(dbx) run
Running: a.out
signal SEGV (access to address exceeded protections)
in program at line 9 in file "stuffup.p"
9 a[i] := 1;
(dbx) print a[i]
subscript out of range
(dbx) print i
i = -1860
(dbx) print a[1]
`a[1] = 1
(dbx) quit
sally% _
A number of things are demonstrated here.
One way to get around that is to compile the program with the -C flag, i.e. pc -g -C files, which causes the compiler to build in code to check for this. In the case of this example, the program will crash when i is set to zero; reporting it with a message like
sally% a.out Overflow/Subrange/Array Subscript Error. *** Program execution terminated by trace trap End traceback. Trace/BPT trap (core dumped) sally% _
signal SEGV in program at 0x22e0 program+0x38: st %o3, [%o1 + %o2]