Invoking BDS C using C.SUB Overview of the BDS C Language System Overview -- C Compiler, Pass 1 Overview -- C Compiler, Pass 2 Overview -- C Linker Overview -- C Librarian Overview -- C Skeleton File Variable Types Braces Variable Accessing ARIES-1 C Library Special I/O using CIO :Invoking BDS C using C.SUB BDS C may be invoking either by the conventional means or by using the SUBMIT file C.SUB. If the SUBMIT file is used, it is engaged as follows -- SUBMIT C filename where 'filename' is the name of 'filename.C', the file to compile. Note that the user is NOT to to type filename.C, but is just to type filename. As execution of the two passes of the compiler and the linker proceeds, the user will be given the chance to abort processing at various critical points in the process by the execution of the ABORTSUB program. If an error has occurred during the previous processing, ABORT when this program is executed. :Overview of the BDS C Language System The main components of C are: 4 executable programs, a standard library file, and one skeleton run-time subroutine file. A description of each follows: :Overview -- C Compiler, Pass 1 CC1: Because C loads the entire source file into memory in one shot, the compilation is broken up into two phases (not "passes", strictly; The two phases end up taking about 8 passes to actually implement), maximizing the amount of memory available for the source file. CC1, the first half of the compiler, accepts a C source file with any filename and extension (say, "foo.c") and writes out a temporary file (with the same filename and extension ".CCI") containg a symbol table and an encoded form of the source code. The file extension ".C" is NOT assumed for the input file, so saying "FOO" for "FOO.C" would not work. If the source file name is preceded by a disk designation, then the input is taken from the specified disk and the ouput is also written to that disk. If any errors are detected during CC1, the output file will not be written. In addition to the name of the source file, a few options may also be specified on the command line by preceding the option list with a dash (-): s causes undeclared identifiers to be implicitly declared as integer variables, wherever possible. hex digit (4-f) sets symbol table size to the specified value (in K bytes); default is 8 (5 for versions x.xT.) For example, A>cc1 foobar.c -s6 supresses errors for undefined variables and sets symbol table size to 6K bytes; A>cc1 zot.c -e sets symbol table size to 14K bytes. Note that the option list must contain no blanks. A>cc1 b:td.c takes the source file from disk B and writes the .CCI file to disk B (regardless of what the currently logged disk is.) On an 8080, speed is about 12 lines source/sec. :Overview -- C Compiler, Pass 2 CC2: This is the second half of the compiler. CC2 accepts a ".CCI" file as input, and writes out a ".CRL" file if no errors are detected. (CRL is mnemonic for 'C ReLocatable') If all goes well, writing out of the CRL file is followed by deletion of the "CCI" file, and compilation is complete. As for CC1, if a disk is specified explicitly as in A>cc2 c:yahoo then the .CCI file is loaded from the specified disk and the .CRL file is written to that same disk. On an 8080, execution time = about 35 lines/sec. :Overview -- C Linker CLINK: This program links a "main" function from some CRL file together with C.CCC (for common system subroutines) and any subordinate functions which "main" may require (from perhaps many CRL files). A successful linkage causes a ".COM" file to be generated. At this point, the 8080 absolute machine code file is ready to be executed (for better or worse) as a transient command by CP/M. The first argument on the command line must be the name of a CRL file containing a "main" function. If the name is specified with an extension, then that extension is interpreted specially as indicating which disks are to be involved in the operation (this is akin to the mechanism ASM uses to determine source and destination disks.) For example, if the first argument to CLINK were given as: A>clink foo.bc then CLINK would interpret the "b" in ".bc" as specifying the disk on which "DEFF.CRL" and "C.CCC" are to be found, and the "c" in ".bc" as specifying which disk the .COM file is to be written to. Both of these values, if omitted, default to the currently logged in disk. The first argument may also be preceded by a disk designation, to specify where all .CRL files are to be searched for (by default). For example, the command A>clink b:zot.ac tells CLINK to get C.CCC and DEFF.CRL from disk A; to write the ouput file to disk C; and to find ZOT.CRL on disk B. Any other CRL files to search may also be specified on the command line (WITHOUT their .CRL suffixes), causing those to be searched in the order specified. The default disk to search will be the same disk from which the original CRL file was taken; this default can be overridden by specifying an explicit disk designation for any appropriate CRL file name needing it. For example, A>clink c:foo.bb bar a:zot fraz causes disk C to be searched for the files FOO.CRL, BAR.CRL and FRAZ.CRL, while disk A would be searched to find ZOT.CRL. Disk B is where CLINK would expect DEFF.CRL and C.CCC to reside, and the output would go to disk B also. When all given CRL files have been searched, CLINK will automatically search DEFF.CRL. If there are still some unresolved references, then CLINK will ask for input from the keyboard to try resolving them. There are also several options which may be specified on the command line. Each option must be preceded by a dash (-); the space between options and their argument (if needed) is optional. The presently supported options are: -s Prints out load statistics; -t nnnn Reserves location nnnn (hex) and above for user; default is to reserve no space. What this really does is to cause the first op in the object file to be lxi sp,nnnn instead of lxi sp,bdos. -o name Causes the .COM file generated to have the given name. Default is the name of the first .CRL file given (the one with the "main" function.) -e xxxx Sets start of data area to address xxxx, to maintain consistency between several separate .COM files when chaining (via the library function "exec") is used. -c Specifies that the .COM file is to be chained to from another .COM file. If the resultant .COM file is invoked directly from CP/M instead of via the "exec" function, then ARGC & ARGV processing is suspended, since upon being chained to you wouldn't want ARGC & ARGV processing to take place. Note that if you use this option, you should also use the -e option to set the data area address equal to that of the chaining .COM file. Examples: A>clink foo bar gets "main" from the file FOO.CRL, searches for needed functions first in FOO.CRL and then, if needed, in BAR.CRL and DEFF.CRL. All files are assumed to reside on the currently logged in disk. A>clink b:ihtfp belle -s searches for IHTFP.CRL and BELLE.CRL on disk B; prints a statistics summary when linkage is complete. The files DEFF.CRL and C.CCC are assumed to reside on the currently logged in disk; output also goes to the currently logged in disk. A>clink b:ihtfp.aa -s belle -o zot is the same as the last example except: the output file is called ZOT.COM, DEFF.CRL and C.CCC are assumed to reside on A, and output goes to A. A>clink stoned -t7000 -s sets top of memory to 7000h and prints out load statistics. Current disk used for everything. Note that if the load statistics tell you that the "LAST ADDRESS" is greater than the "TOP OF MEMORY", the program hasn't got the chance of a snowball in hell of running correctly. :Oveview -- C Librarian CLIB: This program maintains .CRL files, allows transfer of functions from one CRL file to another, etc. To invoke CLIB, just type A>clib Clib will print a line such as FUNCTION BUFFER SIZE = nnnnn specifying the largest function size that can be handled. Attempting to "transfer" or "extract" a function larger than this size could be destructive. Next CLIB will prompt with a "*". Typing "h" at this point will give you a command summary. Basically, you work CLIB by opening one to six CRL files (which then become associated with "file numbers"), diddling the files to your hearts content, closing all files which you altered, and typing control-C. The old version of any CRL file you change with CLIB is renamed to name.BRL (for Backup ReLative). A sample session of CLIB to, say, transfer the functions named "FOO", "BAR", and "ZOT" from a .CRL file named "DSSR" to one named "RTS" would go as follows: A>clib BD SOFTWARE C LIBRARIAN VERSION x.x FUNCTION BUFFER SIZE = xxxx BYTES * open 0 dssr * open 1 rts * t 0 1 foo * t 0 1 bar * t 0 1 zot * c 1 * ^C A> ... The "open" commands prepare to do work on a .CRL file, and associate each .CRL file opened with a digit (0-5). The "transfer" commands tell CLIB to transfer the named function from the first file (named by file #) to the second file (also named by number). The "close" command need only be given for files which have been altered; since DSSR wasn't written to in the above example, it didn't need to be closed, but RTS did need to be closed. DEFF.CRL: This file contains the standard function library... all 60+ functions worth. See the BDS C User's Guide for documentation on these functions. :Overview -- C Skeleton File C.CCC: The run-time skeleton file, containing code for processing the command line (generating argc and argv, for you UNIX lovers), room for file I/O buffers, some math subroutines, etc. Note on the BDS C compiler: THIS IS NOT AN INTERPRETER. Some hacks, such as BASIC-E, are billed as compilers but actually just do some preprocessing and then interpret the program. BDS C is a true compiler, generating not-too-optimal but nevertheless quick 8080 code. For the gory details on the BDS C implementation, see my notes to APPENDIX A of the EXCELLENT book "The C Programming Language." :Variable Types Variable types supported: int char unsigned struct union arrays (of one or two dimensions) pointers simple combinations of the above For example, char *foo[10][15]; declares foo to be a two dimensional array of pointers to characters; char (*foo)(); declares foo to be a pointer to a function returning a character; char *foo, bar, zot[10]; declares foo to be a pointer to characters, bar to be a single char variable, ant zot to be an array of 10 characters. :Braces If your keyboard doesn't support the '{' and '}' characters (open and close brace, for those of you whose printer doesn't know about ascii 7B and 7D), the symbols 'begin' and 'end' may be substituted. Don't unless you have to; '{' and '}' take up less memory. The CONVERT program will perform this conversion, if necessary. :Variable Accessing Since all functions in C may be used recursively, all variable accessing is done relative to a base-of- stack-frame pointer, kept in the BC register pair during execution. Note that it takes 8 bytes of code to transfer a simple local variable whose address is (Base of stack pointer) + foo to the HL register pair; The code appears as: lxi h,foo dad b mov a,m inx h mov h,m mov m,a . To get an array element or structure element is even more hairy. Facts like this are enough to make me REALLY wish Intel had bothered to implement a double byte indirect load instruction. Oh well. :ARIES-1 C Library The following are the names of the routines available in the C Library DEFF.CRL. They are listed here as a memory convenience, and refer to the manual for further details. 1. General Purpose Functions csw() exit() bdos(c,de) peek(n) poke(n,b) inp(n) outp(n,b) pause() sleep(n) call(adr,h,a,b,d) abs(n) srand(n) rand() setmem(adr,count,byte) movmem(source,dest,count) qsort(base,nel,width,compar) char *source, *dest; char *base; int(*compar)(); exec(name) char *name; 2. Character Input/Output getchar() ungetch(c) kbhit() putchar(c) puts(str) char *gets(str) char *str; char *str; printf(format,arg1,arg2,...) scanf(format,arg1,arg2,...) char *format; char *format; 3. String and Character Processing isalpha(c) isupper(c) islower(c) isdigit(c) char c; char c; char c; char c; touppper(c) tolower(c) isspace(c) strcat(s1,s2) char c; char c; char c; char *s1, *s2; strcmp(s1,s2) strcpy(s1,s2) strlen(str) atoi(str) char *s1,*s2; char *s1,*s2; char *str; char *str; initw(array,string) initb(array,string) int *array; char *string; char *array, *string; getval(strptr) char **strptr; 4. File I/O creat(filename) unlink(filename) char *filename; char *filename; open(filename,mode) close(fd) char *filename; {mode=0 - input, mode=1 - output, mode=2 - input and output} read(fd,buf,nbl) write(fd,buf,nbl) char *buf; char *buf; seek(fd,offset,code) tell(fd) fopen(filename,iobuf) fcreat(filename,iobuf) char *filename; char *filename; struct buf *iobuf; struct buf *iobuf; getc(iobuf) putc(c,iobuf) struct buf *iobuf; char c; struct buf *iobuf; getw(iobuf) putw(w,iobuf) struct buf *iobuf; struct buf *iobuf; fflush(iobuf) struct buf *iobuf; 5. Plotting Functions (for Memory-Mapped Video Boards) setplot(base,xsize,ysize) clrplot() plot(x,y,chr) char chr; txtplot(string,x,y,ropt) char *string; line(c,x1,y1,x2,y2) 6. Plotting Functions for Hazeltine 1500 clear() cplot(x,y,chr) char chr; ctxtplot(x,y,string) char *string; 7. Special I/O -- CIO cio(fn) or cio(fn,arg) CIO indexes directly into the BIOS Jump Table. 'fn' is the index offset, and 'arg' is an argument passed (up to 16 bits). The offsets and functions permitted are -- Offset Function 0 CONST -- Console status; Returned value = 0 if no char ready, 255 if char ready 1 CONIN -- Console input; Returned value = char typed 2 CONOUT -- Console output; Input value = char to output 3 LIST -- List output; Input value = char to output 4 PUNCH -- Punch output; Input value = char to output 5 READER -- Reader input; Returned value = char input :Special I/O using CIO CIO is called by -- cio(fn) or cio(fn,arg) CIO indexes directly into the BIOS Jump Table. 'fn' is the index offset, and 'arg' is an argument passed (up to 16 bits). The offsets and functions permitted are -- Offset Function 0 CONST -- Console status; Returned value = 0 if no char ready, 255 if char ready 1 CONIN -- Console input; Returned value = char typed 2 CONOUT -- Console output; Input value = char to output 3 LIST -- List output; Input value = char to output 4 PUNCH -- Punch output; Input value = char to output 5 READER -- Reader input; Returned value = char input