Trailing-Edge
-
PDP-10 Archives
-
SRI_NIC_PERM_FS_1_19910112
-
c/old/kc/cc.doc
There are 8 other files named cc.doc in the archive. Click here to see a list.
CC is a C compiler subset that runs on SAIL and SCORE. Currently, it
supports most of Version 7 constructs that are described in:
Kernighan,B.W.,D.M.Ritchie, "The C Programming Language",
Prentice-Hall, 1978.
Floating point operations has not been implemented yet.
------------------------------------------------------------------------
To run CC, simply say
.R CC; foo
where "foo" is the C source file to be compiled. If an extension is not
explicity given, the compiler will first look for the file "foo.c", and
failing that, it will look for the file "foo".
CC produces a FAIL source that can be assembled and loaded by the usual
means. CC emits code that will load in the neccessary runtime functions
from SYS:CLIB.REL. Included in the package are most of the STDIO
routines given in the reference above.
------------------------------------------------------------------------
CC is basically recursive descent, with expressions parsed by operator
precedence. The C Preprocessor is part of the compiler. Currently, the
following preprocessor functions are defined:
#include
#macro
#ifdef
#endif.
Auto and macro identifiers are unique to 9 characters. Upper and lower
cases are distinguished. Extern and static identifiers are unique only
to 6 characters and upper and lower cases are not distinguished (don't
blame me, FAIL limits me to that).
Short, int and long are all 36-bit words. This may change in the future,
but you can always be sure that int shall always be 36-bits and long is
at least as large as an int and int is at least as large as a short. Int
pointers are implemented simply as 36-bit machine addresses.
A scalar char is stored as a 36-bit word. Char arrays are packed 4 per
word. The arrays (and pointers) are represented as standard DEC-10/20
9-bit bytes (and byte pointers). [Don't worry, char pointers to scalar
char, i.e. &foo, works the way it should...] Char pointers point
exactly at the byte in question, and not at the previous byte, as in
TOPS-20 JSYS conventions (beware, those who want to interface directly
with TOPS-20). Standard STDIO file operations converts 7-bit byte files
to the internal 9-bit bytes so you will not have to do anything special.
In addition, a hack was put in into the runtime to allow files created
with the E directory page to be properly read. SOS-created files may
cause problems.
Float and double are not yet implemented. Struct, union and typedef
are, so all is not lost.
The shift operations (<<, >>, >>= and <<=) are interpreted as logical
shifts.
[This paragraph is intended for those who wish to write assembler
program interfaces. Those who live in the 20-th century may skip this
paragraph.] Arguments to functions are passed by pushing them onto the
stack. The stack pointer is the usual P (AC017). AC0 is used as the
function return value. Arguments are pushed onto the stack so that the
first argument is closest to the return address after a PUSHJ. The
value of the number of arguments is not pushed. Variable-argument calls
are possible if everything depends on the information contained in the
first argument, such as done in printf(). Upon entering a function, the
first argument is addressed via -1(P), the second via -2(P) and so on.
No frame pointer is used, nor is one neccessary. The compiler updates
its internal representation of the stack pointer along the way. The
caller is responsible for popping the arguments back off the stack,
since it is the only one who has knowledge of how many arguments a
function is called with. The callee is responsible for allocating stack
space for auto (local) variables and releasing them before executing a
return.
Some type coercions (casting) are implemented. These are (char) <->
(int), (char *) <-> (int *) and (char *) <-> (struct *).
(int *) -> (char *) and (struct *) -> (char *) make good sense. But, if
you are demented enough to try (char *) -> (int *) or (char *) ->
(struct *), it will try its best, which may still not be what you want.
It simply zeros out the left half of the byte pointer and hands that to
you as the int or struct pointer. I.e., the int or struct pointer
points to the word that contains the character pointed to by the char
pointer.
Int and struct pointers are assured to be zero on the left half-word so
that you can do meaningful comparisons.
The only claim I am willing to make at the moment is that the compiler
will compile itself. Since I write pretty straightforward code, this may
mean little. It has also been used to write two moderate-sized programs
(one is a wire-wrap compiler and the other is one that takes a
description of a logic diagram and produces a schematic diagram in PRESS
format, both at SCORE), so the compiler does work in some fashion. The
code it generates is not super, nor is it rotten. Written in C, it runs
moderately fast, 15,000 to 30,000 source lines per minute, depending on
the amount of white-space in your program.
Please report bugs to KC%SU-AI or CSL.SP.KCHEN%SU-SCORE, whichever is
more convienient. It may take some hours before I find time to fix a
reported bug. You will have to code around the bugs in the meantime.
Those who are weak of heart are advised to stick to PASCAL.