IMD 1.18: 30/01/2015 20:28:56 BIG BOARD USER DISK #17 Micro Cornucopia PO BOX 223 Bend, OR 97709  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  CRC COMD COM IOLIB ASM  IOLIB ASMJ!"#$%&'()*LIBL BAKLIBL H CC22 C >CC3 C CC2 C SMALLC DOC17A-DISKDOC SMALLC2 DOC/ #e w~ T #>2 @ - s M@ File not found ! 4 >2 o: G: „: G: „@ *Match* 2 !PRINTF C =>SIGN C ?CC DEF CC41 C 1͔0CRCKLIST???CRCKFILE???!9" M à*,*.}|ډ!".*,{z{** u*.".G*.",SMALLC DOC OP`abcSMC COM+,-./01245:;<@ABSMC COMCDFGHIJKLMRSTUVWSMC COMXY]CC31 C 6CC32 C *CC33 C "CC4 $$$CRCKLISTCRC SAMPLE DOC6HELLO C CALL REL  4@ <-- is, was --> : ) > T : ) M 2 ! 4<2 ~# @ Not a space between CRC values<2 G-CATALOG???STRCMP C ECC13 C ;CC22 C FUTOI C N!".***,}>*.#".ɯ22)! ",". <  NO FILECRC FILE$!   >. @ Checking wiCALL ASMLZ[\^_dCC11 C RefghijklmnoCC21 C 1pqrstuvDTOI C 3SMC COMABS C STD H MAKE SUB@ ++ Now searching for "-CATALOG" file++ !  ) .) ! ”>.”#””͡”››tK›STDIOA H CC4 C XTOI C QCC31 C Bth file - ! ~T #M M 2 2 2 2 ! >2 3o: : @ ***No CRC Files found***$> ʉ ʉw#: CC12 C ?wxyz{|}~ITOD C 6ITOU C 7ITOX C 8#CRC.COM 5.0 6/18/82CRCKFILE???!9" 1 M @ CRC Ver 5.0 CTL-S pauses, CTL-C aborts :] O@ ++Searching for CRCKLISTSMC COMSMC COMLIB BAKLIB C :›͸›* =: =͔="  ʳ ª~#.  ¿~  #~  .+~#0CC32 C +CC33 C $CC1 C -CC3 C <2 P6: .6@ Can not parse string ! ~ʽT #ñM ! > 6 #6^#6! ~T #! 4M #x]LEFT C 9OUT C LIBASM C CC42 C E file++@ Now searching for "CRCKFILE" file++ !  1 .) F!  ͡]͸!  :0~#!A.O.Gy~#0M0 K MMɷ:m2 FSÄCRCKLIST$$$››tK›,!4w_#~ ʸ A:4~~# ¼ > \ ?ʻ w# !ͼ ? !ͼ  ++ABORTED++$ : ~ 2 M @ Quantity of file CRC that matched - : ̓ :  M @ Quantity of file CRC that did notww*C#[E *C:K( ~#( ( #:6yw~(#.~(#~^*<"<;?k`OPEN FAILED++ !" !" * | ʹ) \!~2 #" Ý: ) > T : ) @ ++FILE READ E`ƀo&"C0y"Ey *E8 x[E8x8 g x(x0}MyD8yx~w*@&[ › **}|!"*{z*~]*"Ü  DISK FULL: CRCFILE$!"*~x }I~24~21~25nf"2>(>2Knf"/*~624~72125n8&"2n5&"/BK80)x match - : ̓ : J M @ Quantity of lines failed parse test - : ̓ : ~ M @ Quantity of file(s) not found - : ̓ *o*2>2:͟0 x ;::=2: >2:~2;#:;2;*1,&̓xGyOzW{_ #q#!Y!YO RROR++ <* |): o% |g}o" 2  ; 0T ~T #~A > T > _h : F{͇2h2T{(#">:29262827:6!8_!@0:7( {@:>!8w:72 s : ~# ++FILE NOT FOUND++$:sz2{2"G!"I:2:2Ҽ*GҶ*I DM:g:*G)"G*I)#"IÛ<)KB7B0 = d͔  ͔ 0T  Җ Wyʩ 0T 0ztiil~o&)))Y *C#N?(7#Ÿw#(pO)͎ /‡ G)/‡ ͻ #yOzW{_ #q#!Y!YO |: ʲ !\   :\2 ! \  \ ! \  \! \  \<7=Ɓo&   ]  2:68:(*1&#))*/#) !|, !y9) /|B#|/W}/_*2#;?k) UNUSED Entries/Bytes: *A}/o|/g#* F*}’">͇†]<  CANNOT CLOSE CRCFILE$CRCKLISTCRCSK FULL: CRCFILE$  w|}/o|/g# ~˿(~#(_0~#OF#|  {0} (>- x( 8G( sL1Y_OʊQ>ÖH >2 2 û: B­>ôD> ¸!52 !"!N#~#A07O! ~*!) " h2|2   ~$#~# x  : F} *}= ">͇1 ] FILE: XXXXXXXX.XXX CRC = oS) \<‘@ ++:@( =Gw {L!>2K"<!]~  ?N >?2h!\~(_00A2ɯ2@!"A\0*A#"A :  '<ͭ'<>V$>O$:Ğà\ÞØ`rÍÖthe language C. It consists of the two files C80.C (compiler) and C80LIB.I80 (runtime library) It is in source form and is fr M x_BH!œ#¶ ¦{KÈCÈ<:JCR:  !6 s! intermediate files were avoided in order to conserve floppy space. COMPILER SPECIFICATIONS As of this writing, the cons */ /* called by these functions */ #include "abs.c" #include "dtoi.c" #include "itod.c" #include "itou. its own syntax checking and parsing and produces no intermediate files). (6) It can compile itself. This means any processoee to anyone wishing to use it. Characteristics of the compiler are as follows: (1) It supports a subset of the language C.#  ɯ<:O=_Z!F!V#fjQ̓E!^#Vo&)~#FxGyѯ<àn8mpiler supports the following: (1) Data type declarations can be: - "char" (8 bits) - "int" (16 bits) - (by placing anc" #include "itox.c" #include "left.c" #include "out.c" #include "printf.c" #include "sign.c" #include "strcmp.c" #includr supporting C can be used to develop this small C compiler for any other processor. The intention behind the writing of ![w#w#b!"!F#v2[ (see the book "C A Programming Language", by Brian Kernighan and Dennis Ritchie.) (2) It is written in C itself. (3) It!~ڢͅ6~44O! s#r!~ ڿ6ͅ^4!mw!wp!~ͅ!55N! N#fio&)^#fk "*" before the variable name, a pointer can be formed to the respective type of data element). (2) Arrays: -single dime "utoi.c" #include "xtoi.c" this compiler was to bring the C language to small computers. It was developed primarily on a 8080 system with 40 K bytes andG*##~w*##~<*}q!~ڬ6![^![^#fk"͎͘!G#*####*^#Vû!^*"* is syntactically identical to the C on UNIX (unlike some other small C compilers and interpreters). (4) It produces as ou c80.doc >>> Small C-compiler documentation <<< Available in the directory is a compiler for a subset of ension (vector) arrays can be of type "char" or "int". (3) Expressions: -unary operators: "-" (minus) "*" (indirecti?'  v:P@< !  PP27 ( *"  NZZ NCC POPEP a single mini-floppy. Consequently, an effort was made to keep the compiler small in order to fit within limited memory, and /* ** lib.c -- function library ** ** Copyright 1982 J. E. Hendrix */ #define NOCCARGC /* don't pass arg count to functiotput a text file suitable for input to an 8080 assembler. (5) It is a stand-alone single-pass compiler (which means it does on) "&" (address of) "++" (increment, either prefix or postfix) "--" (decrement, either prefix of postfix) -binary op#asm...#endasm else..." (7) Miscellaneous: -Expression evaluation maintains the same hierarchy as standard C. -Functstatic pointers can contain the address of "char" or "int" data elements. (6) Compiler commands: - #define name string (prive) functions. COMPILER RESTRICTIONS Since recent stages of compiler check-out have been done both on an 8080 system ction(arg1, arg2,...,argn) -constant -decimal number -quoted string ("sample string") -primed string ('a' or 'Z'  top of the stack) generate calls to library routines to shorten the amount of code generated. -Generated code is "pure"erators: "+" (addition) "-" (subtraction) "*" (multiplication) "/" (division) "%" (mod, i.e. remainder from division calls are defined as any primary followed by an open paren, so legal forms include: variable(); array[expressione-processor will replace name by string throughout text.) - #include filename (allows program to include other files witand on UNIX, language syntax appears to be identical (within the given subset) between this small C compiler and the standard or 'ab') -local variable (or pointer) -global (static) variable (or pointer) (4) Program control: -if(expression)statem (i.e. the code may be placed in Read Only Memory). Code, literals, and variables are kept in separate sections of memory.ion) "|" (inclusive 'or') "^" (exclusive 'or') "&" (logical 'and') "==" (test for equal) "!=" (test for not equal](); constant(); function()(); -Pointer arithmetic takes into account the data type of the destination (e.g. pointehin this compilation.) - #asm (not supported by standard C) Allows all code between "#asm" and "#endasm" to be passed unUNIX compiler. Not supported yet are: (1) Structures. (2) Multi-dimensional arrays. (3) Floating point, long integer, or uent; -if(expression) statement; else statement; -while (expression) statement; -break; -continue; -return; -retur -The generated code is re-entrant. Everytime a function is called, its local variables refer to a new stack frame. ) "<" (test for less than) "<=" (test for less than or equal to) ">" (test for greater than) ">=" (test for greater++ will increment by two if pointer was declared "int *pointer"). -Pointer compares generated unsigned compares (sincchanged to the target assembler. This command is actually a statement and may appear in the context: "if (expression) nsigned data types. (4) Function calls returning anything but "int". (5) The unaries "!", "~", and "sizeof". (6) The control n expression; -; (null statement) -{statement; statement; ... statement;} (compound statement) (5) Pointers: -local and By way of example, the compiler uses recursive-descent for most of its parsing, which relies heavily on re-entrant (recursr than or equal to) "<<" (arithmetic left shift) ">>" (arithmetic right shift) -primaries: -array[expression] -fune addresses are not signed numbers). -Often used pieces of code (i.e. storing the primary register indirect through the   #asm ; ;------------------------------------------------------------------ ; Small-C Run-time Library (ASM Version) ; ;  MOV A,M ; ;PUT THE ACCUM INTO HL AND SIGN EXTEND THROUGH H. ; CCARGC: CCSXT:  ; M80 EQU 1 ; Compiler compiled with #define M80 ; to generate short names B ; ;STORE A SINGLE BYTE FROM HL AT THE ADDRESS IN DE ; CCPCHAR: PCHAR: MOV A,L STHAR() print LF after reading CR. ; Made GETCHAR() return -1 on EOF (=CTRL-Z) ; Added EOL and LF equates, instead of maX H MOV A,L STAX D RET ; CCINCC: INX H INX H DAD SP MOV ; V3b As of June 9, 1980 12pm (rj) ; corrected cp to chp in @gets ; changed lower case to hex constants in @fopen and MOV L,A RLC SBB A MOV H,A RET ; CCDDGI: DAD D JMP CCGINT (unique in 6 chars). ; Set to 0 if compiler NOT compiled with M80 ; switch. AX D RET ; CCDECI: INX H INX H DAD SP MOV D,H MOV E,L Cgic numbers ; V4d As of July 16, 1980 9:00 pm (gtf) ; Added EXIT() function ; V5 As of April 12, 1983 12:30 am (br) ;  D,H MOV E,L CALL CCGCHAR INX H MOV A,L STAX D RET ; ;  fcb ; V4 As of June 26, 1980 12:15pm (gtf) ; Changed all @'s and ?'s to "QZ" for ASM compatibility ; V4b As of July 7, 1 ; CCDSGI: INX H INX H DAD SP ; ;FETCH A FULL 16-BIT INTEGER FROM THE ADDRESS  ; CCDDGC: DAD D JMP CCGCHAR ; CCDSGC: INX H INX H ALL CCGINT DCX H JMP CCPINT ; CCINCI: INX H INX H DAD SP MOV D,H Modified to reuse package for Small-C, ver 2. ; Removed "QZ" in front of names. ; Added runtime initialization and IF M80 ; use short symbol name CCDDPC: ENDIF IF NOT M80 ; use full length name CCD980 3:00 pm (gtf) ; Changed putc() to test code returned by cput() ; V4c As of July 9, 1980 9:15 pm (gtf) ; Fixed bugIN HL ;INTO HL ; CCGINT: MOV A,M INX H MOV H,M MOV L,A RET  DAD SP ; ;FETCH A SINGLE BYTE FROM THE ADDRESS IN HL AND ;SIGN EXTEND INTO HL ; CCGCHAR:  MOV E,L CALL CCGINT INX H JMP CCPINT ; ; IF M80 ; use s #asm ; ;----- call.a: Small-C ver. 2 arithmetic and logical library ; (ASM Version 7-28-83, Bill Randle) ; DPDPC: ENDIF ; DAD D CCPDPC: POP B ;;RET ADDR POP D PUSH  in CPMIO which returned wrong error status. ; Added PUTS() function ; Un-hardwired I/O buffer count. ; Made GETC ; CCDECC: INX H INX H DAD SP MOV D,H MOV E,L CALL CCGCHAR DC hort symbol name CCDDPI: ENDIF IF NOT M80 ; use full length name CCDDPDPI: ENDIF  ; CCGE: CALL CCCMP RNC DCX H RET ; ;TEST IF DE < HL (SIGNED) CEQ: CALL CCCMP RZ DCX H RET ; ;TEST IF DE <> HL ; CCNE: le] ; ======================================== ; NULL EQU 0 ;pointer to nothing FCBSIZE EQU 36 ;size, in bytes, of an FCB NDE INTO HL ; CCXOR: MOV A,L XRA E MOV L,A MOV A,H XRA D MOV H,A; V5d As of July 29, 1983 7:47am (br) ; Fixed GETC()/CGET() so it skips check for CR when ; calling GETCHAR(). ;---- ; DAD D CCPDPI: POP B ;;RET ADDR POP D PUSH B ; ;STORE A  command line ; processing from RUNTIM.MAC [by Bill Danielson, 3/83]. ; Added I/O redirection for stdin and stdout. ; CALL CCCMP RNZ DCX H RET ; ;TEST IF DE > HL (SIGNED) ; CCGT: EXTP EQU 0 ;offset to next-character pointer in I/O structure UNUSED EQU 2 ;offset to unused-positions-count in I/O structure  RET ; ;"AND" HL AND DE INTO HL ; CCAND: MOV A,L ANA E MOV L,A -------------------------------------------------------------- ; ; *** may need following statement when using ASM *** ORG 116-BIT INTEGER IN HL AT THE ADDRESS IN DE ; CCPINT: PINT: MOV A,L STAX D INX D MOV A,H  Added FPUTS(), FGETS(), DOLDDR(), DOLDIR(), ; UNLINK() and ABORT() functions. ; V5a As of April 14, 1983 12:55 pm (b XCHG CALL CCCMP RC DCX H RET ; ;TEST IF DE <= HL (SIGNED) ; BUFFER EQU 4 ;offset to disk sector buffer in I/O structure FLAG EQU 33 ;file-type flag byte (in unused part of FCB) FREEFLG E MOV A,H ANA D MOV H,A RET ; ;IN ALL THE FOLLOWING COMPARE ROUTINES, HL IS 00H ; *** ; JMP START ; ; *** delete following extern when using ASM *** ; EXTRN MAIN, CCDSGI, CCSXT ; *** ; ; ======= STAX D RET ; ;INCLUSIVE "OR" HL AND DE INTO HL ; CCOR: MOV A,L r) ; Masked parity bit in compares for EOL, LF & ^Z. ; V5b As of July 19, 1983 9:50 pm (br) ; Fixed bug in FCLOSE().  CCLE: CALL CCCMP RZ RC DCX H RET ; ;TEST IF DE >= HL (SIGNED) QU 128 ;This I/O structure is available for the taking EOFFLG EQU 2 ;The end of this file has been hit WRTFLG EQU 1 ;This fileSET TO 1 IF THE ;CONDITION IS TRUE, OTHERWISE IT IS SET TO 0 (ZERO). ; ;TEST IF HL = DE ; C================================= ; I/O subroutines for CP/M ; By Glen Fisher ; The Code Works(tm) ; [modified by Bill RandORA E MOV L,A MOV A,H ORA D MOV H,A RET ; ;EXCLUSIVE "OR" HL AND  ; V5c As of July 27, 1983 9:55 pm (br) ; Fixed bug in initialization of RSTDIN and RSTDOUT. ; Fixed bug in PUTS().   open for writing BUFSIZ EQU 128 ;how long the sector buffer is NBUFS EQU 4 ;number of I/O buffers (change buffer declarationscond thing, we run through the CPM input line and ; modify it so that we can pass the C program the ; command line in the argc: DS 2 ;I/O structure address to act on IP: DS 2 ;int *ip; CHP: DS 2 ;char *chp; DP: DS 2 ;char *dp; FILE: DS 2 ;file name er to CPM arg line LDAX D ; Load # character in line MOV B,A ; Save it in B NXTSP: INX D ; Point to next character DCR B 21 ;write a sector ; LF EQU 10 ;line feed EOL EQU 13 ;end-of-line character (=carriage return) CTRLZ EQU 26 ;end-of-file mar LXI H,STDOUT SHLD RSTDOUT ; Init rstdout MVI C,0 ; Init argc LXI H,ARGV ; Pointer to first entry of argv array ; Unf, too) ; CP/M system call codes CLOSE EQU 16 ;close a file CPMSTR EQU 9 ;print '$' delimited string on console CREATE EQU 2, argv form that it expects ; HL = pointer to next argv entry ; DE = pointer to next character in command line ; B = numberMODE: DS 2 ;char *mode;(read or write) ZCH: DS 2 ;char ch; ZT: DS 2 ;int t; FN: DS 2 ;int fn; i/o function (for cpmio) ; SV; Decrement character count JM ENDCMD ; End of cmd line LDAX D ; Load next character in line CPI ' ' ; Space? JZ NXTSP ;k for text files TBUFF EQU 80H ;address of default I/O address BDOS EQU 5 ;Entry point to CP/M BDOS CPMARG EQU 80H ;CP/M commortunately, CPM does not tell us what the first word of ; the command line was (the name of pgm), so we fake ; it by pointing 2 ;make a file DMA EQU 26 ;set DMA (I/O address) DELETE EQU 19 ;delete a file GETCH EQU 1 ;read character from console GETST of characters left in line ; C = argument count (argc) START: LXI H,0 ; Get CPM's stack pointer DAD SP SHLD STACK ; SavCHP: DS 2 ;char *svchp; saved character pointer RSTDIN: DS 2 ;int rstdin; unit of redirected stdin RSTDOUT: DS 2 ;int rstdout; Yes...continue searching CPI '>' ; Redirect output? JZ RDOUT ; Yes...open the file for output CPI '<' ; Redirect input? and line MAXARG EQU 32 ;Maximum number of args in input line STDIN EQU 0 ;Default for stdin STDOUT EQU 1 ;Default for stdout it to a ascii string with 'pgmname' in it LXI D,PGM ; Pointer to 'pgmname' string CALL SVARG ; Save next argument ; Ok,R EQU 10 ;read string from console LSTOUT EQU 5 ;write character to list device OPEN EQU 15 ;open a file PUTCH EQU 2 ;write ce it for later MVI C,QUERY ; get logged-in disk CALL BDOS INR A ; make it so it will work in fcb STA DFLTDSK LDA BDOS+ unit of redirected stdout ; ; First thing, we save CPM's stack pointer and current disk and ; init stdin and stdout. ; Se JZ RDINP ; Yes...open the file for input CALL SVARG ; Nope, save starting point of this arg ; Loop looking for either end  STDERR EQU 2 ;Default for stderr STDLIST EQU 4 ;Default for stdlist ; DFLTDSK: DS 1 ;drive to use if no drive is named UNIT now for the real stuff. Set DE pair to point to ; CPM command line and start searching for arguments LXI D,CPMARG ; Pointharacter to console QUERY EQU 25 ;get logged-in drive id READ EQU 20 ;read a sector SELECT EQU 14 ;log-in a drive WRITE EQU 2 ; Get base of BDOS MOV H,A ; Save page in HL MVI L,0 SPHL ; Set stack pointer LXI H,STDIN SHLD RSTDIN ; Init rstdin  of line of a space NXTCH: INX D ; Point to next character DCR B ; Decrement character count JM ENDWRD ; End of cmd line, unit for redirected input POP B ; Restore registers POP D POP H MVI A,0FFH CMP B ; End of command line? JZ ENDCMD r redirected input POP B ; Restore registers POP D POP H MVI A,0FFH CMP B ; End of command line? JZ ENDCMD JMP NXT Load source DB 0EDH, 0B0H ; Do LDIR instruction PUSH H ; Restore stack PUSH D PUSH B DCX SP DCX SP RET ; End oVARG: MOV M,E ; Save pointer to start of string INX H MOV M,D INX H INR C ; Increment argc RET ARGV: DS MAXARG*2 PGMrminal JMP EXIT RDOPN: DB 'r',0 WROPN: DB 'w',0 NAMBUF: DS 16 RDEMSG: DB 'iolib: Unable to open < or > file$' ; lddbut need to end arg LDAX D ; Load next character in line CPI ' ' ; Space? JNZ NXTCH ; Nope...keep looking MVI A,0 ; Yes,JMP NXTSP ; Get next argument DEBLNK: INX D ; Skip leading spaces DCR B RM ; End of line reached LDAX D CPI ' ' JZSP ; Get next argument RDOUT: CALL DEBLNK ; Skip leading spaces JM RDERR ; End of line reached PUSH H CALL CPYNAM ; Copf memory function ; Returns top memory location in HL TOPOFMEM: LDA BDOS+2 ; Get base of BDOS MOV H,A ; Save page in HL : DB 'PGMNAME',0 RDINP: CALL DEBLNK ; Skip leading spaces JM RDERR ; End of line reached PUSH H CALL CPYNAM ; Copy filer(source, dest, n) DOLDDR: INX SP ; Skip over return address INX SP POP B ; Load n POP D ; Load destination POP H ; replace it with a zero byte STAX D JMP NXTSP ; Look for start of next arg ENDWRD: MVI A,0 STAX D ENDCMD: MVI B,0 ; Zero DEBLNK RET CPYNAM: LXI H,NAMBUF ; Copy filename to temp buffer PUSH B ; Save reg C MVI C,16 ; Maximum filename length y filename to temp buffer PUSH D ; Save registers PUSH B LXI H,NAMBUF ; Begining of filename PUSH H LXI H,WROPN ; Mode MVI L,0 RET ; Return the first free location FIRSTFREE: LHLD MEMRY$ RET MEMRY$:DW 0 ; This assembly routine alname to temp buffer PUSH D ; Save registers PUSH B LXI H,NAMBUF ; Begining of filename PUSH H LXI H,RDOPN ; Mode PUS Load source DB 0EDH, 0B8H ; Do LDDR instruction PUSH H ; Restore stack PUSH D PUSH B DCX SP DCX SP RET ; doldi B (BC now is 16 bit argc) PUSH B ; First arg to main procedure LXI H,ARGV ; Point to argv array PUSH H ; Second argument  CPY1: MOV M,A INX D INX H DCR B JM ENDNAM DCR C JZ RDERR LDAX D CPI ' ' JNZ CPY1 ENDNAM: MVI M,0 POP H M PUSH H CALL FOPEN ; Open the file POP D POP D MOV A,H ORA L ; Check return status JZ RDERR SHLD RSTDOUT ; Save lows CPM calls from Small C. ; ; cpm(cpmfunction#, inputparameter) ; ; Since this function returns whatever is returned H H CALL FOPEN ; Open the file POP D POP D MOV A,H ORA L ; Check return status JZ RDERR SHLD RSTDIN ; Save unit for(source, dest, n) DOLDIR: INX SP ; Skip over return address INX SP POP B ; Load n POP D ; Load destination POP H ;to main procedure MVI A,2 ; Load up the argument count CALL MAIN ; Transfer to the C world.... JMP EXIT ; Return to CPM SOV C,L ; Restore reg C RET RDERR: LXI D,RDEMSG ; Error message MVI C,CPMSTR CALL BDOS ; Make sure it gets put on the te  in register ; it cannot be used to call ReturnVersionNumber, ReturnLoginVector, ; WriteProtectDisk, or GetAddr. CPM: POP H buffer as taken LXI D,-FLAG ;back up to buffer start DAD D RET ;and hand it back ; ; freeio(unit) ; ; mark a bufcompiler POP B JMP EXIT ABTMSG: DB 0DH, 0DH, 'Aborted, reason = ',0 ; ; grabio() ; ; find an input buffer, and returnT ; cpmdisk(*unit); MOV L,M MVI H,0 PUSH H CALL CPMDISK POP H LHLD MODE ; if(*mode=='r' || *mode=='R'){ MOV AA DFLTDSK ; Grab orig. logged-in disk MOV E,A DCR E ; (cvt. back to 0-n) MVI C,SELECT ; and log it in again CALL BDOS e,mode) ; FOPEN: POP B ;get args POP H ;mode SHLD MODE POP D XCHG SHLD FILE PUSH H PUSH D PUSH B CALL ; Pop rtn address POP D ; Pop input parameter in DE register pair POP B ; Pop function code into C register PUSH B ; Restofer as free. ; FREEIO: ;Mod 6 May 80 rj POP B ;save rtn addr POP H ;get buffer addr PUSH H ;put the stack bac its address. ; if there isn't one, return a NULL. ; GRABIO: ;6 May 80 rj MVI B,NBUFS LXI H,IOBUFS+FLAG LXI D,FCB,M CPI 72H ; 'r' ? 9 Jun 80 rj JZ FOPIF0 CPI 52H ; 'R' ? 9 Jun 80 rj JNZ FOPIF1 FOPIF0: MVI C,OPEN ; if(cpm(OPE LHLD STACK ; Load stack pointer SPHL JMP 0 ; return to CP/M STACK: DW 0 ; ; abort(reason) ; ABORT: POP B POP D GRABIO ; unit = grabio(); SHLD UNIT MOV A,H ; if(unit==NULL) ORA L ; return(NULL); RZ LXI D,FCBSIZE ; ip = unitre stack PUSH D PUSH H CALL BDOS ; Call CPM MOV L,A ; Sign extend A into HL register pair RLC SBB A MOV H,A RET k together PUSH B LXI D,FLAG ;find flag byte DAD D MVI M,FREEFLG ;mark buffer as 'free' LXI H,NULL ;return somethSIZE+BUFFER+BUFSIZ MVI A,FREEFLG GRAB2: CMP M ;flag byte == freeflg? JZ GRAB3 ;if so, found a free buffer DAD D ;onN,unit)<0){ LHLD UNIT XCHG CALL BDOS ORA A JP FOPIF2 LHLD UNIT ; freeio(unit); PUSH H CALL FREEIO POP H L PUSH D PUSH B PUSH D ; error code LXI H,ABTMSG ; Load abort message PUSH H LXI H,STDERR PUSH H CALL FPUTS POP+FCBSIZE; DAD D SHLD IP LHLD IP ; ip[NEXTP] = &ip[BUFFER]; LXI D,BUFFER DAD D XCHG LHLD IP LXI B,NEXTP DAD B ; exit() ; ; Stop execution of the program, ; restore the logged-in drive, ; and re-boot CP/M ; EXIT: LHLD RSTDOUT MOing RET IOBUFS: DS FCBSIZE-3 DB FREEFLG,0,0 DS BUFFER+BUFSIZ DS FCBSIZE-3 DB FREEFLG,0,0 DS BUFFER+BUFSIZ DS FC to next buffer DCR B JNZ GRAB2 ;if there is one... LXI H,NULL ;there ain't RET ;give up GRAB3: MVI M,0 ;mark XI H,NULL ; return(NULL); RET ; } FOPIF2: LHLD IP ; ip[UNUSED] = 0; LXI D,UNUSED DAD D LXI D,0 MOV M,E  B POP B LXI H,2 CALL CCDSGI PUSH H ; Someday this should write out the correct error code ; CALL OUTDEC## ; Inside C  MOV M,E INX H MOV M,D LHLD UNIT ; fcb(unit,name); PUSH H LHLD FILE PUSH H CALL FCB POP H POP H LHLD UNIV A,H ORA A ; See if stdout has been redirected JZ EXIT1 PUSH H CALL FCLOSE ; If so, close the file POP B EXIT1: LDBSIZE-3 DB FREEFLG,0,0 DS BUFFER+BUFSIZ DS FCBSIZE-3 ;mod 4 May 80 rj DB FREEFLG,0,0 DS BUFFER+BUFSIZ ; ; fopen(nam   INX H MOV M,D ; } JMP FOPIF4 FOPIF1: ; else if(*mode=='w' || *mode=='W'){ LHLD MODE MOV A,M CPI 77H ; LWH3 FCLWH2: ; *cp++ = CTRL_Z; LHLD CHP MVI M,CTRLZ INX H SHLD CHP JMP FCLWH1 FCLWH3: LXI H,WRITE ; if(cpAD D MOV A,M ANI WRTFLG JZ FCLIF1 LXI H,CTRLZ ; putc(CTRL_Z,unit); PUSH H LHLD UNIT PUSH H CALL PUTC POP H  INX D ; name += 2; INX D CPI 61H-41H ; if(A>'a'-'A') /* lower case? */ 9 Jun 80 rj JC FCBIF2 SUI 61H-41H AG DAD D MVI A,WRTFLG ORA M MOV M,A JMP FOPIF4 ; } FOPIF5: LHLD UNIT ; else{ freeio(unit); PUSH H CALL e to unlink in LXI H,RDOPN ; Mode ; order to get fcb for it. */ PUSH H CALL FOPEN ; unit = fopen(name,'r'); POP D 'w' 9 Jun 80 rj JZ FOPIFA CPI 57H ; 'W' 9 Jun 80 rj JNZ FOPIF5 FOPIFA: MVI C,DELETE ; cpm(DELETE,unit); LHLD UNImio(WRITE,unit)<0) PUSH H LHLD UNIT PUSH H CALL CPMIO POP D POP D MOV A,H ORA A JP FCLIF4 LXI H,0 ; t =  POP H LHLD UNIT ; ip = unit + FCBSIZE; LXI D,FCBSIZE DAD D SHLD IP LHLD IP ; cp = ip[NEXTP]; LXI D,NEXTP DA; A -= 'a'-'A'; 9 Jun 80 rj JMP FCBIF2 ; } FCBIF1: LDA DFLTDSK ; else A = default_drive; FCBIF2: STAX B ; *fp++ =FREEIO POP H LXI H,NULL ; return(NULL); RET ; } FOPIF4: LHLD UNIT ; return(unit); RET ; ; fclose(unit) ; POP D SHLD UNIT MVI C,DELETE ; cpm(DELETE,unit); CALL BDOS LHLD UNIT ; freeio(unit); PUSH H CALL FREEIO POP DT XCHG CALL BDOS MVI C,CREATE ; if(cpm(CREATE,unit)<0){ LHLD UNIT XCHG CALL BDOS ORA A JP FOPIF3 LHLD UNIT 0; SHLD ZT FCLIF4: ; } FCLIF3: ; } FCLIF1: MVI C,CLOSE ; if(cpm(CLOSE,unit)<0) LHLD UNIT XCHG CALL BD D MOV E,M INX H MOV D,M XCHG SHLD CHP LHLD IP ; dp = &ip[BUFFER]+BUFSIZ; LXI D,BUFFER+BUFSIZ DAD D SHLD D A; INX B MVI H,' ' ; fp = fcbfill(fp,name,' ',8); MVI L,8 CALL FCBFILL MVI L,3 ; fp = fcbfill(fp,name,' ',3); C FCLOSE: POP B POP H SHLD UNIT PUSH H PUSH B MOV A,H ; if (unit<256) ORA A ; /* assume stdin, stdout, etc. */ RET ; return; ; ; fcb(fp,name) ; FCB: POP H ;get args POP D ;name POP B ;fp PUSH B PUSH D PUSH H I; freeio(unit); PUSH H CALL FREEIO POP H LXI H,NULL ; return(NULL); RET ; } FOPIF3: LHLD IP ; ip[UNUSEDOS ORA A JP FCLIF5 LXI H,0 ; t = 0; SHLD ZT FCLIF5: LHLD UNIT ; freeio(unit); PUSH H CALL FREEIO POP H LP FCLWH1: ; while(cp0 && (A= *D)~='.' && A~=0){ ORAE,M INX H MOV D,M XCHG SHLD CHP LHLD IP ; if(ip[UNUSED]==0){ LXI D,UNUSED DAD D MOV A,M INX H ORA M JNZ it) ; CGET: POP D POP H PUSH H PUSH D MOV A,H ORA A ; if(unit < 256) { JNZ CGET1 ; /* assume stdin */ CALLrected */ ORA A JZ GETCHR1 PUSH H CALL GETC ; getc(rdstdin); POP B ; return; RET GETCHR1: ; } else { /* read fr) ; B H L ; FCBPAD: MOV A,L ; while(L>0){ ORA A JZ PAD2 MOV A,H ; *B++ = H; STAX B INX B DCR L ; L--;  ; ip[NEXTP] = cp+1; INX H XCHG LHLD IP LXI B,NEXTP DAD B MOV M,E INX H MOV M,D LHLD CHP ; if(*cp==CTRL_Z){  A JZ FILL2 LDAX D CPI '.' JZ FILL2 CPI 0 JZ FILL2 CPI 61H ; if(A>='a' && A<='z') JC FILL1 CPI 7AH+1 ; 'z'GTCIF2 LXI H,READ ; if(cpmio(READ,unit)~=0) PUSH H LHLD UNIT PUSH H CALL CPMIO POP D POP D MOV A,H ORA L J GETCHAR ; getchar(); POP D ; /* return to caller of getc() POP D ; to bypass CR check */ RET ; return; } CGET1:om console */ MVI C,GETCH ; t = cpm(GETCH,0) & 0377; CALL BDOS MOV L,A MVI H,0 ANI 7FH ; /* mask parity in compa JMP FCBPAD ; } PAD2: RET ; return; ; ; getc(unit) ; FGETC: GETC: POP B POP H ; get args PUSH H PUSH B  MOV A,M ANI 7FH ; /* mask parity in compare */ CPI CTRLZ JNZ GTCIF4 LHLD UNIT ; unit[FLAG] |= EOF_FL; LXI D,FLAG 9 Jun 80 rj JNC FILL1 SUI 61H-41H ; A = A - 'a' + 'A'; FILL1: STAX B ; *B++ = A; INX B INX D ; D++; DCR L Z GTCIF3 LXI H,-1 ; return(-1); RET GTCIF3: LHLD IP ; else { ip[UNUSED] = BUFSIZ; LXI D,UNUSED DAD D LXI D,BUF SHLD UNIT LXI D,FLAG ; if(unit[FLAG] & EOF_FL) DAD D MOV A,M ANI EOFFLG JZ GTCIF1 LXI H,-1 ; return(-1); RET re */ CPI CTRLZ ; if(t==CTRLZ) JNZ GET1CHAR LXI H,-1 ; t = -1; GET1CHAR: CPI EOL ; if(t==EOL) JNZ GET2CHAR PU ; c=cget(unit); PUSH H CALL CGET POP D MOV A,L ; if(c=='\r') ANI 7FH ; /* mask parity in compare */ CPI EO DAD D MOV A,M ORI EOFFLG MOV M,A LXI H,-1 ; return(-1); RET ; } GTCIF4: MOV A,M MOV L,A ; return(*cp ; L--; JMP FCBFILL ; } FILL2: LDAX D ; while(*D~='.' && *D~=0) CPI '.' JZ FILL3 CPI 0 JZ FILL3 INX D ; D+SIZ MOV M,E INX H MOV M,D LHLD IP ; cp = &ip[BUFFER]; LXI D,BUFFER DAD D SHLD CHP ; } ; } GTCIF2: GTCIF1: LHLD UNIT ; ip = unit + FCBSIZE; LXI D,FCBSIZE DAD D SHLD IP LXI D,NEXTP ; cp = ip[NEXTP]; DAD D MOV SH H ; putchar('\n'); MVI C,PUTCH MVI E,LF CALL BDOS POP H GET2CHAR: ; return(t); RET ; } ; ; gets(buff) ; L JNZ GETCRET PUSH H ; cget(unit); PUSH D ; /* to skip LF */ CALL CGET POP H POP H GETCRET: RET ; ; cget(un & 0377); MVI H,0 RET ; ; getchar() ; GETCHAR: LHLD RSTDIN ; if(rdstdin >= 256) { MOV A,H ; /* stdin has been redi+; JMP FILL2 FILL3: CPI '.' ; if(*D=='.') JNZ FILL4 INX D ; D++; FILL4: ; fall into... ; ; fcbpad(dest,pad,size LHLD IP ; ip[UNUSED]--; LXI D,UNUSED DAD D MOV E,M INX H MOV D,M DCX D MOV M,D DCX H MOV M,E LHLD CHP   GETS: POP B POP H PUSH H PUSH B PUSH H ; buff LHLD RSTDIN ; if(rstdin >= 256) { MOV A,H ORA A JZ GETS1 XCH: MOV A,L ; else { POP H MOV M,A ; *cp++ = c; INX H ANI 7FH ; /* mask parity in compare */ CPI LF ; if(; PUSH D ; keep stack right FGETS2: POP D DCX D ; while (--len) { PUSH D MOV A,D ORA E JZ FGETS4 PUSH H ; save cUTCRET: POP H ; return(c); RET PUTCERR: ;putcerr: POP B ; return(-1); PTCER1: LXI H,-1 RET ; ; putlist(c)  = save; buff[-2] = save2; POP H MOV M,E INX H MOV M,D INX H MVI C,PUTCH ; putchar('\n'); MVI E,LF CALL BDOS NZ PUTC2 CALL PUTCON ; putconsole(c); RET ; return;} PUTC2: CPI STDLIST ; elseif(unit == stdlist) { JNZ PUTC3 PUSG LXI H,80 PUSH H ; len PUSH D ; unit CALL FGETS ; return(fgets(buff, 80, rstdin)); POP B POP B POP B RET GETSc=='\n') JNZ FGETS2 FGETS4: MVI M,0 ; *cp='\0'; POP D ; fix stack LHLD SVCHP ; return save_cp; RET ; } } } } ;p PUSH B ; unit CALL GETC ; c = getc(unit); POP B MOV A,H ; if(c==EOF) /* c>255 */ ORA A JZ FGETS3 POP D; PUTLST: POP B POP D PUSH D PUSH B SHLD ZCH MVI C,LSTOUT ; cpm(LSTOUT,c); CALL BDOS LDA ZCH CPI EOL ; if(c= LHLD CHP ; return(buff); RET ; } ; ; fgets(cp,len,unit) ; FGETS: INX SP ; skip rtn addr INX SP POP B ; unit PH H CALL PUTLST ; putlist(c); POP H RET ; return;} PUTC3: JMP PTCER1 ; else goto putcerr; } PUTC4: PUSH H ; if1: POP H ; } else { SHLD CHP DCX H ; save = buff[-1]; save2 = buff[-2]; MOV D,M ; buff[-1] = 0; buff[-2] = 79; MVI ; putc(c,unit) ; FPUTC: PUTC: POP B ;rtn addr POP D ;unit POP H ;c PUSH H PUSH D PUSH B MOV A,D ORA A ; if ; cp LHLD SVCHP ; if (cp<>save_cp) XCHG ; /* read something */ MOV A,H CMP D JNZ FGETS4 ; goto fgets4; M=EOL) JNZ PUTLS1 MVI E,LF ; cpm(LSTOUT,LF); MVI C,LSTOUT CALL BDOS PUTLS1: LHLD ZCH ; return(c & 0377) MVI H,0 OP D ; length POP H ; cp PUSH H PUSH D PUSH B DCX SP DCX SP MOV A,B ; if(unit < 256) { ORA A ; /* assume stdin(cput(c,unit)<0) PUSH D ; goto putcerr; CALL CPUT POP D MOV A,H ORA A JM PUTCERR MOV A,L ; if(c=='\r') CPI E M,0 DCX H MOV E,M MVI M,79 ;6 May 80 rj PUSH H PUSH D XCHG ; cpm(GETSTR,buff-2); MVI C,GETSTR CALL BDOS (unit < 256) { JNZ PUTC4 ; /* assume stdout, stderr */ MOV A,E ; /* or stdlist. */ CPI STDOUT ; if(unit == stdout) { OV A,L CMP E JNZ FGETS4 ; else LXI H,0 ; /* no characters */ POP D ; fix stack RET ; return (NULL); FGETS3RET ; ; cput(c,unit) ; CPUT: POP B POP D POP H PUSH H PUSH D PUSH B SHLD ZCH XCHG SHLD UNIT LXI D,FCBSIZ */ JNZ FGETS1 PUSH H CALL GETS ; gets(cp) POP B ; return (cp); RET ; } else { FGETS1: SHLD SVCHP ; save_cp = cpOL JNZ PUTCRET LXI H,LF ; cput('\n',unit); PUSH H PUSH D CALL CPUT POP D POP D MOV A,H ORA A JM PUTCERR P LHLD CHP ; buff[buff[-1]] = 0; (9 Jun 80. Was cp) DCX H MOV E,M INX H MVI D,0 DAD D MVI M,0 POP D ; buff[-1]JNZ PUTC1 PUSH H CALL PUTCHAR ; putchar(c); POP H RET ; return;} PUTC1: CPI STDERR ; elseif(unit == stderr) { J E ; ip = unit + FCBSIZE; DAD D SHLD IP LXI D,NEXTP ; cp = ip[NEXTP]; DAD D MOV E,M INX H MOV D,M XCHG SHLD TS1 PUSH H CALL FPUTS ; return (fputs(cp, rstdout)); POP B POP B RET PUTS1: POP H ; } else { MOV A,M ; while(P B ; return; RET PUTCHR1: ; } else { POP H PUTCON: SHLD ZCH ; /* send to console */ XCHG ; cpm(PUTCH,c); MVI CUFF CALL BDOS LHLD ZT ; if(t~=0) return(-1); MOV A,H ; else return(0); ORA L JNZ CPMIF1 LXI H,0 JMP CPMIF2 NUSED]--; DAD D MOV E,M INX H MOV D,M DCX D MOV M,D DCX H MOV M,E LHLD CHP ; ip[NEXTP] = cp+1; INX H XCHFPUTS3: LXI H,0 RET ; return(NULL); ; ; cpmio(fn,unit) ; CPMIO: POP B POP D POP H SHLD FN XCHG SHLD UNIT PCHP LHLD IP ; if(ip[UNUSED]==0){ LXI D,UNUSED DAD D MOV A,M INX H ORA M JNZ PTCIF1 LXI H,WRITE ; if(cpmio(WR*cp) ORA A JZ PUTSRET MOV E,M ; putchar(*cp++); INX H PUSH H MVI C,PUTCH CALL BDOS JMP PUTS1 PUTSRET: ; re,PUTCH CALL BDOS LDA ZCH ; if(c==EOL) ANI 7FH ; /* mask parity in compare */ CPI EOL JNZ PUTCHIF1 MVI E,LF ; c CPMIF1: LXI H,-1 CPMIF2: RET ; ; cpmdisk(disk) ; CPMDISK: POP D POP H PUSH H PUSH D MOV A,L ; if(d~=0) OG LHLD IP LXI B,NEXTP DAD B MOV M,E INX H MOV M,D LDA ZCH ; return((*cp = c) & 0377); LHLD CHP MOV M,A MVIUSH D PUSH H PUSH B LHLD UNIT ; cpmdisk(*unit); MOV L,M MVI H,0 PUSH H CALL CPMDISK POP H LHLD UNIT ; ip =ITE,unit)~=0) PUSH H LHLD UNIT PUSH H CALL CPMIO POP D POP D MOV A,H ORA L JZ PTCIF2 LXI H,-1 ; return(-turn; RET ; } ; ; fputs(cp,unit) ; FPUTS: POP B POP D ; unit POP H ; cp PUSH H PUSH D PUSH B FPUTS1: MOV A,pm(PUTCH,LF); MVI C,PUTCH CALL BDOS PUTCHIF1: LHLD ZCH ; return(c & 0377); MVI H,0 RET ; } ; ; puts(cp) ; PUTRA H JZ DISKIF1 XCHG ; cpm(SELECT,d-1); DCX D MVI C,SELECT CALL BDOS DISKIF1: RET ; ;----------- End of Small- H,0 MOV L,A RET ; ; putchar(c) ; PUTCHAR: POP B POP H PUSH H PUSH B PUSH H LHLD RSTDOUT ; if(rdstdout >= 2 unit+FCBSIZE; LXI D,FCBSIZE ; cpm(DMA,&ip[BUFFER]); DAD D LXI D,BUFFER DAD D XCHG MVI C,DMA CALL BDOS LHLD FN 1); RET PTCIF2: LHLD IP ; else { ip[UNUSED] = BUFSIZ; LXI D,UNUSED DAD D LXI D,BUFSIZ MOV M,E INX H MOV M,D M ; while((c=*cp++) <> NULL) { INX H ORA A JZ FPUTS3 PUSH H MOV C,A MVI B,0 PUSH B PUSH D CALL PUTC ; if(putS: POP B ; get args POP H PUSH H PUSH B PUSH H ; cp LHLD RSTDOUT MOV A,H ; if(rstdout >= 256) { ORA A JZ PUc library ----------- ; #endasm LECT,d-1); DCX D MVI C,SELECT CALL BDOS DISKIF1: RET ; ;----------- End of Small-56) { MOV A,H ; /* stdout has been redirected */ ORA A JZ PUTCHR1 PUSH H CALL PUTC ; putc(c, rdstdout); POP B PO ; t = cpm(fn,unit); MOV C,L LHLD UNIT XCHG CALL BDOS CALL CCSXT SHLD ZT MVI C,DMA ; cpm(DMA,TBUFF); LXI D,TB LHLD IP ; cp = &ip[BUFFER]; LXI D,BUFFER DAD D SHLD CHP ; } ; } PTCIF1: LHLD IP LXI D,UNUSED ; ip[Uc(c,unit)==EOF) POP D POP B MOV A,H ORA A JZ FPUTS2 POP B RET ; return(EOF); FPUTS2: POP H JMP FPUTS1 ; }   DCX SP DCX SP RET ; doldir(source, dest, n) DOLDIR:: INX SP ; Skip over return address INX SP POP B ; Load n G *6{Gc*?6!".6"06!*u!7>4!*̀8>4͏** 6|ʥ):8<2727ë)!&*ͫ*!**ͫ** 6| Unable to open < or > file$33;;33;;:g.*og*|:_*!!*| !PJ " +V6+^6O * +^#6s#r# * 33;;x_ "zʕ |ʊ *|•  function returns whatever is returned in register ; it cannot be used to call ReturnVersionNumber, ReturnLoginVector, ; Write^#V" * " * * z*6{6* 6#" !* |N!"*a!"*A*!f" POP D ; Load destination POP H ; Load source DB 0EDH, 0B0H ; Do LDIR instruction PUSH H ; Restore stack PUSH D PUSH )>,C:8<>,dB:8<2727!:*ͫ*͏*)!G*7|*)Gͭ:8*>CQCNo Fatal error( !͑ Aborted, reason = !p>:-!6!6!~8/(#~d&(~w,'T(l(~w#w}• !}w# c 6*z {³ ͓ ¼ ͨ   | } !  | !":!9"<2:g.!"!"!͍G~ R><͍{ j>R>*A:©@ ڬ ì:& ..&.! 6}.a{ -..B DCX SP DCX SP RET ; End of memory function ; Returns top memory location in HL TOPOFMEM:: LDA BDOS+2 ; Get bases) Warning(s):6GG )ͨ*!a*ͫ*Ï*REPT/IRP/IRPC/MACROUnterminated ͨ*!*ͫ*> > :8<> dB> ""#"#w#w"<6c(:6 xfx 2+6*<6"86> x:7Ä"<6c(:6 xf*<6#~l~@ w#s#r#*6s#r.C:E8R*:6ă*!  *&""$" ^#V" * ~#k !* |T !* s#r* " * ^#Vr+s* #* !>G"s#r# PGMNAME5[?!j!f|[">} |-&} %&|5"!~F!*$" ^#V" * ~#•!* |~!*  of BDOS MOV H,A ; Save page in HL MVI L,0 RET ; Return the first free location FIRSTFREE:: LHLD $MEMRY RET $ME|$" * *  s#r**͌*n&h *~rDRm*]*A!* s#r*~w{W¸*64~=J)!7~(!7~(#7~# ( (( ( (!7p"86Ga#!CE"e84 1)"86~w#~@F*~ )#^#VG )*6  s#r:* w&o*|ʧ ͜ ":  *&*| ~ ^# ~# O~R5[?!j!h|[">~R 5!jw#V [ E6Mz rwT:6 0'{2,6iolib:s#r* " * ^#Vr+s* #*  s#r* ~*!~w!~o&*| o&!  MRY::DW 0 ; This assembly routine allows CPM calls from Small C. ; ; cpm(cpmfunction#, inputparameter) ; ; Since this**A!* s#r*!>w*A!*"|.!"*!~N!*͜ *$" *  ͜ | !""*n&h *$*M*͈"*|d !g !}x G" sk() { #ifdef OPTIMIZE optimize= #endif monitor=alarm=pause=listfp=nxtlab=0; line=mline; while(1) { prompt("O /* ** dtoi -- convert signed decimal string to integer nbr ** returns field length, else ERR on error */ dtoi(decsutput file: ", line, LINESIZE); if(output=fopen(line, "w")) break; else lout("open error", stderr); } #ifndef LItr, nbr) char *decstr; int *nbr; { int len, s; if((*decstr)=='-') {s=1; ++decstr;} else s=0; if((len=utoi(decstr, nbNK while(1) { prompt("Beginning label number: ", line, LINESIZE); bump(0); if(number(&nxtlab)) break; } r))<0) return ERR; if(*nbr<0) return ERR; if(s) {*nbr = -*nbr; return ++len;} else return len; } #endif while(1) { prompt("Monitor function headers? ", line, LINESIZE); if(upper(*line)=='Y') monitor=YES; elsendif #ifndef LINK sout(" [-b#]", stderr); #endif sout("\n", stderr); abort(ERRCODE); } } #else a [file]... [-c] [-m] [-a] [-p] [-l#] [-o] [-b#] !"1"!"!*9"#"9"*!|:(!!*9")͔"!*!͇!-|'ÿ'*!!Z(!ڇ|ʗ%HRâ%!,JQN%'%*+"|ʷ%!%cRno closing bracket!9!"""A"ԇ!"5"!}2 }2 }2~ }2} }2| !J "! DCX H RET ; ;COMMON ROUTINE TO PERFORM UNSIGNED COMPARE ;CARRY SET IF DE < HL !!";"!"="Zwi(#ͧ%pw*5"too many command argumentsSmall-C Ver. 2.03 (ASM) (7/28/83)*/"|`$!a$!T|/ itod(nbr, str, sz) int nbr; char str[]; int sz; { char sgn; if(nbr<0) {nbr = -nbr; sgn='-';} else sgn=' '; if"1"|-(!\(!Q*!!Q!!"7"Hÿ'*7"#"7"+|P(!"/"V(!"1"Hropen error: !]!!=!! ~ԇԇ!]!!9T]͔#ԇ*!|t'!!)͔"!*!͇!-|q'*!͇|EM'*!͇BF*!͇! |ʏ&*!͇ ;ZERO/NONZERO SET ACCORDINGLY ; CCUCMP: ENTRY MOV A,D CMP H JNZ CCUCMP1 MOV A,$!q+Z$!q+|$Z$!h$͕T|1$ͅ@Z$!m$͕T|D$ *Z$!v$͕T|W$kNZ$1V#extern#asm#include#define(sz>0) str[--sz]=NULL; else if(sz<0) sz = -sz; else while(str[sz]!=NULL) ++sz; while(sz) { str[--sz]=(nbr%10+'0');!9͔! |p"!#!Q!!9͔"!!9!!=!!~ԇԇ!]!!=!!'~ԇԇ!]!!=!!~ԇԇ!]!!=!!$ԇԇ!]! !ԇ!=! !ԇ!!0`"A"q'Ò&'!}2} q'!}2~ q'!}2 q'!}2 q'!}2| q'*!͇BF*!͇! |'!G!G! /* ** itou -- convert nbr to unsigned decimal string of width sz ** right adjusted, blank filled; returns str ** *!9!ԇ* "|#%!9͔&|!9! ԇ!9T]͔+ԇ#| %!s!9͔DP!9!9͔ԇ! if((nbr=nbr/10)==0) break; } if(sz) str[--sz]=sgn; while(sz>0) str[--sz]=' '; return str; } ԇ!9T]͔+ԇ#|"!!!9T]͔#ԇ+)!9T]͔##ԇ++͔ԇÅ"!#!Q!#!Q!#!Q!#!Q! " /* ** itod -- convert nbr to signed decimal string of width sz ** right adjusted, blank filled; returns str ** ** "+t|'q'!v'!Q!'!Q!'!Q!'!Q!q'K&L&A&M&C&P&O&B'&usage: cc * if sz > 0 terminate with null byte ** if sz = 0 find end of string ** if sz < 0 use last byte for data * " ڇ|%HR %!,JQï$Ë$!9͔%ʥ%!9͔&|!9!ԇ!9T]͔+ԇ#|ʢ%!P!9T]͔+ԇ! RET ; ;TEST IF DE <= HL (UNSIGNED) ; CCULE: ENTRY CALL CCUCMP RZ RC !*!!`"!! "!!"9""7""+""/""-""%"" """"""!"!!!!}!"?"""!!""!!!"}!"3""1"%ͳ'K!" if sz > 0 terminate with null byte ** if sz = 0 find end of string ** if sz < 0 use last byte for data *  */ itou(nbr, str, sz) int nbr; char str[]; int sz; { int lowbit; if(sz>0) str[--sz]=NULL; else if(sz<0) sz = -sz; XCHG LXI D,0 CCDIV1: DAD H CALL CCRDEL JZ CCDIV2 CALL CCCMPBCDE JM CCDIV2  else while(str[sz]!=NULL) ++sz; while(sz) { digit=nbr&15; nbr=(nbr>>4)&4095; if(digit<10) offset=48; else offset]! !ԇ!=! !ԇ!]!!Ȁԇ!=!!iԇ!]!!ԇ!=!!ԇ!]!!=!!F~ԇԇ!]!!=!!U~ ; CCCOM: ENTRY MOV A,H CMA MOV H,A MOV A,L CMA MOV L,A RET CMA MOV E,A INX D RET ; ;NEGATE THE INTEGER IN BC ;(INTERNAL ROUTINE) else while(str[sz]!=NULL) ++sz; while(sz) { lowbit=nbr&1; nbr=(nbr>>1)&32767; /* divide by 2 */ str[--sz] /* ** left -- left adjust and null terminate a string */ left(str) char *str; { char *str2; str2=str; while(*str2==55; str[--sz]=digit+offset; if(nbr==0) break; } while(sz) str[--sz]=' '; return str; } ԇԇ!]!!=!!}ԇԇ!]!!=!!}ԇԇ!]!!=!!}ԇԇ!]!!=!!}ԇԇ!]!!=!! /* ** itox -- converts nbr to hex string of length sz ** right adjusted and blank filled, returns str ** **  ; CCBCNEG: MOV A,B CMA MOV B,A MOV A,C CMA MOV C,A INX B=((nbr%5)<<1)+lowbit+'0'; if((nbr=nbr/5)==0) break; } while(sz) str[--sz]=' '; return str; } =' ') ++str2; while(*str++ = *str2++); } E) ; CCDIV: ENTRY DIV: MOV B,H MOV C,L MOV A,D XRA B PUSH PSW MOV A,~ԇԇ!9*3"!|/*!1+cRH!9V*!͇!"*!͇!<ڇ|*!9!ԇ!9!9ԇ!|*!9* if sz > 0 terminate with null byte ** if sz = 0 find end of string ** if sz < 0 use last byte for data */ ito RET ; ;ROTATE DE LEFT ONE BIT ;(INTERNAL ROUTINE) ; CCRDEL: MOV A,E RAL  MOV L,A MOV A,D SBB H MOV H,A RET ; ;FORM THE TWO'S COMPLEMENT OF HL  RP CALL CCDENEG XCHG CALL CCDENEG XCHG RET ; ;NEGATE THE IND ORA A CM CCDENEG MOV A,B ORA A CM CCBCNEG MVI A,16 PUSH PSW !#"!͇}!9͇!"!9͇!>ڇ|ʿ*!9!ԇ*!9T]͔#ԇ+!9͇}m*!9͔!}!9!9ԇ+!9*!x(nbr, str, sz) int nbr; char str[]; int sz; { int digit, offset; if(sz>0) str[--sz]=NULL; else if(sz<0) sz = -sz;  MOV E,A MOV A,D RAL MOV D,A ORA E RET ; ;COMPARE BC TO D ; CCNEG: ENTRY CALL CCCOM INX H RET ; ;FORM THE ONE'S COMPLEMENT OF HL TEGER IN DE ;(INTERNAL ROUTINE) ; CCDENEG: MOV A,D CMA MOV D,A MOV A,E  !9͔!R+"3"|(+!"3"!T+cRH!9nested include files not allowedropen failure on include file!+!T|r!1͕T|ʕ1!!9r|®1!9!ԇ寴1!1cR!9gԇ!1iA]negative size illegal]!";!"9!!" |/!g0͕T|/!9͔|/!9͔!9͔!9m0!i0͕T|//Ó/!k0iA/!9͔!9͔!9m0!9͔!har *ctl, *cx, c, right, str[7], *sptr, pad; i = CCARGC(); /* fetch arg count from A reg first */ nxtarg = &argc + i - 1cRA|ʐ-!#/͕T|ʫ-!9!ԇö-!9!ԇ!0!!D|-5A!9!ԇ!%/͕T|S.!9͂1ԇ|E.!4!4cR4ù3H6!|!4n{* "|<4*!"EZR!~$illegal function or declaration(no open paren)illegal argumentʛ+!!9͔+8!!+!T!9͔!ڇ|+!!9͔+8!!charintA|+!=-͕T|,!""C"ͺE"!"!"!:~ ͈|(2*!!Q!0!!D|G2!>4cRH*"|]2*#"E!""!9!0!ͦAԇ|ʾ2͇!|!9͔|:0!! 9!ԇu!9!ԇ!9͔~$!9͔!9͔&%!9͔={,}!9qu|0!9; ctl = *nxtarg; while(c = *ctl++) { if(c!='%') {cout(c, stdout); continue;} if(*ctl=='%') {cout(*ctl++, stdout)| .!'/cR!9!ԇ!9͔!|B.!9!9͔!YԇP.!9!ԇÛ.!D/͕T|n.!9!ԇÛ.!9͔! name),no commacharintwrong number of arguments!9*'"|4!9! 6͕T|4!9!ԇ4!9!ԇ!9!0!!D9!ԇ!9!ԇ.,!9!ԇ!9!ԇ!0!!D|C,5A!0!ͦA|X,!0!PA!?-͕T|s,!9!ԇì,!B-͕T|ʬ,ʏ2!0!PAû2͇!|ʯ2!0!PAû2!}2!0!!!!!!![B! 9!^4͕T|2!`4cRͯw!"!!͔!! 9͔!ڇ|ʪ0!D1cR!9͔!9͔͔* "!9͔``ԇ!9͔!|0Q|B1!9r|B1!9͔; continue;} cx=ctl; if(*cx=='-') {right=0; ++cx;} else right=1; if(*cx=='0') {pad='0'; ++cx;} else pad=' '; !|ʛ.!9!ԇ*"""!0!! 9͔*%"*"`!!![B! 9.Å-!G/͕T|.Å-not allowed wit /* ** printf(controlstring, arg, arg, ...) -- formatted print ** operates as described by Kernighan & Ritchie ** !9͂1ԇ!|ʡ,!D-cR!9!ԇ!9͔!|,!0!;w,!9! 9͔!K!9͔!9͔I/ԇ!0!"'"!n4͕T|­3!0!!D|j3!0!A|;3!0!PAg3!0!!!*'"!!![B! 9*'""'"u3!p4cR@V*!!4!|1!i1cR! 9͔u!9͔!9͔͔!`ԇmust assign to char pointer or arraycannot assign to pointe if((i=utoi(cx, &width)) >= 0) cx=cx+i; else continue; if(*cx=='.') { if((preclen=utoi(++cx, &prec)) >= 0) cx=cx+preh gotomust declare first in block*[declaration type not allowed(),!" "!9͔|g/!9!ԇ!9!9͔ԇͯw!e0͕T only d, x, c, s, and u specs are supported. */ printf(argc) int argc; { int i, width, prec, preclen, len, *nxtarg; c! 9͔!9͔!!!9͔[B! 9!a-͕T|7-+*()[declaration type not allowed,*;!|u-!.cR*"-!/cS|Ÿ3!4͕T|Ÿ3!4cRA|ʪ3í33!"%"*'"")"*'"|4!4!T|3!Ͷ48 4!4!T|4!Ͷ48  clen; else continue; } else preclen=0; sptr=str; c = *cx++; i = *(--nxtarg); if(c=='d') itod(i, strlowed with goto"); #endif if(declared < 0) error("must declare first in block"); while(1) { while(1) { if(endame, YES)==0) illname(); if(findglb(ssname)) multidef(ssname); if(match("()")) j=FUNCTION; else if (match("[")) {9!"C"Å8!8!T|(7:!"C"Å8!8!T|F7*;!"C"Å8!8!T|d7͢;! "C"Å8!8!T|ʂ7͆0) return 1; else if(nbr8!8!T|ʠ7=! "C"Å8!8!T|ʾ7I>! "C"Å8!8!T|7͢>! "C"Å8?|7Å8!8!T|8?8!(class==EXTERNAL)) { declglb(CINT, class); ns(); return 1; } return 0; } /* ** delcare a static va!9͔}! 9͔}*)"!D`!̓D5!-6cR*'"!`"'"A|5!9!=6͕T|6!?6 if(c=='u') itou(i, str, 7); else continue; ctl=cx; /* accept conversion spec */ if(c!='s') while(*sptr==' ') ++sno multidef check, block-locals are together */ k=BPW; if (match("[")) { k=needsub(); if(k) { ==0) return 0; else return -1; } "C"Å8!8!T|)8?8!"C"Å8!8!T|J8-@8!"C"Å8!8͕T|`8!"-"Å8!8͕T|y8ͅ@!"C"Å8v:8!riable */ declglb(type, class) int type, class; { int k, j; while(1) { if(endst()) return; /* do line */ cRû4!9*[declaration type not allowednot an argument,no comma*"!*/"|_6!8!T|6!c-8Å8!ptr; len=-1; while(sptr[++len]); /* get length */ if((c=='s')&(len>prec)&(preclen>0)) len=prec; if(right) while(( j=ARRAY; if(typ==CINT)k=k<0) cout(pad, stdout); while(len) {cout(*sptr++, stdout); --len; --width;} while(((width--)-len)>0) cout) j=FUNCTION; else if((typ==CCHAR)&(j==VARIABLE)) k=SBPC; declared = declared + k; addsym(ssname, j, typ, c micolon!9*%"ԇ!9*!ԇ!""*+"#"+"!9͕T|V9*/"|P9!9cRV9S9H6-9*+"+"+"!a|"%""!!*!!*!,|cRë?!0!!!ͺE!!![B! 9"!!*!!!Dnot a labelA|?v:!!a|?!!a|n{!9*"!PHR*!|ʛ=*!ͨ{! 9͔E@G"!!9͔"!!9͔"!!9()*!|=!*>cR*!*!2|=!8>cR*!## | DC!9!9͔!9T]͔+ԇ͇ԇ!9T]͔+ԇ#|~D!9!Y! 9͔!9͔͇!ڇԇ6D!9͔E@G8! 9while!9!9͂F!9ͺEԇ!9ͺEԇ!|iAnot in switchtoo many cases:*!|d>*!|a>!>cRl>!>cR!>iAͺE"!E!9T]͔+ԇ#|D!9T]͔#ԇ+!9͔}!9!9͔!KԇÃD;V*"E|D!3!9!ԇ*"dF|^E!9͔͔!͉p8ͨ{!9͔E!<͕T|@ʹ>!>cRÿ>!";!!0!!D|>`?ͨ{>!?cR8not allowed with block-l|$E!9͔!9͔G|E};E!9͔!9͔G}!9͔!|[E!9T]͔#ԇD!9͔!9͔!}!33!9;))!9!9*!ԇ!9*!ԇ!9!9*!ԇԇ! 9͂F*"!`!ԇ!=iAv:!=iA!"!!"!!9ͺEԇ!!!9͇}*!!}!9͔*!!!̓D*!!"#!"%!! 9͔͇dF|yC*#!#"#!+!9T]͔#ԇ+͇}EC*#!*#!!9O!9!9__O*"!,|ʺ::!G{:!9!9!9͂F!9͔E!9͔!͉pH"| AAG@VV*!!3AcS*"!ڇ;!AAcR@illegal symbol!YAcRalready defined͕T|A!AcRocalsbad labelV!9*!ԇ!0!!D|Z?G!:|M?`?E!*!`G!!0!A"!!|ʆ?*!!͇|ʃ?!?͇!a !9͇!z|ʱE!9͇! `!9͇*"#""EZRHR!EQPCC!9͇!a !9͇!z{H6! 9͔ͨ{!9͔EA{*!,|x=!&|!9T]͔##ԇ++͔E!,JQ!9T]͔##ԇ++͔PHR%=!&|*%!`}!9͔*#!#"#!ԇ*!!global symbol table overflowlocal symbol table overflow!9!9͔ԇ!9T]͔#ԇ+͇!6!9͔ͨ{!9͔E@G!9!9!9͂F!9ͺEԇEH6!;iA!9͔E!9͔!͉pͨ{missing token!AcRmust be lvalue!"!!*!!*!,|A*!!!S|A*!!*!!C"!!ðA!*!!`"!!*! !9͇!A !9͇!Zڇ!9͇!_ڇ!9͇!0 !9͇!9!9͇E!9͇BFtst=STSWITCH;} else if(amatch("case",4)) {docase();lastst=STCASE;} else if(amatch("default",7)) {dodefault();lastst > 1) nogo=declared; /* disable goto if any */ #endif csp=modstk(csp - declared, NO); declared = -1; } 9!ԇ*"dF|JM!9͔!|DM!'!!9T]͔#ԇ+*"}G M!'!!9͔!}!9!'! str2 */ strcmp(str1, str2) char *str1, *str2; { char c1, c2*"JG*"!"*!!`͇!\*!!`͇!\ڇ|K*"|K!$NcRKGJËKG!"JM*"!'"++!9͔!9T]͔#ԇ+)͔ԇFtoo many active loops*"!!2|\G*"!`""!!9|xG!GcR!!}33NH*/"|ʗI!J͕T|I*"#""*"|ʶIËIV*!= 0) { #ifdef STGOTO if(ncmp"!/*"!*|L!G*"!**"!/|L*"|L!GL͋I*/"|LLåL!GM*"dF|M!!͇""""|H*!͇""*!!}!G*"|JH*/"|DH!K0HG*1"!|bHͳ'*/"|mH!9*3"ԇ!|INËI*"|ʐJËI*A"|J*A"*5"|ʴJ!;*5"ͳQ*!*A"Q*"|JËIJËI#ifdef#ifndef#else#endif*"!d|K!  queue full!/* "!9͇}* "!|4O* "#" "!9͇!" "* "* "|ʽO!/* "!S|ʊO!/* "#" "+͇|cS"!|U*!*!͇!=*!*!͇*!*!!`͇|U!!9͔͇|U!9T]͔#ԇ*}!#"}!U!&US!9͔͇!9͔͇|ʯS!!9T]͔#ԇoS!9!ԇ!9͔|VT!9͔͇!9͔͇9͔X|Z!9͔Fp!9͔͔|Z!9͔͔|RZ!9͔ԇ!9͔!}|ʭZ*%""%"!O!Q!9͇*5"ͳQ!9͇staging buffer overflow!9͇!9͔͜ !|Q$R!9͔!9͔ !|Q$R!9!9!9͔!9͔Xԇ!9͔U|@X!9͔!9!9͔|XX!9͔Fp!9͔U|ʼX*!G*}!!9͔"}!ʆOnO* "!/* "#" "+͇|ʢOÊO!/* "#" "+͇|ʺOâOBO!!9͔*!ԇ|O! "!*!ԇ*!!}!9͔"!|O*"|V͓G|VGVV*!!J |-VK*/"|;V>VVBV!9!9!ԇ!9!9͔!9͔Xԇ!9͔U|| TVT!9͔͇! |)TVT!9͔͇! |FTVT!9T]͔#ԇS!9͔͇dF|sT!!9͔͇9͔͔! 9͔! 9͔͖nYsZ!9͔͔! 9͔! 9͔͖nYos!9͔yz[!9͔y9͔!9͔Q! !9͔ͳQ!:R! !output error ! JQ! JQ!:JQ*-"|lR!"-"*!!Q!=!*}!)͔!]!*}!)͔!9͔!9͔!9/Y! 9X!!9XX!9!9!9O!9! 9͔! 9͔!X|P;!9!ԇ!9!'ԇ!9͔PP!9!9͔gԇ!-JQ!9͔! |P!9! 9͔!9͔͓0}V*!G!9͔|¬V!9!ԇ!9ͺEԇ!9͔!9͔!9͔!9͔ͭW!9äW!9͔|ʕW!9͔!9͔!9͔!dF|ʐT!V!9*!!9͔cSԇ|TG!!V!9*!! 9͔! 9͔Sԇ|UG*"!9͔!}!9͔!}ڇ|z[!9͔!9͔͖n|D[ͷ}!9͔! 9͔͖n|z[͑yͷ}!9͔!}|z[͑y!9͔!R:} ͈|ʥR!!͜ : ͈|R! ! |RðR*A"RR*A"R!9*!ԇ!9T]͔#ԇԇ!9͔͔|&Y!9͔!O!9!9O!9͔ !ԇ!9͔!ԇ!9͔͔|Y! 9͔!!9͇!0!9͔!ڇ!9͔ڇ|P!9!ԇ!9͇JQ!9! 9͔!9͔͓ԇ!9!9͔! ͓ԇPP39͔ͭW!9!9͔os!9ͺEԇͨ{E!9͔osE! 9͔! 9͔!9͔!9͔!ԇdF|U0HT!!!"}!V!"!!9͔͇! |hU!9*!#"!+!9T]͔#ԇ+͇},U!9*!!}*!!9|(]!9͔! 9͔͔! 9͔͔ԇ|\!9͔! 9͔͔!9͔! 9͔͔+]ԇ!+*!9|!S! !9͔ͳQR!ZS!9͔Q!]S!9͔Q!9͔!9͔Q/\**** !9!ԇ!9͔͇|9͔X|ʝY!9͔Fp!9͔͔|Y!9͔*!ԇ!9͔͔!9͔! 9͔͖nYsz[y! 9͔!QHRQRQ͇! |IQ!9T]͔#ԇ+͇JQQ*!|ʂQ*!*!|mQ!QcR!*!#"!+!9͇}ԇԇԇ!!9!9͔!9RV!9!9͔|WFpW͔|W͔os!9͔!9͔!W! O!9͔ !ԇØ\!9͔͔!!9͔͔!|u\!9͔!\\!9͔ !9͔ԇØ\! 9͔!\!!9!b!9͔BV! 9||!b!2!!!9!b!9͔BV! 9&&!b!!9!b! 9͔W!9|!͕T|ʗ`!9!}ԇHa!ab͕T|ʲ`!9!}ԇHa!db͕T|`!9!}ԇHa!gb͕T|`!9!~ԇHa!jb͕T|a!9!F~ԇ|g͎A!!~!9͔xo!9͔͔!KͰ~!!g͕T|ʒg|ag͎A!!~!9͔xo!9͔͔K!9͔!U~|ʬ^!9͔Y!9͔!}|^!9͔!9͔!}|^!9͔`!9͔!}|g͕T|Re!9͔,d|(e!9͔Fp6~!9͔!9͔͔ԇ!!g͕T|ʦe!9͔,d||e!9͔Fpd~!!9͔ ! 9͔ԇ!9͔!}|\!9͔͔!!9͔͔!|\͑y!osF~!9͔!}!9$c!!9!&c! 9͔W!9^!Lc!!9!Nc! 9͔W!9&!tc!!9!zc! 9͔W!9== !=!c!Ha!nb͕T|a!9!U~ԇHa!rb͕T|9a!9!ԇHa!9͔!9!9͔|ba͎A!!9!9͔͔|a|ʍa!K͂~!++--~!-*&illegal address++--!9!9! 9͔jԇ!9! 9͔͔ԇV*"![*"_!9͔s!9͔!}|6_!9͔͓!9͔!~|Z_!9͔͓!!9!9_|{_!9Fp!99͔!9͔͔gԇ!!g͕T|Bf!9͔,d|e!9͔Fp!9!9͔͔ԇ|f!9͔͇͔!}ڇ|(]!9͔!9͔n!9͔! ~|N]!9͔ڇ!9͔!~|q]!9͔!9͔!'~|!9!c! 9͔W!9<= >= < >!c! !9!c! 9͔W!9>> <<!c! !9!d! 9͔W!9+ -y!9͔Fp!9͔!_!9͔! 9/Y! 9|a{6b|b!9͔Fp!9͔!_!9͔! 9/Y! 9!(ڇ|hj!9͔ !ԇ!j͕T|i!9͔|Yh!jcR@!jiA!!9!9͔͇!|~h!9͔Fpçh!͔|ʳ_!9͔!ԇ!9͔!9͔ԇ_!9͔!ԇ!9!9!9!9!tb!9͔Xԇ!9͔͔|`!ԇf!9͔!ԇ!9͔!ԇ!9͔!ԇ!!g͕T|f!9͔,d|nf!gcR!!9!9͔͔ʔ]!9͔!9͔!~|ʷ]!9͔!9͔!$|]!9͔!9͔!|]!9͔!!&d! !9!,d! 9͔W!9* / %!g͕T|ld!9͔,d|Ud͎A!!~!9͔xo!!g͕T|ʪd!9͔6b!9_|b!9Fp!9͔ !9 ͔ԇ!9͔ p!!9!9|=^=&=+=-=*=/=%=>>=<<==!b!~!9͔͇!|ʧh!jcR!9!ԇ!9!9O!9!ԇ!!!_! 9!9/Y! 9!jiA!9͔|ei9͔͔os!Rb͕T|+`!9! ~ԇHa!Ub͕T|F`!9!~ԇHa!Xb͕T|a`!9!'~ԇHa![b͕T||`!9!}ԇHa!^b!9͔͇ԇ!9͔͔|ʵf!t!9͔͇ԇ!!9!9͔gԇ!g͕T|Bg9͔!| ^!9͔ !9͔!i|C^!9͔!9͔!|f^!9͔!9͔!F~|ʉ^!9͔,d|“d͎A!!~!9͔xo!!g͕T|d!9͔,d|d!9͔Fps~!9͔!9͔͔lԇ!!  /* ** utoi -- convert unsigned decimal string to integer nbr ** returns field size, else ERR on error */ utoi(decze either for code size or speed. It was assumed a post-processor optimizer would later be written for the target machine. atements "for", "switch", "case", and "default." (9) The use of arguments within a "#define" command. Compiler restrictionm" pseudo-op must appear on a line by itself (i.e. everything after #endasm is also thrown away). Since the parser is completeglbptr) { if(astreq(sname, cptr+NAME, NAMEMAX)) return cptr; cptr=nextsym(cptr); } #endif return 0; } fows the user to place assembly language code directly into the control context. Since it is considered by the compiler to be str, nbr) char *decstr; int *nbr; { int d,t; d=0; *nbr=0; while((*decstr>='0')&(*decstr<='9')) { t = *nbr;t=(10 (3) Since the target assembler is of unknown characteristics, no attempt is made to produce pseudo-ops to declare static vas include: (1) Since it is a single-pass compiler, undefined names are not detected and are assumed to be function names ly free-format outside of these execeptions, the expected format is as follows: if (expression) #asm ... ... #endasm indloc(sname) char *sname; { cptr = locptr - 1; /* search backward for block locals */ while(cptr > STARTLOC) { cpa single statement, it may appear in such forms as: while(1) #asm ... #endasm or if (expression) #asm...#endasm else... *t) + (*decstr++ - '0'); if ((t>=0)&(*nbr<0)) return ERR; d++; *nbr=t; } return d; } riables as internal or external. (4) Constants are not evaluated by the compiler. That is, the line of code: X = 1+2; wnot yet defined. If this assumption is incorrect, the undefined reference will not appear until the compiled program is ass /* ** xtoi -- convert hex string to integer nbr ** returns field size, else ERR on error */ xtoi(hexstr, nbr) chatr = cptr - *cptr; if(astreq(sname, cptr, NAMEMAX)) return (cptr - NAME); cptr = cptr - NAME - 1; } return 0;  Due to the workings of the preprocessor which must be suppressed in this construct, the pseudo-op "#asm" must be the last it(str)==0) error("missing token"); } needlval() { error("must be lvalue"); } findglb(sname) char *sname; { #ifdeould generated code to add "1" and "2" at runtime. The results are correct, but unnecessary code is the penalty. ASSEMembled. (2) No optimizing is done. The code produced is sound and capable of re-entrancy, but no attempt is made to optimir *hexstr; int *nbr; { int d,t; d=0; *nbr=0; while(1) { if((*hexstr>='0')&(*hexstr<='9')) t=48; else ibinary operators "&&", "||", and "?:". (7) The declaration specifiers "auto", "static", "extern", and "register". (8) The stem before the carriage return on the end of the line (i.e. the text between #asm and the is thrown away), and the "#endasf HASH if(search(sname, STARTGLB, SYMMAX, ENDGLB, NUMGLBS, NAME)) return cptr; #else cptr=STARTGLB; while(cptr < BLY LANGUAGE INTERFACE Interfacing to assembly language is relatively straight-forward. The "#asm ... #endasm" construct all f((*hexstr>='A')&(*hexstr<='F')) t=55; else if((*hexstr>='a')&(*hexstr<='f')) t=87; else break; if(d<4) ++d; elseʺl͇!|ʴl!9͔!9͔͇ԇ!t!9͔!9͔!9͔͇ԇԇ!!9!0!!9͔͇!|ʰj!9͔t!!9!9͔!9!9[can't subscript]can't subscript](!em͕T|k!9!9͔|Gq!O!9͔|5q!9!9͔ͨ{!9!9͔|r!9 ͔""*"!~*"!ڇ|eturn ((alpha(c))|(numeric(c))); } addwhile(ptr) int ptr[]; { int k; ptr[WQSP]=csp; /* and stk ptr */ !9͔!ԇwo͔|wo!9͔!9͔͔ԇ!9͔!9͔͔ԇ!9͔!9͔͔ԇ return ERR; *nbr = *nbr<<4; *nbr = *nbr+(*hexstr++)-t; } return d; } !!!!!![B! 9ԇ!9͔ԇ!9͔!ԇ!!9͔͏s|]mim!()!}mcR!os@inv!9͔_ԇ!gmiA!!9͔!̓D!0!!D|Im!9!0!Aԇ|&l͇|pkim!x!9͔ʝq!~!9͔!9{r*"!$*"!ڇ|q!2!9͔!9{r*"!|q!*!9͔!9{r*!O!9͔|bi!9͔͇!|Oi!9͔!Ys_i!9͔s}Åi!9͔͇!|ʂi͔|o ͔|oyFp!9͔!9͔͔!K!o{ ppy !ԇFp!9͔!9͔label) int label; { outstr("CC"); outdec(label); } /* ** test if given character is alphabetic */ alpha(c) charalid expression!9!ԇV!9͔|°my*!!ncS|nA|mn!9!9__!9͔|m3{y!9!9͔ԇ!9͔!9͔͇ԇ͇!|k!9͔!ԇ!9͔!9͔͇ԇ͇!| l!9"!|'r!!9͔!9{r*"!|Nr!9͔!Or*"!i|wr!w!9͔!9{r*"!Ȁ}}!9͔! 9͔!ԇԇ!9͔!9͔͇ԇ!9!ԇej!j͕T|Vj!9͔|i!͐m,j!9͔͇!͔!K!p p͔|='a')&(c<='z'))|((c>='A')&(c<='Z'))|(c=='_')); } /* ** test if given character is numeric */ numerԇ!n͕T|nnðm!niA!9͔!ncS|Jn!9͔!K}w!9͔|in!9͔S{ln{{*%"!9͔!a|͔!9͔͇ԇ!!!9!0!ͦAԇ|l͇!|l!9͔ԇ!9͔!ԇ͇!||ʠr!׀!9͔!9{r*"!|r!!9͔!9{r!9͔{r!9͔{O!9(,)| j!9͔Fp!͐m,j!9͔͐m!9! 9͔!"9͔!ԇԇԇej!9͔!9"h!9͔|ƒj!9͔!9Ϳw!9!9͔|ʢp!riA!9!9O!9_|p!9Fp!r͕T|pOppâp!9͔|q!riAic(c) char c; { return((c>='0')&(c<='9')); } /* ** test if given character is alphanumeric */ an(c) char c; { r"%"),)CCARGC!9͔͔!|ʴn!͔|n!!!9͔͔!!9͔͔!|o !9!9O!9! 9͔__!O!9͔|Es!SscR!9͔must be constant expression͡yPHRMOV D,HMOV E,L!yQXCHG;;!yQLXI H,!yQLXI D,!yQ*%"!`"%"PUSH H!9͔ ͔|y{zzz!9T]͔#ԇ+!9T]͔#ԇ+͇}z!9*!ԇ!9T]͔+ԇ!9͔2|z!{cS|z!9T]͔9͔͔ԇ͇!͇!|Vx!nxQQHR!sxS{lx!yxQQHRLDA CCSXTLHLD M!~Q!9T]͔+ԇ!|ʦ~é~Â~INX H!~Q!9T]͔+ԇ!|~~ð~DCX H!~S{CCEQ!Q!Q!9͔!s* "!9͔̓D* "" "literal queue overflow*"!\*"!ڇ|fvGG*"!n|ʁvG! !9͔寴|!||!||!}Q!9T]͔+ԇ#||!}Q!9!`ԇ|!9͔寴Q}!|y*!"E!+JQt!͔PHR!!9!9!ԇԇ!t͕T|Qtot!t͕T|lt!9!ԇotrtAt*"BF|…t!+ԇ!9!ԇ!9T]͔+ԇ͇BF|z͇!9͔`}!0|z͇ }!9!ԇz!9!ԇÏzIz*%"!D*%"`os!xQDAD SP!9!9͔͔ԇ͇!͇!|x!yQ!yQy!!yQEHRMOV A,HORA LJNZ !-S{CCNE!WQ!_Q!eQEHRMOV A,HORA LJZ !rS{CCLT!Q!*"!t|ʙvG! *"!b|ʱvG!*"!f|vG! !9!ԇ!9!ԇ!9T]͔+ԇ#!*"!0 Q}!|%}!}Q!9T]͔#ԇ+|H}!}Q!9ԇ%}!9͔!9͔|`}͑yos!}Q!}Q!9͔|*"BF|ʹt!9!9͔! s0H!0`ԇÅt|t!9gԇ!9͔ԇ!+-͡yQHR!"%" XCHG;; DAD SP!-{Q*%""%"POP D!<{QXTHL!J{S{CCSWITCH!h{QQHRCALL !w{QRET͡y!QQHRMOV A,LSTA SHLD ͔!|Qy!ZyQ!byQYy!iyS{MOV A,LSTAX DCCPINT!yQ!yQQ!QEHRXRA AORA HJP !S{CCLE!Q!Q!Q! Q!Q!QEHRMOV A,HO*"!7|:w!9!YG!0`ԇv!|OwGZwͺE"#"*#"!|ow!ywQEND!wʆ}͑y!9͔INX SPPOP BDCX SPPUSH BDAD SPSPHL!}QDAD H!}QDAD D!}S{CCSUB!}S{CCMULT!}S{CCD9!ԇ!ou͕T|u!*"!'|Uu!9!!s@v!ԇu*!#"!!9͔ԇ!';!!͕T|„u!{QHR3{!{Q*%""%"$+5PCHL!{QEHRJMP !{Q!{Q!{QEHRMOV A,HORA LJZ  RA LJZ $+8XRA AORA HJP !%S{CCGT!kQ!qQ!wQEHR!{Q!QEHRXRA AORA HJM ORA LCDECC DAD D POP D CALL CCPINTCALL CCDDPI DAD D POP D MOV A,L STAX DCALL CCDDPC POP D CALL CCPINTCALL CCPDPI POP D *5"ͳQ LXI H,0 DAD SP CALL CCGINT XCHG;; LXI H,2 DAD SP CALL CCGINT XCHG;; DAD SP CALL CCGINTCALL CCDSGI DA CMP H ;;COMPARE MSBS JNZ CCCMP1 ;;DONE IF NEQ MOV A,E ;;COMPARE LSBS 9͔ԇn!?cS|Â!TQ!9!9͔ԇn!`cS|!Q!9!9͔;ԇn!c ; CCLT: CALL CCCMP RC DCX H RET ; ;COMMON ROUTINE TO PERFORM A JZ !S{CCGE!Q!Q!ĀQEHRXRA AORA HJM !рS{CCULT!QEHRJMP !S{CCULEMOV A,L STAX DCALL CCPDPC!-Q!3QPOP HPUSH H!KQ!QQPOP DPUSH D!sQ!j!yQPOP BPUSH BD D CALL CCGINTCALL CCDDGI DAD SP CALL CCGCHARCALL CCDSGC DAD D CALL CCGCHARCALL CCDDGC DAD SP MOV D,H MOV E,L CALL  CMP L CCCMP1: LXI H,1 ;;PRESET TRUE COND RET ; ;TEST IF DE >= HL (UNSIGNED) S|'!Q!9!9͔;ԇn!cS|Y!.Q!9!9͔@ԇn!:cS|ʋ!zQ!9!9͔SIGNED COMPARE ; OF DE AND HL ;THIS ROUTINE PERFORMS DE - HL AND SETS THE CONDITIONS: ; CARRY REFLEC! S{CCUGT!S{CCUGE͇|ʏ!cS|ʈ!cS|n:!9!9͔&ԇÅ!9!9͔Ç##9~ogÔ##9~#fo##9T]͇+}##9T]͇#}}##9T]͔+ԇ##9T]͔#ԇ}|}o|g}o|g}o|g++CCGINT INX H CALL CCPINTCALL CCINCI DAD SP MOV D,H MOV E,L CALL CCGINT DCX H CALL CCPINTCALL CCDECI DAD SP MOV D,H ; CCUGE: CALL CCUCMP RNC DCX H RET ; ;TEST IF DE < HL (UNSIGNED) @ԇn!cS|ʽ!Q!9!9͔ԇn!cS|!̆Q!9!9͔ԇn!؆cS|TS SIGN OF DIFFERENCE (SET MEANS DE < HL) ; ZERO/NON-ZERO SET ACCORDING TO EQUALITY. ; CCCMP: MOV AԇÌ!cS|!ԄcS|с!:X!9!9͔&ԇ!X!9!9͔ԇÌ:| ͈|q++++|gz"{!@+@+@+@+zG{!||g}oL)Z{ozgl#|/g}/oDM!y~xMOV E,L CALL CCGCHAR INX H MOV A,L STAX DCALL CCINCC DAD SP MOV D,H MOV E,L CALL CCGCHAR DCX H MOV A,L STAX DCALL C ; CCULT: CALL CCUCMP RC DCX H RET ; ;TEST IF DE > HL (UNSIGNED) !!Q!9!9͔ԇn!cS|S!Q!9!9͔ԇn!9T]͔#ԇ+͇*5"ͳQÌ!9T]͔#ԇ+,H ;;INVERT SIGN OF HL XRI 80H MOV H,A MOV A,D ;;INVERT SIGN OF DE XRI 80H !܄cS|-!Q!9!9͔ԇn!cS|_!Q!9!9͔ԇn!cS|ʑ!3Q!9!GyOȯ{_zWxDMzzԈx܈>)}o{_zW=ɈéԈԈz/W{/_x/Gy/O{_zW{z|.!N  ; CCUGT: XCHG CALL CCUCMP RC DCX H RET ; ;TEST IF DE <= HL (T2: XRA A MOV A,B RAR MOV B,A MOV A,C RAR MOV C,A ORA B  ;FORM THE TWO'S COMPLEMENT OF HL ; CCNEG: CALL CCCOM INX H RET ; ; return 0; } findloc(sname) char *sname; { cptr = locptr - 1; /* search backward for block locals */ while(cptr MOV A,H RAL MOV A,H RAR MOV H,A MOV A,L RAR MOV L,A Jnk(); } multidef(sname) char *sname; { error("already defined"); } needtoken(str) char *str; { if (match(strUNSIGNED) ; CCULE: CALL CCUCMP RZ RC DCX H RET ; ;COMMRZ XRA A MOV A,E RAL MOV E,A MOV A,D RAL MOV D,A ORA E FORM THE ONE'S COMPLEMENT OF HL ; CCCOM: MOV A,H CMA MOV H,A MOV A,L CMA > STARTLOC) { cptr = cptr - *cptr; if(astreq(sname, cptr, NAMEMAX)) return (cptr - NAME); cptr = cptr - NAME - 1MP CCASR+1 ; ;SHIFT DE ARITHMETICALLY LEFT BY HL AND RETURN IN HL ; CCASL: XCHG D)==0) error("missing token"); } needlval() { error("must be lvalue"); } findglb(sname) char *sname; { #ifdef ON ROUTINE TO PERFORM UNSIGNED COMPARE ;CARRY SET IF DE < HL ;ZERO/NONZERO SET ACCORDINGLY ; CCUCMP: RZ JMP CCMLT1 ; ;DIVIDE DE BY HL AND RETURN QUOTIENT IN HL, REMAINDER IN DE ;(SIGNED MOV L,A RET ; ;MULTIPLY DE BY HL AND RETURN IN HL ;(SIGNED MULTIPLY) ; C DIVIDE) ; CCDIV: DIV: MOV B,H MOV C,L MOV A,D XRA B PUSH PSW MOV A,CR E RM DAD H JMP CCASL+1 ; ;SUBTRACT HL FROM DE AND RETURN IN HL ; CCSUBHASH if(search(sname, STARTGLB, SYMMAX, ENDGLB, NUMGLBS, NAME)) return cptr; #else /* HASH */ cptr=STARTGLB; whil MOV A,D CMP H JNZ CCUCP1 MOV A,E CMP L CCUCP1: LXI H,1 RET ; #F#x~#~#`izԈx܈>)}o{_zW=ɈéԈԈz/W{/_x/Gy/O{_zW{z|.!NCMULT: MULT: MOV B,H MOV C,L LXI H,0 CCMLT1: MOV A,C RRC JNC CCMLT2 DAD D CCMLD ORA A CM CCDENEG MOV A,B ORA A CM CCBCNEG MVI A,16 PUSH PSW : MOV A,E SUB L MOV L,A MOV A,D SBB H MOV H,A RET ; e(cptr < glbptr) { if(astreq(sname, cptr+NAME, NAMEMAX)) return cptr; cptr=nextsym(cptr); } #endif /* HASH */  ;SHIFT DE ARITHMETICALLY RIGHT BY HL AND RETURN IN HL ; CCASR: XCHG DCR E RM s(); } endst() { blanks(); return ((streq(lptr,";")|(ch==0))); } illname() { error("illegal symbol"); ju  XCHG LXI D,0 CCDIV1: DAD H CALL CCRDEL JZ CCDIV2 CALL CCCMPBCDE JM CCDIV2 . ; DW 0 ; [JMP default] ; continuation ; CCSWITCH: XE ;(INTERNAL ROUTINE) ; CCCMPBCDE: MOV A,E SUB C MOV A,D SBB B RET n the stack may be modified by the called program. STACK FRAME The stack is used extensively by the compiler. Funct CMA MOV E,A INX D RET ; ;NEGATE THE INTEGER IN BC ;(INTERNAL ROUTINE) from the c-code have access to all registers and do not have to restore them prior to exit. They may push items on the stack  MOV A,L ORI 1 MOV L,A MOV A,E SUB C MOV E,A MOV A,D SBB Belse statement; Note a semicolon is not required after the #endasm since the end of context is obvious to the compiler. Ass ; ; LOGICAL NEGATION ; CCLNEG: MOV A,H ORA L JNZ $+6 MVI L,1 ion arguments are pushed onto the stack as they are encountered between parentheses (note, this is opposite that of standard C ; CCBCNEG: MOV A,B CMA MOV B,A MOV A,C CMA MOV C,A INX Bas well, but must pop them off before exit. It is the responsibility of the calling program to remove arguments from the stac MOV D,A CCDIV2: POP PSW DCR A JZ CCDIV3 PUSH PSW JMP CCDIV1 CCDIV3: POP PSW embly language code within the "#asm ... #endasm" context has access to all global symbols and functions by name. It is up to  RET LXI H,0 RET ; ; EXECUTE "SWITCH" STATEMENT ; ; HL = SWITCH VAL, which means routines expressly retrieving arguments from the stack rather than declaring them by name must beware). By the d RET ; ;ROTATE DE LEFT ONE BIT ;(INTERNAL ROUTINE) ; CCRDEL: MOV A,E RAL k after a function call. This must not be done by the function itself. There is no limit to the number of bytes the function RP CALL CCDENEG XCHG CALL CCDENEG XCHG RET ; ;NEGATE THE INthe programmer to know the data type of the symbol (whether "char" or "int" implies a byte access or a word access). Stack loUE ; (SP) -> SWITCH TABLE ; DW ADDR1, VALUE1 ; DW ADDR2, VALUE2 ; ..efinition of the language, parameter passing is "call by value". For example the following code would be produced for the C s MOV E,A MOV A,D RAL MOV D,A ORA E RET ; ;COMPARE BC TO D may push onto the stack, providing they are removed prior to returning. Since parameters are passed by value, the paramters oTEGER IN DE ;(INTERNAL ROUTINE) ; CCDENEG: MOV A,D CMA MOV D,A MOV A,E cals and arguments may be retrieved by offset (see STACK FRAME). External assembly language routines invoked by function calls  tatement: function(X, Y, z()); LHLD X PUSH H LHLD Y PUSH H CALL z PUSH H CALL function POP B POP B POP B and UNIX), this was the preferred method. The questions asked are as follows: Do you want the c-text to appear? This ginumber of bytes, whereas function arguments always consist of two bytes apiece. In the event the argument was type "char" (8 UATION CODE MOV A,M INX H CMP E MOV A,M INX H JNZ SWLOOP CMP D ration is made: char array[3]; the code would be: DCX SP PUSH B Array[0] would be at SP+0, array[1] would be at  the module being compiled. This is the normal method. If N, no storage will be allocated, but symbol references will still Notice, the compiler cleans up the stack after the call using a simple algorithm to use the least number of bytes. Localves the user the option of interleaving the source code into the output file. Response is Y or N. If Y, a semicolon will be pbits), the most significant byte of the 2-byte value is a sign-extension of the lower byte. OPERATING THE COMPILER  JNZ SWLOOP MOV H,B ;;CASE MATCHED MOV L,C SWEND: PCHL ; #endasm  CMP D SP+1, array[2] would be at SP+2, and X would now be at SP+3. Thus, assembly language code using "#asm...#endasm" cannot acces be made in the normal way. Essentially, this question allows the user to specify all or none of the static symbols external. variables allocate as much stack space as is needed, and are then assigned the current value of the stack pointer (after the laced at the start of each input line (to force a comment to the 8080 assembler) and the input lines will be printed where appThe small C compiler begins by asking the user for a number of options regarding the expected compilation. Since it was easiere it for later MVI C,QUERY ; get logged-in disk CALL BDOS INR A ; make it so it will work in fcb STA DFLTDSK LDA BDOS+2 ; Gs local variables by name, but must know how many intervening bytes have been allocated between the declaration of the variableCHG ;;DE = SWITCH VALUE POP H ;;HL -> SWITCH TABLE SWLOOP: MOV C,M INX H MOV Ballocation) as their address. int X; would produce: PUSH B which merely allocates room on the stack for 2 bytes (nropriate. If the answer is N, only the generated 8080 code will be output. Do you wish the globals to be defined? This qu to ask questions than to pull arguments from a command line (which is in no way similar between the 8080 developmental systemet base of BDOS MOV H,A ; Save page in HL MVI L,0 SPHL ; Set stack pointer LXI H,STDIN SHLD RSTDIN ; Init rstdin LXI H,ST and its use. It is worth pointing out local declarations allocate only as much stack space as is required, including an odd ,M ;;BC -> CASE ADDR, ELSE 0 INX H MOV A,B ORA C JZ SWEND ;;DEFAULT OR CONTINot initialized to any value). References to the local variable X will now be made to the stack pointer + 0. If another declaestion is primarily a developmental aid between machines. If the answer is Y, all static symbols will allocate storage within! DOUT SHLD RSTDOUT ; Init rstdout MVI C,0 ; Init argc LXI H,ARGV ; Pointer to first entry of argv array ; Unfortunately, CPM SIZE); #else /* DYNAMIC */ swnext=swq; swend=swnext+SWTABSZ-SWSIZ; stagelast=stage+STAGELIMIT; #endif /* DYNAMIC */* CMD_LINE */ sout("Small-C Ver. ", stderr); sout(VERSION, stderr); sout(" ", stderr); lout(DATE, stderr); #i*/ symtab=CCALLOC(NUMLOCS*SYMAVG); /* global space is allocated with each new entry */ #endif /* HASH */ #endif /* DYNint ii; if (argc > MAXARGS) { lout("too many command arguments", stderr); abort(ERRCODE); } argcs=argc;  /* enable preprocessing */ wqptr=wq; /* clear while queue */ quote[0]='"'; /* fake a quote literal */ idoes not tell us what the first word of ; the command line was (the name of pgm), so we fake ; it by pointing ; it by pointing  swactive= /* not in switch */ stagenext= /* direct output mode */ iflevel= /* #if... nesting levelfdef DYNAMIC swnext=CCALLOC(SWTABSZ); swend=swnext+((SWTABSZ-SWSIZ)>>1); stage=CCALLOC(STAGESIZE); stagelast=stage+SAMIC */ #ifdef HASH cptr=STARTGLB-1; while(++cptr < ENDGLB) *cptr=0; #endif /* HASH */ glbptr=STARTGLB; glbfla ii = 0; while(argc--) argvs[ii++] = *argv++; /* make static copy of args */ #else /* N_CMD_LN */ /* * originalnput=input2= EOF; /* * this is where the nitty-gritty begins */ ask(); /* get user options */ openin();  /* ** execution begins here */ /* * there are four different versions of the beginning of the * main procedure, dependi = 0 */ skiplevel= /* #if... not encountered */ macptr= /* clear the macro pool */ csp = /* stacTAGELIMIT; wq=CCALLOC(WQTABSZ*BPW); litq=CCALLOC(LITABSZ); #ifdef HASH macn=CCALLOC(MACNSIZE); cptr=macn-1; whg=1; ctext=0; header(); /* intro code */ setops(); /* set values in op arrays */ parse();  command line processing. * NOTE: the function 'getarg' is not in the library * supplied with this distribution. */ main( /* and initial input file */ preprocess(); /* fetch first line */ #ifdef SMALL_VM fopen(" ",NULL);/* pre-alloc FCng on the compiler used and whether * command line processing is used. */ #ifdef CMD_LINE #ifdef N_CMD_LN #ifdef FULLC k ptr (relative) */ errflag= /* not skipping errors till ";" */ eof= /* not eof yet */ ncmp= ile(++cptr < MACNEND) *cptr=0; #endif /* HASH */ macq=CCALLOC(MACQSIZE); pline=CCALLOC(LINESIZE); mline=CCALLOC(LINE /* process ALL input */ outside(); /* verify outside any function */ trailer(); /* follow-up code */ argc, argv) int argc, *argv; { argcs=argc; argvs=argv; #endif /* N_CMD_LN */ #else /* CMD_LINE */ main() { #endif /B for include file */ #endif #ifdef DYNAMIC #ifdef HASH symtab=CCALLOC(NUMLOCS*SYMAVG + NUMGLBS*SYMMAX); #else /* HASH  main(argc, argv) int argc; char *argv[]; { #else /* FULLC */ main(argc, argv) int argc, argv[]; { #endif /* FULLC */  /* not in compound statement */ files= filearg= 0; quote[1]='\0'; func1= /* first function */ ccode=1;" fclose(output); } /* ** process all input text ** ** At this level, only static declarations, ** defines, includeIMIZE optimize= #endif /* OPTIMIZE */ alarm=monitor=pause=m80flg=NO; line=mline; #ifdef N_CMD_LN while(++i < a j=30; while(j--) { outdec(0); if ((--count <= 0)|(j==0)) { nl(); break; }  #ifdef OPTIMIZE sout(" [-o]", stderr); #endif /* OPTIMIZE */ #ifndef LINK sout(" [- POLL CCPOLL(1); /* allow program interruption */ #endif defstorage(size); j=10; while(j--) { outd': pause = YES; break; #ifdef OPTIMIZE case 'O': optimize = YES; break; #s and function ** definitions are legal... */ parse() { while (eof==0) { if(amatch("extern", 6)) dodeclare(EXTrgcs) { line = argvs[i]; if (line[0] == '-') { switch (upper(line[1])) { case 'L': if (numeric(line[2 outbyte(','); } } } /* ** verify compile ends outside any function */ outside() { if (ncmp) error(b#]", stderr); #endif /* LINK */ sout("\n", stderr); abort(ERRCODE); } ec(getint(litq+k, size)); k=k+size; if ((j==0)|(k>=litptr)) { nl(); break; } outendif /* OPTIMIZE */ #ifndef LINK case 'B': if (numeric(line[2]) & (line[3] <= ' ')) { bump(0);ERNAL); else if(dodeclare(STATIC)); else if(match("#asm")) doasm(); else if(match("#include"))doinclude(); ]) & (line[3] <= ' ')) { listfp = line[2] - '0'; break; } "no closing bracket"); } /* ** get run options */ #ifdef CMD_LINE ask() { int i; i=listfp=nxtlab=0; #ifdef C8} } #else /* N_CMD_LN */ /* ** use original input processing abortion */ while(getarg(++i, line, LINESIZE,byte(','); } } } /* ** dump zeroes for default initial values */ dumpzero(size, count) int size, count; {  bump(2); if(number(&nxtlab)) break; } /* fall through to error c else if(match("#define")) addmac(); else newfunc(); blanks(); /* force eof if pending */  else goto errcase; case 'A': alarm = YES; break; ca0 output=fout; /* V6 convention */ #else /* C80 */ output=stdout; /* V7 convention */ #endif /* C80 */ #ifdef OPT argcs, argvs)!=EOF) { if(line[0]!='-') continue; if((upper(line[1])=='L')&(numeric(line[2]))&(line[3]<=' ')) {  int j; while (count > 0) { #ifdef POLL CCPOLL(1); /* allow program interruption */ #endif defstorage(size);ase */ #endif /* LINK */ errcase: default: sout("usage: cc [file]... [-c] [-m] [-a] [-p] [-l#]", stderr);  } } /* ** dump the literal pool */ dumplits(size) int size; { int j, k; k=0; while (k= ENDGLB) {  zzsub; op2[13]= op[13]=zzmult; /* heir12 */ op2[14]= op[14]= zzdiv; op2[15]= op[15]= zzmod; }  return 0; } findloc(sname) char *sname; { cptr = locptr - 1; /* search backward for block locals */ while(cptrD_LINE */ setops() { op2[00]= op[00]= zzor; /* heir5 */ op2[01]= op[01]= zzxor; /* heir6 */ op2[02]= nk(); } multidef(sname) char *sname; { error("already defined"); } needtoken(str) char *str; { if (match(str CP/M STACK: DW 0 ; ; abort(reason) ; ABORT: POP B POP D PUSH D PUSH B PUSH D ; error code LXI H,ABTMSG ; Load a error("global symbol table overflow"); return 0; } #endif /* DYNAMIC */ cptr = *lgptrptr; #endif /* HA; Sign extend A into HL register pair RLC SBB A MOV H,A RET ; exit() ; ; Stop execution of the program, ; restore th > STARTLOC) { cptr = cptr - *cptr; if(astreq(sname, cptr, NAMEMAX)) return (cptr - NAME); cptr = cptr - NAME - 1op[02]= zzand; /* heir7 */ op2[03]= op[03]= zzeq; /* heir8 */ op2[04]= op[04]= zzne; op2[05]=ule; op[05]= )==0) error("missing token"); } needlval() { error("must be lvalue"); } findglb(sname) char *sname; { #ifdef bort message PUSH H LXI H,STDERR PUSH H CALL FPUTS POP B POP B LXI H,2 CALL CCDSGI PUSH H ; Someday this shouSH */ } else { if(locptr > (ENDLOC-SYMMAX)) { error("local symbol table overflow"); abort(ERRCODE);e logged-in drive, ; and re-boot CP/M ; EXIT: LHLD RSTDOUT MOV A,H ORA A ; See if stdout has been redirected JZ EXIT1 ; } return 0; } addsym(sname, id, typ, value, lgptrptr, class) char *sname, id, typ; int value, *lgptrptr, clazzle; /* heir9 */ op2[06]=uge; op[06]= zzge; op2[07]=ult; op[07]= zzlt; op2[08]=ugt; op[08]= zzgt; op2[09]= HASH if(search(sname, STARTGLB, SYMMAX, ENDGLB, NUMGLBS, NAME)) return cptr; #else /* HASH */ cptr=STARTGLB; whil junk() { if(an(inbyte())) while(an(ch)) gch(); else while(an(ch)==0) { if(ch==0) break; gch(); } blank } cptr = *lgptrptr; } cptr[IDENT]=id; cptr[TYPE]=typ; cptr[CLASS]=class; putint(value, cptr+OFFSET PUSH H CALL FCLOSE ; If so, close the file POP B EXIT1: LDA DFLTDSK ; Grab orig. logged-in disk MOV E,A DCR E ; (css; { if(lgptrptr == &glbptr) { if(cptr2=findglb(sname)) return cptr2; #ifdef HASH if(cptr==0) { error("gop[09]= zzasr; /* heir10 */ op2[10]= op[10]= zzasl; op2[11]= op[11]= zzadd; /* heir11 */ op2[12]= op[12]=e(cptr < glbptr) { if(astreq(sname, cptr+NAME, NAMEMAX)) return cptr; cptr=nextsym(cptr); } #endif /* HASH */ % , OFFSIZE); cptr3 = cptr2 = cptr + NAME; while(an(*sname)) *cptr2++ = *sname++; #ifdef HASH if(lgptrptr == &locptr) internal label number */ getlabel() { return(++nxtlab); } /* ** post a label in the program */ postlabel(label) in string is legal symbol name */ symname(sname, ucase) char *sname; int ucase; { int k;char c; blanks(); if(alpha(ch)=/ if (ptr <= wq) { error("out of context"); return 0; } else return (ptr-WQSIZ); } white() { /* tes #endif /* HASH */ /* ** get integer of length len from address addr ** (byte sequence set by "putint") */ getint(addr, lha(c))|(numeric(c))); } addwhile(ptr) int ptr[]; { int k; ptr[WQSP]=csp; /* and stk ptr */ ptr[WQLOOP]{ *cptr2 = cptr2 - cptr3; /* set length */ *lgptrptr = ++cptr2; } #else /* HASH */ *cptr2 = cptr2 - ct label; { printlabel(label); col(); nl(); } /* ** print specified number as a label */ printlabel(label) int=0) return 0; k=0; while(an(ch)) { #ifdef UPPER if(ucase) sname[k]=upper(gch()); else #endif /* UPPERt for stack/program overlap */ /* primary -> symname -> blanks -> white */ #ifdef DYNAMIC CCAVAIL(); /* abort on stacken) char *addr; int len; { int i; i = *(addr + --len); /* high order byte sign extended */ while(len--) i = (i << 8) |=getlabel(); /* and looping label */ ptr[WQEXIT]=getlabel(); /* and exit label */ if (wqptr==WQMAX) { error("too mptr3; /* set length */ *lgptrptr = ++cptr2; #ifdef DYNAMIC if(lgptrptr == &glbptr) CCALLOC(cptr2 - cptr); /* label; { outstr("CC"); outdec(label); } /* ** test if given character is alphabetic */ alpha(c) char c; { re */ sname[k]=gch(); if(k='a')&(c<='z'))|((c>='A')&(c<='Z'))|(c=='_')); } /* ** test if given character is numeric */ numeric(c) charics */ upper(c) char c; { if((c >= 'a') & (c <= 'z')) return (c - 32); else return c; } /* ** return next avail ch() { int c; if(c=ch) bump(1); return c; } bump(n) int n; { if(n) lptr=lptr+n; else lptr=line; if(ch =addr, len) char *addr; int i, len; { while(len--) { *addr++ = i; i = i>>8; } } /* ** test if next input patched per DDJ */ if(wqptr > wq) wqptr=wqptr-WQSIZ; } readwhile(ptr) int *ptr; { /* ** patched per DDJ * nextsym(entry) char *entry; { entry = entry + NAME; while(*entry++ >= ' '); /* find length byte */ return entry; }  c; { return((c>='0')&(c<='9')); } /* ** test if given character is alphanumeric */ an(c) char c; { return ((alp&  nch = *lptr) nch = *(lptr+1); } kill() { *line=0; bump(0); } inbyte() { while(ch==0) { if (eof) retuunit < 256) { JNZ CGET1 ; /* assume stdin */ CALL GETCHAR ; getchar(); POP D ; /* return to caller of getc() POP DOV A,H ; *B++ = H; STAX B INX B DCR L ; L--; JMP FCBPAD ; } PAD2: RET ; return; ; ; getc(unit) ; FGETC:  else fname = lptr; /* no '"' or '<' (original convention) */ if((input2=fopen(fname,"r"))==NULL) { input2=  } } } /* * special version of 'fgets' that deletes trailing '\n' */ #ifdef FULLC char * xgets(string, leclude files not allowed"); kill(); /* ignore rest of line */ return; } blanks(); /* skip over to namrn 0; preprocess(); } return gch(); } inline() { int k,unit; #ifdef FULLC char *xgets(); #endif /* F ; to bypass CR check */ RET ; return; } CGET1: SHLD UNIT LXI D,FLAG ; if(unit[FLAG] & EOF_FL) DAD D MOV A,M A GETC: POP B POP H ; get args PUSH H PUSH B ; c=cget(unit); PUSH H CALL CGET POP D MOV A,L ; if(c=='\rEOF; error("open failure on include file"); } kill(); /* clear rest of line */ /* so next read will n, fd) char *string; int len, fd; { #else /* FULLC */ xgets(string, len, fd) char *string; int len, fd; { #endif /* FULLC *e */ /* * added code to handle include filename in quotes or brackets * 4/5/83 br */ if ((*lptr == '"') | (*lpULLC */ #ifdef POLL CCPOLL(1); /* allow program interruption */ #endif /* POLL */ while(1) { if (input == EOF)NI EOFFLG JZ GTCIF1 LXI H,-1 ; return(-1); RET GTCIF1: LHLD UNIT ; ip = unit + FCBSIZE; LXI D,FCBSIZE DAD D S') ANI 7FH ; /* mask parity in compare */ CPI EOL JNZ GETCRET PUSH H ; cget(unit); PUSH D ; /* to skip LF */ come from */ /* new file (if open) */ } /* ** test for global declarations */ dodeclare(class) int class; { i/ char c, *strptr; strptr = string; while ((((c = getc(fd)) & 127) != '\n') && (--len)) { if (c == EOF) return Ntr == '<')) { i = 0; fname = buff; while (i<14) { c = *++lptr; if ((c == '"') | (c == '>'))  openin(); if(eof) return; if((unit=input2) == EOF) unit=input; if(xgets(line, LINEMAX, unit)==NULL) { fcl /* ** open an include file */ doinclude() { char c, *fname, buff[15]; int i; /* * test for nested includes adCALL CGET POP H POP H GETCRET: RET ; ; cget(unit) ; CGET: POP D POP H PUSH H PUSH D MOV A,H ORA A ; if(f(amatch("char",4)) { declglb(CCHAR, class); ns(); return 1; } else if((amatch("int",3))|(class==EXTERNALULL; else *string++ = c & 127; /* mask parity off */ } *string = NULL; return strptr; } c == EOF) return N i = 14; /* force exit from loop */ else *fname++ = c; } *fname = '\0'; fname = buff; } ose(unit); if(input2 != EOF) input2 = EOF; else input = EOF; } else { bump(0); return; ded 4/7/83 br. * (this may be buried somewhere else, but I don't see it) */ if(input2 != EOF) { error("nested in' )) { declglb(CINT, class); ns(); return 1; } return 0; } /* ** declare a static variable */ decl } else j=POINTER; } else if(match("()")) j=FUNCTION; else if((typ==CCHAR)&(j==VARIABLck"); while(1) { while(1) { if(endst()) return; if(match("*")) j=POINTER; else j=VARIABLE; i(constexpr(&value)) { if(ident==POINTER) error("cannot assign to pointer"); stowlit(value, size); *dim = *dim - 1laration type not allowed"); j=ARRAY; /* !0=array */ /* I don't understand this comment. br */ } if(class==); } else init(size, ident, &dim); } if((dim == -1)&(dim==savedim)) { stowlit(0, size=BPW); identglb(type, class) int type, class; { int k, j; while(1) { if(endst()) return; /* do line */ if(match("*")) {E)) k=SBPC; declared = declared + k; addsym(ssname, j, typ, csp - declared, &locptr, AUTOMATIC); break; f (symname(ssname, YES)==0) illname(); /* no multidef check, block-locals are together */ k=BPW; if (match(; } } /* ** get required array size */ needsub() { int val; if(match("]")) return 0; /* null size */ if EXTERNAL) external(ssname); else j=initials(type>>2, j, k); addsym(ssname, j, type, k, &glbptr, class); if (match=POINTER; } dumplits(size); dumpzero(size, dim); return ident; } /* ** evaluate one initializer */ init(s j=POINTER; k=0; } else { j=VARIABLE; k=1; } if (symname(ssname, YES)==0) il } if (match(",")==0) return; } } /* ** initialize global objects */ initials(size, ident, dim) int size, "[")) { k=needsub(); if(k) { /* * check for `*var[nn]' 4/7/83 br */ (constexpr(&val)==0) val=1; if (val<0) { error("negative size illegal"); val = -val; } needtoken("]"); (",")==0) return; /* more? */ } } /* ** declare local variables */ declloc(typ) int typ; { int k,j; #ifdefize, ident, dim) int size, ident, *dim; { int value; if(qstr(&value)) { if((ident==VARIABLE)|(size!=1)) error(lname(); if(findglb(ssname)) multidef(ssname); if(match("()")) j=FUNCTION; else if (match("[")) { k=needsuident, dim; { int savedim; litptr=0; if(dim==0) dim = -1; savedim=dim; entry(); if(match("=")) { if(match if (j==POINTER) error("declaration type not allowed"); j=ARRAY; if(typ==CINT)k=k< SWITCH TABLE ; DW C"); ptr=ptr+22; } else if(streq(ptr, " DAD D\n CALL CCGCHAR")) { ol("CALL CCDDGC");  ol("POP H"); ol("PUSH H"); } pp2() { ol("POP D"); ol("PUSH D"); } #ifdef FULLC pp3(pp) int (*pp)(); { ix characters */ #else /* M80 */ ol("CALL CCDDPDPC"); #endif /* M80 */ ptr=ptr+31; } else iffull C */ /* #define C80 /* bootstrap compile with C/80 compiler */ #define M80 /* generate m80 compatable library ce if(streq(ptr, " DAD SP\n MOV D,H\n MOV E,L\n CALL CCGCHAR\n DCX H\n MOV A,L\n STAX D")) { ol("CALL CCDECC"); ADDR1, VALUE1 ; DW ADDR2, VALUE2 ; ... ; DW 0 ; [JMP default] ptr=ptr+21; } else if(streq(ptr, " DAD SP\n MOV D,H\n MOV E,L\n CALL CCGINT\n INX H\n CALL CCPINT")) {  ol("POP B"); (*pp)(); ol("PUSH B"); } #else /* FULLC */ pp3(pp) int pp; { ol("POP B"); pp(); ol("PUSH B, alls */ #define PHASE2 /* 2nd and later compiles */ #define SEPARATE /* compile separately */ #define OPTIMIZE /* compile oe FUNCTION 4 /* ** possible entries for "TYPE" ** low order 2 bits make type unique within length ** high order bit /* ** symbol table parameters */ #define NUMLOCS 25 #define STARTLOC symtab #define ENDLOC (symtab+(NUMLOCS*SYMAVG)ne MACNBR 90 #define MACNSIZE 990 /* 90*(NAMESIZE+2) */ #define MACNEND (macn+MACNSIZE) #define MACQSIZE 450 /* 90*5 * force symbols to upper case */ #define LINK /* will use with linking loader */ /* ** machine dependent parameters */ WQTABSZ-WQSIZ) /* ** entry offsets in while queue */ #define WQSP 0 #define WQLOOP 1 #define WQEXIT 2 /* ** lutput optimizer */ #define NOCCARGC /* no calls to CCARGC */ /* #define HASH /* use hash search for macros */ /* #define s give length of object */ /* LABEL 0 */ #define CCHAR (1<<2) #define CINT (BPW<<2) /* ** possible entries ) #define NUMGLBS 180 #define STARTGLB ENDLOC #define ENDGLB (ENDLOC+((NUMGLBS-1)*SYMMAX)) #define SYMTBSZ 2770 /* N/ #else /* HASH */ #define MACQSIZE 950 #endif /* HASH */ #define MACMAX (MACQSIZE-1) /* ** statement types */ # #define BPW 2 /* bytes per word */ #define LBPW 1 /* log2(BPW) */ #define SBPC 1 /* stack bytes per characteriteral pool */ #define LITABSZ 700 #define LITMAX (LITABSZ-1) /* ** input line */ #define LINEMAX 100 #define LINESSMALL_VM /* uses Small-VM interface */ #define CMD_LINE /* command line run options */ /* #define DYNAMIC /* allocate memory for "CLASS" */ /* LABEL 0 */ #define STATIC 1 #define AUTOMATIC 2 #define EXTERNAL 3 /* ** "switch" table UMLOCS*SYMAVG + NUMGLBS*SYMMAX */ /* ** System wide name size (for symbols) */ #define NAMESIZE 9 #define NAMEMAX 8 define STIF 1 #define STWHILE 2 #define STRETURN 3 #define STBREAK 4 #define STCONT 5 #define STASM 6 #de */ #define ERRCODE 7 /* op sys return code */ /* ** symbol table format */ #define IDENT 0 #define TYPE 1 #dIZE 101 /* ** command line */ #define MAXARGS 32 /* maximum number of option arguments */ /* ** output staging budynamically */ /* #define POLL /* poll for operator interruptions */ /* #define PDS /* uses PDS assembler and loader  */ #ifdef PHASE2 #define SWSIZ (2*BPW) #define SWTABSZ (25*SWSIZ) #else /* PHASE2 */ #define SWSIZ 4 #define SWTABSZ /* ** possible entries for "IDENT" */ #define LABEL 0 #define VARIABLE 1 #define ARRAY 2 #define POINTER 3 #definfine STEXPR 7 #define STDO 8 /* compile "do" logic */ #define STFOR 9 /* compile "for" logic */ #define STSWITCH efine CLASS 2 #define OFFSET 3 #define NAME 5 #define OFFSIZE (NAME-OFFSET) #define SYMAVG 10 #define SYMMAX 14 ffer size */ #define STAGESIZE 800 #define STAGELIMIT (STAGESIZE-1) /* ** macro (define) pool */ #ifdef HASH #defi*/ #define COL /* terminate labels with a colon */ #define TAB 9 /* put out tabs of this value */ #define UPPER /* 100 #endif /* PHASE2 */ /* ** "while" statement queue */ #define WQTABSZ 30 #define WQSIZ 3 #define WQMAX (wq+- 10 /* compile "switch/case/default" logic */ #define STCASE 11 #define STDEF 12 #define STGOTO 13 /* compile "goto" lo ol("EXTRN"); } #endif /* LINK */ } /* ** fetch object indirect to primary register */ indirect(lval) int lval[RGC")==0) { #endif /* HASH */ ot("MVI A,"); outdec(val); nl(); } } /* ** declare entry point */ ; } /* ** move primary register to secondary */ move() { ol("MOV D,H"); ol("MOV E,L"); } /* ** swap primar { #ifdef SMALL_VM #ifndef LINK if((beglab == 1)|(beglab > 9000)) #endif /* LINK */ { ol("CC9997:JMP CCconst(getint(sym+OFFSET, OFFSIZE)-csp); ol("DAD SP"); } /* ** store primary register into static cell */ putmem(lvalgic */ pile "switch/case/default" logic */ #define STCASE 11 #define STDEF 12 #define STGOTO 13 /* compile "goto" lo]; { if(lval[1]==CCHAR) call("CCGCHAR"); else call("CCGINT"); } /* ** fetch a static memory cell intoentry() { outstr(ssname); col(); #ifdef LINK if (m80flg) { col(); nl(); } else ol("ENTRY"); y and secondary registers */ swap() { ol("XCHG;;"); /* peephole() uses trailing ";;" */ } /* ** partial instructionBOJ"); ol("CC9998:DS 6"); ol("PUSH D"); ol("LXI D,$+6"); ol("JMP CC9997"); ol("ORG CC9998"); ol("J) int lval[]; { char *sym; sym=lval[0]; if((sym[IDENT]!=POINTER)&(sym[TYPE]==CCHAR)) { ol("MOV A,L"); ot("ST /* ** print all assembler info before any code is generated */ header() { beglab=getlabel(); #ifndef LINK if(begl primary register */ getmem(lval) int lval[]; { char *sym; sym=lval[0]; if((sym[IDENT]!=POINTER)&(sym[TYPE]==CCHAR))#else /* LINK */ nl(); #endif /* LINK */ } /* ** declare external reference */ external(name) char *name; { #i to get immediate value ** into the primary register */ immed() { ot("LXI H,"); } /* ** partial instruction to get MP $+6"); } #endif /* SMALL_VM */ ol("END"); } /* ** load # args before function call */ loadargc(val) int vA "); } else ot("SHLD "); outstr(sym+NAME); nl(); } /* ** put on the stack the type object in primary regisab < 3) #endif /* LINK */ { #ifdef SMALL_VM ol("LXI D,$+6"); ol("JMP CC9998"); #endif /* SMALL_VM */ #i { ot("LDA "); outstr(sym+NAME); nl(); call("CCSXT"); } else { ot("LHLD "); outstr(sym+NAMfdef LINK if (m80flg) { ot("EXTRN "); outstr(name); nl(); } else { outstr(name); col(); immediate operand ** into secondary register */ immed2() { ot("LXI D,"); } /* ** push primary register onto stack al; { #ifdef HASH if(search("NOCCARGC", macn, NAMESIZE+2, MACNEND, MACNBR, 0)==0) { #else /* HASH */ if(findmac("NOCCAter */ putstk(lval) int lval[]; { if(lval[1]==CCHAR) { ol("MOV A,L"); ol("STAX D"); } else call("CCPINT")fdef LINK jump(beglab); #endif /* LINK */ } } /* ** print any assembler stuff needed at the end */ trailer()E); nl(); } } /* ** fetch addr of the specified symbol into primary register */ getloc(sym) char *sym; { . */ push() { ol("PUSH H"); csp=csp-BPW; } /* ** unpush or pop as required */ smartpop(lval, start) int lval[]; chmary register and jump if false */ testjump(label) int label; { ol("MOV A,H"); ol("ORA L"); ot("JZ "); printlabel call("CCSWITCH"); } /* ** call specified subroutine name */ call(sname) char *sname; { ot("CALL "); outstr(s ol("DCX SP"); k++; } while(k) { ol("PUSH B"); k=k+BPW; } return n/* TAB */ if(streq(sour," DAD SP")) { #endif /* TAB */ --sour; i=BPW; while(numeric(*(--sour))) {  ot("DB "); else ot("DW "); } /* ** point to following object(s) */ point() { ol("DW $+2"); } /* **ar *start; { if(lval[5]) pop(); /* secondary was used */ else unpush(start); } /* ** replace a push with a swap *(label); nl(); } /* ** test primary register against zero and jump if false */ #ifdef FULLC zerojump(oper, label, lname); nl(); } /* ** return from subroutine */ ret() { ol("RET"); } /* ** perform subroutine call to valueewsp; } } if(save) swap(); const(k); ol("DAD SP"); ol("SPHL"); if(save) swap(); return newsp; } if((*sour = *sour-i) < '0') { *sour = *sour+10; i=1; } else i=0; }  modify stack pointer to value given */ modstk(newsp, save) int newsp, save; { int k; k=newsp-csp; if(k==0)return ne/ unpush(dest) char *dest; { int i; char *sour; #ifdef TAB sour="\tXCHG;;"; /* peephole() uses trailing ";;" */ #val) int (*oper)(), label, lval[]; { clearstage(lval[7], 0); /* purge conventional code */ (*oper)(label); } #else /* on stack */ callstk() { immed(); outstr("$+5"); nl(); swapstk(); ol("PCHL"); csp=csp+BPW; } /* ** ju /* ** double primary register */ doublereg() {ol("DAD H");} ); ol("SPHL"); if(save) swap(); return newsp; } } } csp=csp+BPW; } /* ** pop stack to the secondary register */ pop() { ol("POP D"); csp=csp+BPW; wsp; if(k>=0) { if(k<7) { if(k&1) { ol("INX SP"); k--; } while(k) { olelse /* TAB */ sour=" XCHG;;"; /* peephole() uses trailing ";;" */ #endif /* TAB */ while(*sour) *dest++ = *sour++;  FULLC */ zerojump(oper, label, lval) int oper, label, lval[]; { clearstage(lval[7], 0); /* purge conventional code */ omp to internal label number */ jump(label) int label; { ot("JMP "); printlabel(label); nl(); } /* ** test pri LXI H,46 CALL CCEQ MOV A,H ORA L JZ CC69 LXI H,20 DAD SP PUSH H LXI H,14 DAD SP MOV D,H MOV E,L CALL CC } /* ** swap primary register and stack */ swapstk() { ol("XTHL"); } /* ** process switch statement */ sw() {("POP B"); k=k-BPW; } return newsp; } } if(k<0) { if(k>-7) { if(k&1) {  sour=stagenext; while(--sour > dest) { /* adjust stack references */ #ifdef TAB if(streq(sour,"\tDAD SP")) { #else per(label); } #endif /* FULLC */ /* ** define storage according to size */ defstorage(size) int size; { if(size==1)/ GINT INX H CALL CCPINT PUSH H LXI H,26 DAD SP PUSH H CALL UTOI POP B POP B POP D CALL CCPINT XRA A ORA else if(amatch("switch",6)) {doswitch();lastst=STSWITCH;} else if(amatch("case",4)) {docase();lastst=STCASE;} elmp > 1) nogo=declared; /* disable goto if any */ #endif /* STGOTO */ csp=modstk(csp - declared, NO); declared = break; } else statement(); /* do one */ --ncmp; /* close current level */ csp=modstk(sI H,18 DAD SP MOV D,H MOV E,L CALL CCGINT DCX H DCX H CALL CCPINT CALL CCGINT POP D CALL CCPINT LXI H,11 TASM;} else {doexpr();ns();lastst=STEXPR;} } return lastst; } /* ** semicolon enforc H JM CC70 LXI H,12 DAD SP PUSH H LXI H,14 DAD SP CALL CCGINT XCHG;; LXI H,22 DAD SP CALL CCGINT DAD D se if(amatch("default",7)) {dodefault();lastst=STDEF;} #endif /* STSWITCH */ #ifdef STGOTO else if(amatch("goto", 4))  -1; } if(match("{")) compound(); else if(amatch("if",2)) {doif();lastst=STIF;} else ifavcsp, NO); /* delete local variable space */ #ifdef STGOTO cptr=savloc; /* retain labels */ while(cptr < lo /* ** statement parser ** ** called whenever syntax requires a statement ** this routine performs that statement ** ander ** ** called whenever syntax requires a semicolon */ ns() { if(match(";")==0) error("no semicolon"); else errflag= POP D CALL CCPINT JMP CC71 CC70: JMP CC59 CC71: JMP CC72 CC69: LXI H,20 DAD SP XCHG;; LXI H,0 CALL CCPINT  {dogoto(); lastst=STGOTO;} else if(dolabel()) ; #endif /* STGOTO */ else if(amatch("return",6)) {doretu(amatch("while",5)) {dowhile();lastst=STWHILE;} #ifdef STDO else if(amatch("do",2)) {dodo();lastst=STDO;} #endifcptr) { cptr2=nextsym(cptr); if(cptr[IDENT] == LABEL) { while(cptr < cptr2) *savloc++ = *cptr++; }  returns a number telling which one */ statement() { if ((ch==0) & (eof)) return; else if(amatch("char",4)) {declloc(CC0; } compound() { int savcsp; char *savloc; savcsp=csp; savloc=locptr; declared=0; /* may now declare l CC72: LXI H,1 DAD SP XCHG;; LXI H,3 DAD SP CALL CCPINT LXI H,11 DAD SP PUSH H LXI H,14 DAD SP MOV D,H rn();ns();lastst=STRETURN;} else if(amatch("break",5)) {dobreak();ns();lastst=STBREAK;} else if(amatch("continue",8) /* STDO */ #ifdef STFOR else if(amatch("for",3)) {dofor();lastst=STFOR;} #endif /* STFOR */ #ifdef STSWITCH else cptr=cptr2; } #endif /* STGOTO */ locptr=savloc; /* delete local symbols */ declared = -1; HAR);ns();} else if(amatch("int",3)) {declloc(CINT);ns();} else { if(declared >= 0) { #ifdef STGOTO if(ncocal variables */ ++ncmp; /* new level open */ while (match("}")==0) if(eof) { error("no final }");  MOV E,L CALL CCGINT INX H CALL CCPINT DCX H CALL CCGCHAR POP D MOV A,L STAX D LXI H,26 DAD SP PUSH H LX){docont();ns();lastst=STCONT;} else if(match(";")) errflag=0; else if(match("#asm")) {doasm();lastst=S0 /* may not declare variables */ } doif() { int flab1,flab2; flab1=getlabel(); /* get label for false branch */ t */ #ifdef STFOR dofor() { int wq[4], lab1, lab2; addwhile(wq); lab1=getlabel(); lab2=getlabel(); needtoken(" test(wq[WQEXIT], YES); /* see if true */ statement(); /* if so, do a statement */ jump(wq[WQLOOP]); /* te(','); outdec(*swptr++); /* case value */ nl(); } defstorage(CINT>>2); outdec(0); nl(); if(swd /* and do "else" clause */ postlabel(flab2); /* print true label */ } doexpr() { int const, val; char *before,act, swdef, *swnex, *swptr; swact=swactive; swdef=swdefault; swnex=swptr=swnext; addwhile(wq); *(wqptr + WQLOOP -est(flab1, YES); /* get expression, and branch false */ statement(); /* if true, do a statement */ if (amatch("else",("); if(match(";")==0) { doexpr(); /* expr 1 */ ns(); } postlabel(lab1); if(match(";")==0) { loop to label */ postlabel(wq[WQEXIT]); /* exit label */ delwhile(); /* delete queue entry */ } #ifdef efault) jump(swdefault); postlabel(wq[WQEXIT]); delwhile(); swnext=swnex; swdefault=swdef; swactive=swact; }  *start; while(1) { setstage(&before, &start); expression(&const, &val); clearstage(before, start); if(ch WQSIZ) = 0; needtoken("("); doexpr(); /* evaluate switch expression */ needtoken(")"); swdefault=0; swactiv4)==0) { /* if...else ? */ /* simple "if"...print false label */ postlabel(flab1); return; /* and ex test(wq[WQEXIT], NO); /* expr 2 */ ns(); } jump(lab2); postlabel(wq[WQLOOP]); if(match(")")==0) { dSTDO dodo() { int wq[4], top; addwhile(wq); postlabel(top=getlabel()); statement(); needtoken("while"); postl docase() { if(swactive==0) error("not in switch"); if(swnext > swend) { error("too many cases"); return;  != ',') break; bump(1); } } dowhile() { /* ** patched per DDJ */ int wq[4]; /* allocae=1; jump(endlab=getlabel()); statement(); /* cases, etc. */ jump(wq[WQEXIT]); postlabel(endlab); sw(); it */ } flab2=getlabel(); #ifdef STGOTO if((lastst != STRETURN)&(lastst != STGOTO)) jump(flab2); #else /* STGOTO oexpr(); /* expr 3 */ needtoken(")"); } jump(lab1); postlabel(lab2); statement(); jump(wq[WQLOOabel(wq[WQLOOP]); test(wq[WQEXIT], YES); jump(top); postlabel(wq[WQEXIT]); delwhile(); ns(); } #endif /* STDO} postlabel(*swnext++ = getlabel()); constexpr(swnext++); needtoken(":"); } dodefault() { if(swactive) { te local queue */ addwhile(wq); /* add entry to queue for "break" */ postlabel(wq[WQLOOP]); /* loop label */  /* match cases */ while(swptr < swnext) { defstorage(CINT>>2); printlabel(*swptr++); /* case label */ outby*/ if(lastst != STRETURN) jump(flab2); #endif /* STGOTO */ postlabel(flab1); /* print false label */ statement(); P]); postlabel(wq[WQEXIT]); delwhile(); } #endif /* STFOR */ #ifdef STSWITCH doswitch() { int wq[4], endlab, sw1 if(swdefault) error("multiple defaults"); } else error("not in switch"); needtoken(":"); postlabel(swdefault=getla FPUTS POP B POP B XCHG;; LXI H,-1 CALL CCEQ MOV A,H ORA L JZ CC123 CALL XOUT CC123: RET LOUT: LXI H,4 bel */ } docont() { int *ptr; ptr = wqptr; while (1) { if ((ptr=readwhile(ptr))==0) return; /* no loops opeND, MACNBR, 0)) #else /* HASH */ if(findmac(lptr)) #endif /* HASH */ skiplevel=iflevel; continue; cptr[IDENT]!=LABEL) error("not a label"); } else cptr=addsym(ssname, LABEL, LABEL, getlabel(), &locptr, LABEL); retur ifline() { while(1) { inline(); if(eof) return; if(match("#ifdef")) { ++iflevel; if(skiplevel)bel()); } #endif /* STSWITCH */ #ifdef STGOTO dogoto() { if(nogo > 0) error("not allowed with block-locals"); else DAD SP CALL CCGINT PUSH H LXI H,4 DAD SP CALL CCGINT PUSH H CALL SOUT POP B POP B LXI H,13 PUSH H LXI Hn */ if (ptr[WQLOOP]) break; } modstk((ptr[WQSP]), NO); /* clean up stk ptr */ jump(ptr[WQLOOP]);  } if(match("#else")) { if(iflevel) { if(skiplevel==iflevel) skiplevel=0; else if(skiplevel==0)n (getint(cptr+OFFSET, OFFSIZE)); } #endif /* STGOTO */ doreturn() { if(endst()==0) { doexpr(); modstk(0, Y continue; blanks(); #ifdef HASH if(search(lptr, macn, NAMESIZE+2, MACNEND, MACNBR, 0)==0) #else /* HASH */  noloc = 1; if(symname(ssname, YES)) jump(addlabel()); else error("bad label"); ns(); } dolabel() { char *save,4 DAD SP CALL CCGINT PUSH H CALL COUT POP B POP B RET XOUT: LXI H,CC125+0 PUSH H LXI H,2 PUSH H CALL F /* jump to loop label */ } doasm() { ccode=0; /* mark mode as "asm" */ while (1) { in skiplevel=iflevel; } else noiferr(); continue; } if(match("#endif")) { if(iflevel) {ES); } else modstk(0, NO); ret(); } dobreak() { int *ptr; if ((ptr=readwhile(wqptr))==0) return; /* no l if(findmac(lptr)==0) #endif /* HASH */ skiplevel=iflevel; continue; } if(match("#ifndef")) {lptr; blanks(); savelptr=lptr; if(symname(ssname, YES)) { if(gch()==':') { postlabel(addlabel()); rePUTS POP B POP B LXI H,7 PUSH H CALL ABORT POP B RET CC125: DB 111,117,116,112,117,116,32,101,114,114 DB 111,11line(); if (match("#endasm")) break; if(eof)break; lout(line, output); } kill(); ccode=1; }  if(skiplevel==iflevel) skiplevel=0; --iflevel; } else noiferr(); continue; } oops open */ modstk((ptr[WQSP]), NO); /* clean up stk ptr */ jump(ptr[WQEXIT]); /* jump to exit la ++iflevel; if(skiplevel) continue; blanks(); #ifdef HASH if(search(lptr, macn, NAMESIZE+2, MACNEturn 1; } else bump(savelptr-lptr); } return 0; } addlabel() { if(cptr=findloc(ssname)) { if(4,13,0 MAIN: PUSH B PUSH B LXI H,0 DAD SP XCHG;; LXI H,128 CALL CCPINT LXI H,2 DAD SP XCHG;; LXI H,CC126+2  if(skiplevel) continue; if(listfp) { if(listfp==output) cout(';', output); lout(line, listfp); } ame)) while(c=macq[k++]) keepch(c); #endif /* HASH */ else { k=0; while(c=msname[k++]) keepch(c); *')&(nch=='/'))==0) { if(ch) bump(1); else { ifline(); if(eof) break; } r *sname, *buf, *end; int len, max, off; { cptr=cptr2=buf+((hash(sname)%(max-1))*len); while(*cptr != 0) { if(astreq if(ch==0) { error("no quote"); break; } keepch(gch()); } gch(urn; } } putint(macptr, cptr+NAMESIZE, 2); #else /* HASH */ while(putmac(msname[k++])); #endif /* HASH */  if(ch==0) continue; break; } } keepch(c) char c; { if(pptr=LINEMAX) error("line too long"); keepch(0); line=pline; b } bump(2); } else if(an(ch)) { k=0; while(an(ch)) { if(k= end) cptr=buf; if(cptr == cptr2) return (cptr=0); } ); keepch('"'); } else if(ch==39) { keepch(39); gch(); while((ch!=39)|((*(lptr-1)==92)&( while(white()) gch(); while(putmac(gch())); if(macptr>=MACMAX) { error("macro string queue full"); abort(ERRCODE); { int k; char c; if(ccode) { line=mline; ifline(); if(eof) return; } else { line=pline; ump(0); } noiferr() { error("no matching #if..."); errflag=0; } addmac() { int k; if(symname(msname, NO) gch(); } msname[k]=0; #ifdef HASH if(search(msname, macn, NAMESIZE+2, MACNEND, MACNBR, 0)) {  return 0; } hash(sname) char *sname; { int i, c; i=0; while(c = *sname++) i=(i<<1)+c; return i; } #els*(lptr-2)!=92))) { if(ch==0) { error("no apostrophe"); break; } keepch(gch()) } } putmac(c) char c; { macq[macptr]=c; if(macptr= ' ') outbyte(*ptr++); } outbyte(c) char c; { if(stagenext) { if(stagenex{ int k; k=line+2; while(k++ <= lptr) cout(' ', fp); lout("/\\", fp); sout("**** ", fp); lout(msg, fp); } stre outbyte('-'); } while (k>=1) { c=number/k + '0'; if ((c!='0')|(k==1)|(zs)) { zs=1; outbyte(c); g[]; { if(errflag) return; else errflag=1; lout(line, stderr); errout(msg, stderr); #ifdef C80 if(alarm) putc(7,  #endif /* HASH */ setstage(before, start) int *before, *start; { if((*before=stagenext)==0) stagenext=stage; *start=s error\n", stderr); abort(ERRCODE); } #ifdef C80 abort(err) int err; { exit(); /* exit to CP/M */ } #endif /* t==stagelast) { error("staging buffer overflow"); return 0; } else *stagenext++ = c; } else coq(str1,str2) char str1[],str2[]; { /* check for string equality over whole string */ int k; k=0; while (str2[k]) {  } number=number%k; k=k/10; } } ol(ptr) char ptr[]; { ot(ptr); nl(); } ot(ptr) char ptrstderr); #else /* C80 */ if(alarm) fputc(7, stderr); #endif /* C80 */ /* ** while reading from stderr is not stricttagenext; } clearstage(before, start) char *before, *start; { *stagenext=0; if(stagenext=before) return; if(startC80 */ #ifdef C80 fputs(string, fd) char *string; int fd; { char c; while ((c = *string++) != NULL) { if (putc(c,ut(c,output); return c; } cout(c, fd) char c; int fd; { #ifdef C80 if(putc(c, fd)==EOF) xout(); #else /* C80 */  if ((str1[k])!=(str2[k])) return 0; ++k; } return k; } astreq(str1,str2,len) char str1[],str2[];int len;[]; { #ifdef TAB tab(); #else /* TAB */ outbyte(' '); #endif /* TAB */ outstr(ptr); } outstr(ptr) char ptrly legal, ** stderr will always be assigned to the user's terminal ** (CON: on CP/M systems [should be /dev/tty on Unix]).) { #ifdef OPTIMIZE peephole(start); #else /* OPTIMIZE */ sout(start, output); #endif /* OPTIMIZE */ }  fd) == EOF) return EOF; } return 0; } #endif /* C80 */ nl() { outbyte('\n'); } tab() { outbyte(TAB); if(fputc(c, fd)==EOF) xout(); #endif /* C80 */ } sout(string, fd) char *string; int fd; { if(fputs(string, fd)==E { /* check for string equality over first 'len' characters */ int k; k=0; while (k0) errout(msg, listfp); } errout(msg, fp) char msg[]; int fp; } outdec(number) int number; { int k,zs; char c; zs = 0; k=10000; if (number<0) { number=(-number);  } col() { #ifdef COL outbyte(':'); #else /* COL */ outbyte(' '); #endif /* COL */ } error(msg) char ms4 [k]))break; /* ** must detect end of symbol table names terminated by ** symbol length in binary */ if(.def" /* ** external references in part 1 */ extern char #ifdef HASH *macn, #endif /* HASH */ #ifdef OPTIMIZE o } nt expression ** lval[5] - true if secondary register altered ** lval[6] - function address of highest/last binary operator *0; blanks(); while(1) { opsize=0; while(*list > ' ') op[opsize++] = *list++; op[opsize]=0; if(opsize=sIRSTFREE: LHLD MEMRY$ RET MEMRY$:DW 0 ; This assembly routine allows CPM calls from Small C. ; ; cpm(cpmfunction#, istr1[k] < ' ') break; if(str2[k] < ' ') break; ++k; } if (an(str1[k]))return 0; if (an(str2[k]))return 0; ptimize, #endif /* OPTIMIZE */ m80flg, *stagenext, ssname[NAMESIZE]; extern int beglab, csp, output; /* ** eCR B JM ENDNAM DCR C JZ RDERR LDAX D CPI ' ' JNZ CPY1 ENDNAM: MVI M,0 POP H MOV C,L ; Restore reg C RET RDER* lval[7] - stage address of "oper 0" code, else 0 */ /* ** skim over terms adjoining || and && operators */ skim(opstr, treq(lptr, op)) if((*(lptr+opsize) != '=')& (*(lptr+opsize) != *(lptr+opsize-1))) return 1; if(*nputparameter) ; ; Since this function returns whatever is returned in register ; it cannot be used to call ReturnVersionNumb return k; } match(lit) char *lit; { int k; blanks(); if (k=streq(lptr,lit)) { bump(k); return 1; xternal references in part 2 */ extern int #ifdef HASH search(), #else /* HASH */ findmac(), #endif /* HASH */ R: LXI D,RDEMSG ; Error message MVI C,CPMSTR CALL BDOS ; Make sure it gets put on the terminal JMP EXIT RDOPN: DB 'r',0 testfunc, dropval, endval, heir, lval) char *opstr; #ifdef FULLC int (*testfunc)(), dropval, endval, (*heir)(), lval[];list) { ++list; ++opindex; } else return 0; } } blanks() { while(1) { while(ch) {  /* ** lval[0] - symbol table address, else 0 for constant ** lval[1] - type of indirect obj to fetch, else 0 for static **  } return 0; } amatch(lit,len) char *lit;int len; { int k; blanks(); if (k=astreq(lptr,lit,len)) { bump( clearstage(), col(), cout(), getint(), getlabel(), nl(), numeric(), ol(), ot(), printlabel(), lout(), outdec(),  /* ** Small-C Compiler Version 2.0 ** ** Copyright 1982 J. E. Hendrix ** ** Part 4 */ #include "stdiol.h" #include "cc { #else /* FULLC */ int testfunc, dropval, endval, heir, lval[]; { #endif /* FULLC */ int k, hits, droplab, endlab;  if(white()) gch(); else return; } if(line==mline) return; preprocess(); if(eof)break; } lval[2] - type of pointer or array, else 0 for all other ** lval[3] - true if constant expression ** lval[4] - value of constak); while(an(ch)) inbyte(); return 1; } return 0; } nextop(list) char *list; { char op[4]; opindex= outstr(), streq(); /* ** external references in part 3 */ extern int const(); #include "cc41.c" #include "cc42.c" 5  hits=0; while(1) { k=plung1(heir, lval); if(nextop(opstr)) { bump(opsize); if(hits==0) { h, (*testfunc)(), exit1, lval[]; { #else /* FULLC */ dropout(k, testfunc, exit1, lval) int k, testfunc, exit1, lval[]; { #endistart; int k; setstage(&before, &start); #ifdef FULLC k= (*heir)(lval); #else /* FULLC */ k= heir(lval); #endif if(k) rvalue(lval); while(1) { if(nextop(opstr)) { bump(opsize); opindex=opindex+opoff; plung2(opits=1; droplab=getlabel(); } dropout(k, testfunc, droplab, lval); } else if(hits) { f /* FULLC */ if(k) rvalue(lval); else if(lval[3]) const(lval[4]); #ifdef FULLC (*testfunc)(exit1); /* jumps on fadropout(k, testfunc, droplab, lval); const(endval); jump(endlab=getlabel()); postlabel(droplab); con /* FULLC */ if(lval[3]) clearstage(before,0); /* load constant later */ return k; } /* ** binary plunge to lower[opindex], op2[opindex], heir, lval, lval2); } else return 0; } } /* ** unary plunge to lower level **  /* ** abs -- returns absolute value of nbr */ abs(nbr) int nbr; {if(nbr<0) return -nbr; else return nbr;} lse */ #else /* FULLC */ testfunc(exit1); /* jumps on false */ #endif /* FULLC */ } /* ** plunge to a lower level st(dropval); postlabel(endlab); lval[1]=lval[2]=lval[3]=lval[7]=0; return 0; } else return k;  level ** renamed "plung2" (original was "plunge2") to have ** first 6 chars unique for M80 assembler. */ plung2(oper, oper2renamed "plung1" (original was "plunge1") to have ** first 6 chars unique for M80 assembler. */ #ifdef FULLC plung1(heir, lv */ plunge(opstr, opoff, heir, lval) char *opstr; #ifdef FULLC int opoff, (*heir)(), lval[]; { #else /* FULLC */ i } } /* ** test for early dropout from || or && evaluations */ #ifdef FULLC dropout(k, testfunc, exit1, lval) int k, heir, lval, lval2) #ifdef FULLC int (*oper)(), (*oper2)(), (*heir)(), lval[], lval2[]; { #else /* FULLC */ int oper,al) int (*heir)(), lval[]; { #else /* FULLC */ plung1(heir, lval) int heir, lval[]; { #endif /* FULLC */ char *before, *nt opoff, heir, lval[]; { #endif /* FULLC */ int k, lval2[8]; k=plung1(heir, lval); if(nextop(opstr)==0) return k; 6  oper2, heir, lval[], lval2[]; { #endif /* FULLC */ char *before, *start; setstage(&before, &start); lval[5]=1; } else { #ifdef FULLC (*oper2)(); #else /* FULLC */ oper2(); #endif /* FULLC */ lval[6] if(dbltest(lval2,lval)) { swap(); doublereg(); if(oper==zzsub) swap(); } oper == zzadd) return (left + right); else if(oper == zzsub) return (left - right); else if(oper ==zzmult) return (lef(oper==zzadd) { /* may test other commutative operators */ csp=csp+2; clearstage(before, 0); const2(lf(oper == zzxor) return (left ^ right); else if(oper == zzand) return (left & right); else if(oper == zzeq) return (l /* flag secondary register used */ lval[7]=0; /* flag as not "... oper 0" syntax */ if(lval[3]) { /* c= oper2; /* identify the operator */ } } if(oper==zzsub) { if((lval[2]==CINT)&(lval2[2]==CINT)) {  } } } if(oper) { if(lval[3]=lval[3]&lval2[3]) { lval[4]=calc(lval[4], oper, lval2[4]); clearst * right); else if(oper == zzdiv) return (left / right); else if(oper == zzmod) return (left % right); else retuval2[4]<= right); else if(oper == zzlt) return (left < right); else if(oper == zzgt) return (leonst2(lval[4]< right); else if(oper == zzasr) return (left >> right); else if(oper == zzasl) return (left << right); else if(heir, lval2)) rvalue(lval2); if(lval2[3]) { /* constant on right side */ if(lval2[4]==0) lval[7]=start; ifc(left, oper, right) int left, oper, right; { #endif /* FULLC */ if(oper == zzor) return (left | right); else i7 oper)(), heir3(); #else /* FULLC */ int k,lval2[8], oper, heir3(); #endif /* FULLC */ k=plung1(heir3, lval); if(lvaval); } heir10(lval) int lval[]; { int heir11(); return plunge(">> <<", 9, heir11, lval); } heir11(lval) inr5(); return skim("&&", ne0, 0, 1, heir5, lval); } heir5(lval) int lval[]; { int heir6(); return plunge("|", 0,  heir13(lval) int lval[]; { int k; char *ptr; if(match("++")) { /* ++lval */ if(heir13(lval)=(lval[1]) { if(oper) { push(); rvalue(lval); } plung2(oper, oper, heir1, lval, lval2); if(opBUFFER DAD D SHLD CHP ; } ; } GTCIF2: LHLD IP ; ip[UNUSED]--; LXI D,UNUSED DAD D MOV E,M INX H Ml[3]) const(lval[4]); if(match("|=")) oper= zzor; else if(match("^=")) oper= zzxor; else if(match("&=")) oper= t lval[]; { int heir12(); return plunge("+ -", 11, heir12, lval); } heir12(lval) int lval[]; { int heir13(); heir6, lval); } heir6(lval) int lval[]; { int heir7(); return plunge("^", 1, heir7, lval); } heir7(lval) int=0) { needlval(); return 0; } step(inc, lval); return 0; } else if(match("--")) { er) pop(); } else { if(oper) { rvalue(lval); plung2(oper, oper, heir1, lval, lval2); } elOV D,M DCX D MOV M,D DCX H MOV M,E LHLD CHP ; ip[NEXTP] = cp+1; INX H XCHG LHLD IP LXI B,NEXTP DAD B MOVzzand; else if(match("+=")) oper= zzadd; else if(match("-=")) oper= zzsub; else if(match("*=")) oper= zzmult; els return plunge("* / %", 13, heir13, lval); }  lval[]; { int heir8(); return plunge("&", 2, heir8, lval); } heir8(lval) int lval[]; { int heir9(); return  /* --lval */ if(heir13(lval)==0) { needlval(); return 0; } step(dec, lval); return 0; se { if(heir1(lval2)) rvalue(lval2); lval[5]=lval2[5]; } } store(lval); return 0; } heir3( M,E INX H MOV M,D LHLD CHP ; if(*cp==CTRL_Z){ MOV A,M ANI 7FH ; /* mask parity in compare */ CPI CTRLZ JNZ GTe if(match("/=")) oper= zzdiv; else if(match("%=")) oper= zzmod; else if(match(">>=")) oper= zzasr; else if(match("<<SH H CALL CPMIO POP D POP D MOV A,H ORA L JZ GTCIF3 LXI H,-1 ; return(-1); RET GTCIF3: LHLD IP ; else { plunge("== !=", 3, heir9, lval); } heir9(lval) int lval[]; { int heir10(); return plunge("<= >= < >", 5, heir10, l } else if (match("~")) { /* ~ */ if(heir13(lval)) rvalue(lval); com(); #ifdef PHASE2 lvallval) int lval[]; { int heir4(); return skim("||", eq0, 1, 0, heir4, lval); } heir4(lval) int lval[]; { int heiCIF4 LHLD UNIT ; unit[FLAG] |= EOF_FL; LXI D,FLAG DAD D MOV A,M ORI EOFFLG MOV M,A LXI H,-1 ; return(-1); RE=")) oper= zzasl; else if(match("=")) oper= 0; else return k; if(k==0) { needlval(); return 0; } ifip[UNUSED] = BUFSIZ; LXI D,UNUSED DAD D LXI D,BUFSIZ MOV M,E INX H MOV M,D LHLD IP ; cp = &ip[BUFFER]; LXI D,8 [4] = ~lval[4]; #endif /* PHASE2 */ return 0; } else if (match("!")) { /* ! */ if(heir13(lval) if(match("[")) { /* [subscript] */ if(ptr==0) { error("can't subscript"); junlval[2]>>2); return 0; } else if(match("--")) { /* lval-- */ if(k==0) { needlval() k=lval[0]=lval[3]=0; } else return k; } } if(ptr==0) return k; if(ptr[IDENT]==FUNCTION) {  return 1; } else if(match("&")) { /* unary & */ if(heir13(lval)==0) { error("illegal addr else const2(lval2[4]); zzadd(); } } else { if(p) rvalue(lval); lneg(); #ifdef PHASE2 lval[4] = !lval[4]; #endif /* PHASE2 */ return 0; } else if (k(); needtoken("]"); return 0; } else if(ptr[IDENT]==POINTER)rvalue(lval); el; return 0; } step(dec, lval); inc(lval[2]>>2); return 0; } else return k;  address(ptr); return 0; } return k; } primary(lval) int *lval; { char *ptr; int k; if(match("(ess"); return 0; } ptr=lval[0]; lval[2]=ptr[TYPE]; if(lval[1]) return 0; /* global & non-arraytr[TYPE]==CINT) doublereg(); zzadd(); } lval[0]=lval[2]=0; lval[1]=ptr[TYPE]; kmatch("-")) { /* unary - */ if(heir13(lval)) rvalue(lval); neg(); lval[4] = -lval[4]; return 0;se if(ptr[IDENT]!=ARRAY) { error("can't subscript"); k=0; } setstage(&before, &start); } } heir14(lval) int *lval; { int k, const, val, lval2[8]; char *ptr, *before, *start; k=primary(lval); pt")) { /* (expression) */ k=heir1(lval); needtoken(")"); return k; } putint(0, lval, 8< */ address(ptr); lval[1]=ptr[TYPE]; return 0; } else { k=heir14(lval); if(match("++")) { =1; } else if(match("(")) { /* function(...) */ if(ptr==0) callfunction(0); else if( } else if(match("*")) { /* unary * */ if(heir13(lval)) rvalue(lval); if(ptr=lval[0])lval[1]=ptr lval2[3]=0; plung2(0, 0, heir1, lval2, lval2); /* lval2 deadend */ needtoken("]"); if(lval2r=lval[0]; blanks(); if((ch=='[')|(ch=='(')) { lval[5]=1; /* secondary register will be used */ while(1) {  int pointer or int array and val2 not ptr or array */ dbltest(val1,val2) int val1[], val2[]; { if( lval[1]=ptr[TYPE]; if(ptr[IDENT]==POINTER) { lval[1]=CINT; lval[2]=ptr[TYPE]; } if(pOUT MOV A,H ; if(rstdout >= 256) { ORA A JZ PUTS1 PUSH H CALL FPUTS ; return (fputs(cp, rstdout)); POP B POP B  /* push argument */ nargs=nargs+BPW; /* count args*BPW */ if (match(",")==0) break; } needtoke rvalue(lval); #ifdef FULLC (*oper)(lval[2]>>2); #else /* FULLC */ oper(lval[2]>>2); #endif /* FULLC *[1]=0; return 0; } if(constant(lval)==0) experr(); return 0; } experr() { error("invalid expression"); val1[2]!=CINT) return 0; if(val2[2]) return 0; return 1; } /* ** determine type of binary operation */ result(lvatr[IDENT]==ARRAY) { lval[2]=ptr[TYPE]; return 0; } else return 1; } if(ptr=findglb RET PUTS1: POP H ; } else { MOV A,M ; while(*cp) ORA A JZ PUTSRET MOV E,M ; putchar(*cp++); INX H PUSH H n(")"); if(streq(ptr+NAME, "CCARGC")==0) loadargc(nargs>>LBPW); if(ptr) call(ptr+NAME); else callstk(); csp=modstk(c/ pop(); store(lval); return; } else { move(); lval[5]=1; } } rv const(0); junk(); } callfunction(ptr) char *ptr; { /* symbol table entry or 0 */ int nargs, const, val; nargl, lval2) int lval[], lval2[]; { if((lval[2]!=0)&(lval2[2]!=0)) { lval[2]=0; } else if(lval2[2]) { lval[0]=(ssname)) if(ptr[IDENT]!=FUNCTION) { lval[0]=ptr; lval[1]=0; if(ptr[IDENT]!=ARRAY) { MVI C,PUTCH CALL BDOS JMP PUTS1 PUTSRET: ; return; RET ; } ; ; fputs(cp,unit) ; FPUTS: POP B POP D ; unit sp+nargs, YES); } alue(lval); #ifdef FULLC (*oper)(lval[2]>>2); #else /* FULLC */ oper(lval[2]>>2); #endif /* FULLC */ store(lval)s=0; blanks(); /* already saw open paren */ if(ptr==0) push(); /* calling HL */ while(streq(lptr,")"lval2[0]; lval[1]=lval2[1]; lval[2]=lval2[2]; } } #ifdef FULLC step(oper, lval) int (*oper)(), lval[]; {  if(ptr[IDENT]==POINTER) lval[2]=ptr[TYPE]; return 1; } address(ptr); lval[1]=lval[2]=pPOP H ; cp PUSH H PUSH D PUSH B FPUTS1: MOV A,M ; while((c=*cp++) <> NULL) { INX H ORA A JZ FPUTS3 PUSH H MOV : ; } store(lval) int lval[]; { if(lval[1]) putstk(lval); else putmem(lval); } rvalue(lval) int lval[]; dec(val); nl(); } const2(val) int val; { immed2(); outdec(val); nl(); } constant(lval) int lval[]; {  if (oper==ult) zerojump(ult0, label, lval); else if (oper==zzle) zerojump(le0, label, lval); else te), 1); } gch(); litq[litptr++]=0; return 1; } stowlit(value, size) int value, size; { if((litptr+size) >=el); return; } if(lval[7]) { /* stage address of "oper 0" code */ oper=lval[6];/* operator function address *)return 0; while (numeric(ch)) k=k*10+(inbyte()-'0'); if (minus) k=(-k); val[0]=k; return 1; } address(ptr) ch{ if ((lval[0]!=0)&(lval[1]==0)) getmem(lval); else indirect(lval); } test(label, parens) i lval=lval+3; *lval=1; /* assume it will be a constant */ if (number(++lval)) immed(); else if (pstr(lval)) immedstjump(label); } else testjump(label); clearstage(before, start); } constexpr(val) int *val; { int const;  LITMAX) { error("literal queue overflow"); abort(ERRCODE); } putint(value, litq+litptr, size); litptr=litptr+si/ if((oper==zzeq)| (oper==ule)) zerojump(eq0, label, lval); else if((oper==zzne)| (operar *ptr; { immed(); outstr(ptr+NAME); nl(); } pstr(val) int val[]; { int k; k=0; if (match("'")==0) retnt label, parens; { int lval[8]; char *before, *start; if(parens) needtoken("("); while(1) { setstage(&before,(); else if (qstr(lval)) { *(lval-1)=0; /* nope, it's a string address */ immed(); printlabel(litlab); ou char *before, *start; setstage(&before, &start); expression(&const, val); clearstage(before, 0); /* scratch generatedze; } /* ** return current literal char & bump lptr */ litchar() { int i, oct; if((ch!=92)|(nch==0)) return gch()==ugt)) zerojump(ne0, label, lval); else if (oper==zzgt) zerojump(gt0, label, lval); else if (oper==zzge) zerojump(ge0urn 0; while(ch!=39) k=(k&255)*256 + (litchar()&255); ++lptr; val[0]=k; return 1; } qstr(val) int val[]; { &start); if(heir1(lval)) rvalue(lval); if(match(",")) clearstage(before, start); else break; } if(parenstbyte('+'); } else return 0; outdec(*lval); nl(); return 1; } number(val) int val[]; { int k, minus;  code */ if(const==0) error("must be constant expression"); return const; } const(val) int val; { immed(); out; gch(); if(ch=='n') {gch(); return 13;} /* CR */ if(ch=='t') {gch(); return 9;} /* HT */ if(ch=='b') {gch(); retur, label, lval); else if (oper==uge) clearstage(lval[7],0); else if (oper==zzlt) zerojump(lt0, label, lval); else char c; if (match(quote)==0) return 0; val[0]=litptr; while (ch!='"') { if(ch==0) break; stowlit(litchar() needtoken(")"); if(lval[3]) { /* constant expression */ clearstage(before, 0); if(lval[4]) return; jump(lab k=minus=0; while(1) { if(match("+")) ; else if(match("-")) minus=1; else break; } if(numeric(ch)==0; n 8;} /* BS */ if(ch=='f') {gch(); return 12;} /* FF */ i=3; oct=0; while(((i--)>0)&(ch>='0')&(ch<='7')) oct=(oct<<3)+ macq[MACQSIZE], pline[LINESIZE], mline[LINESIZE], swq[SWTABSZ], #endif /* DYNAMIC */ *line, /* points to pe for operator on errors? */ m80flg, /* compile for M80 assembler? */ #ifdef DYNAMIC *stage, /* output staging buffx to matched operator */ opsize, /* size of operator in bytes */ swactive, /* true inside a switch */ swdefault,/* de MOV H,A RET ; ;EXCLUSIVE "OR" HL AND DE INTO HL ; CCXOR: MOV A,L SIZE]; /* static symbol name array */ int #ifdef STGOTO nogo, /* > 0 disables goto statements */ noloc, /* gch()-'0'; if(i==2) return gch(); else return oct; } line or mline */ *lptr, /* ptr to either */ *glbptr, /* ptrs to next entries */ *locptr, /* ptr to next local symber */ *symtab, /* symbol table */ *litq, /* literal pool */ #ifdef HASH *macn, /* macro name buffer */ #endifault label #, else 0 */ *swnext, /* address of next entry */ *swend, /* address of last table entry */ #ifdef DYNAM /* ** Small-C Compiler Version 2.0 ** ** Copyright 1982 J. E. Hendrix ** ** Part 1 */ #include "stdiol.h" #include "> 0 disables block locals */ #endif /* STGOTO */ /* ** the following two definitions are arrays of pointers to functions *;;RET ADDR POP D PUSH B ; ;STORE A 16-BIT INTEGER IN HL AT THE ADDRESS IN DE ; CCPol */ *stagenext,/* next addr in stage */ *stagelast,/* last addr in stage */ quote[2], /* literal string for '"' */ *cf /* HASH */ *macq, /* macro string buffer */ *pline, /* parsing buffer */ *mline, /* macro buffer */ #elseIC *wq, /* while queue */ #else /* DYNAMIC */ wq[WQTABSZ], #endif /* DYNAMIC */ #ifdef CMD_LINE argcs, /* cc.def" /* ** miscellaneous storage */ char #ifdef OPTIMIZE optimize, /* optimize output of staging buffer */ #endi* and should look like this: ** (*op)()[16], ** (*op2)()[16], ** but small-c cheats and declares an array of ints INT: PINT: MOV A,L STAX D INX D MOV A,H STAX D RET ; ;INCLUSIVptr, /* work ptrs to any char buffer */ *cptr2, *cptr3, #ifdef CMD_LINE #ifdef FULLC *argvs[MAXARGS], /* static  /* DYNAMIC */ stage[STAGESIZE], symtab[SYMTBSZ], litq[LITABSZ], #ifdef HASH macn[MACNSIZE], #endif /* HASH */ static argc */ #ifdef N_CMD_LN #ifndef FULLC argvs[MAXARGS], /* static argv (new_cmd_line && !full_c) */ #endif /* FUf /* OPTIMIZE */ alarm, /* audible alarm on errors? */ monitor, /* monitor function headers? */ pause, /* paus*/ op[16], /* function addresses of binary operators */ op2[16], /* same for unsigned operators */ opindex, /* indeE "OR" HL AND DE INTO HL ; CCOR: MOV A,L ORA E MOV L,A MOV A,H ORA D copy of argv */ #endif /* FULLC */ #endif /* CMD_LINE */ msname[NAMESIZE], /* macro symbol name array */ ssname[NAME< LLC */ #else /* N_CMD_LN */ *argvs, /* static argv (original version) */ #endif /* N_CMD_LN */ #endif /* CMD_LINE work ptr to any int buffer */ #ifdef C80 extern int fin, fout; #endif /* C80 */ #ifdef SEPARATE #ifdef LINK #ifdef PDS# for input file */ input2, /* fd # for "include" file */ output, /* fd # for output file */ files, /* non-zero zor(), point(), ret(), zzsub(), sw(), trailer(), uge(), ugt(), ule(), ult(), zzxor(); #endif /* SEPARATE */ #inc */ skiplevel,/* level at which #if... skipping started */ func1, /* true for first function */ nxtlab, /* next avwhile(), setstage(), sout(), streq(), symname(), upper(), xgets(); extern int constexpr(), expression(), number()*/ *wqptr, /* ptr to next entry */ litptr, /* ptr to next entry */ macptr, /* macro buffer index */ #ifndef  #asm CC2.R:LIBRY CC3.R:LIBRY CC4.R:LIBRY #endasm #endif /* PDS */ #endif /* LINK */ extern int addmac(), addsym()if file list specified on cmd line */ filearg, /* cur file arg index */ glbflag, /* non-zero if internal globals */ clude "cc11.c" #include "cc12.c" #include "cc13.c" #ifndef SEPARATE #include "cc21.c" #include "cc22.c" #include "cc31.c"ail label # */ litlab, /* label # assigned to literal pool */ beglab, /* beginning label -- first function */ csp, , qstr(), test(), stowlit(); extern int /* ** arithmetic routines prefaced with "zz" to keep M80 ** assembler fHASH mack, /* variable k for findmac routine */ #endif /* HASH */ pptr, /* ptr to parsing buffer */ oper, , addwhile(), amatch(), blanks(), bump(), clearstage(), col(), delwhile(), endst(), error(), findglb(), findloc()text, /* non-zero to intermix c-source */ ccode, /* non-zero while parsing c-code */ /* zero when passing  #include "cc32.c" #include "cc33.c" #include "cc41.c" #include "cc42.c" #endif /* SEPARATE */ cc22.c" #include "cc31.c" /* compiler relative stk ptr */ argstk, /* function arg sp */ argtop, ncmp, /* # open compound statements */rom generating error msgs when this is compiled */ zzadd(), zzand(), zzasl(), zzasr(), defstora(), zzdiv(), zzeq() /* address of binary operator function */ ch, /* current character of line being scanned */ nch, /* next char, gch(), getint(), getlabel(), illname(), inbyte(), inline(), junk(), kill(), lout(), match(), multidef(), needtassembly code */ listfp, /* file pointer to list device */ lastst, /* last executed statement type */ *iptr; /*  MOV A,H ORA L JNZ $+6 MVI L,1 RET LXI H,0 RET ;  errflag, /* non-zero after 1st error in statement */ eof, /* set non-zero on final input eof */ input, /* fd , entry(), external(), zzge(), zzgt(), header(), jump(), zzle(), zzlt(), zzmod(), modstk(), zzmult(), zzne(), zacter of line being scanned */ declared, /* # of local bytes declared, else -1 when done */ iflevel, /* #if... nest leveloken(), nextsym(), nl(), numeric(), outbyte(), outdec(), postlabel(), preprocess(), printlabel(), putint(), read=  ; EXECUTE "SWITCH" STATEMENT ; ; HL = SWITCH VALUE ; (SP) -> SWITCH TABLE ; DW pop(), push(), putmem(), putstk(), ret(), smartpop(), zzsub(), swap(), swapstk(), testjump(), uge(), ugt(), ule(rn int /* ** arithmetic routines prefaced with "zz" to keep M80 ** assembler from generating error msgs when this is corm, *glbptr, *line, *lptr, *cptr, *cptr2, *cptr3, *locptr, msname[NAMESIZE], optimize, pause, quote[2], *stagelast, *staint ch, csp, litlab, litptr, nch, op[16], op2[16], oper, opindex, opsize; /* ** external references in part 2  /* ** Small-C Compiler Version 2.0 ** ** Copyright 1982 J. E. Hendrix ** ** Part 2 */ #include "stdiol.h" #include "ccADDR1, VALUE1 ; DW ADDR2, VALUE2 ; ... ; DW 0 ; [JMP default]), ult(), ult0(), zzxor(), zerojump(); #include "cc31.c" #include "cc32.c" #include "cc33.c" mpiled */ zzadd(), zzand(), zzasl(), zzasr(), call(), callstk(), com(), dec(), zzdiv(), doublereg(), zzeq(), genext; extern int #ifdef DYNAMIC *wq, #else /* DYNAMIC */ wq[WQTABSZ], #endif /* DYNAMIC */ #ifndef HASH  */ extern int addsym(), blanks(), bump(), clearstage(), endst(), error(), findglb(), findloc(), gch(), getlabel(.def" /* ** external references in part 1 */ extern char #ifdef DYNAMIC *symtab, *stage, #ifdef HASH *macn, # /* ** Small-C Compiler Version 2.0 ** ** Copyright 1982 J. E. Hendrix ** ** Part 3 */ #include "stdiol.h" #include "cc0 DAD SP XCHG;; LXI H,1 CALL CCPINT LXI H,8 DAD SP MOV D,H MOV E,L CALL CCGINT INX H CALL CCPINT JMP CC8eq0(), zzge(), ge0(), getloc(), getmem(), zzgt(), gt0(), immed(), immed2(), inc(), indirect(), jump(), zzle(),mack, #endif /* HASH */ ccode, ch, csp, eof, errflag, iflevel, input, input2, listfp, macptr, nch, nxtlab, ), inbyte(), junk(), match(), needlval(), needtoken(), nextop(), nl(), numeric(), outbyte(), outdec(), outstr()endif /* HASH */ *macq, *pline, *mline, #else /* DYNAMIC */ symtab[SYMTBSZ], stage[STAGESIZE], #ifdef HASH .def" /* ** external references in part 1 */ extern char #ifdef DYNAMIC *stage, *litq, #else /* DYNAMIC */ stag CC7: LXI H,0 DAD SP XCHG;; LXI H,0 CALL CCPINT CC8: LXI H,2 DAD SP PUSH H LXI H,10 DAD SP CALL CCGINT  le0(), lneg(), loadargc(), zzlt(), lt0(), zzmod(), modstk(), move(), zzmult(), zzne(), ne0(), neg(), zzor(),  op[16], opindex, opsize, output, pptr, skiplevel, *wqptr; extern int openin(); /* ** external references in, postlabel(), printlabel(), putint(), setstage(), streq(), symname(); /* ** external references in part 4 */ exte macn[MACNSIZE], #endif /* HASH */ macq[MACQSIZE], pline[LINESIZE], mline[LINESIZE], #endif /* DYNAMIC */ alae[STAGESIZE], litq[LITABSZ], #endif /* DYNAMIC */ *glbptr, *lptr, ssname[NAMESIZE], quote[2], *stagenext; extern  PUSH H LXI H,10 DAD SP CALL CCGINT PUSH H CALL UTOI POP B POP B POP D CALL CCPINT XRA A ORA H JP CC9 >  part 4 */ #ifdef OPTIMIZE extern int peephole(); #endif /* OPTIMIZE */ #include "cc21.c" #include "cc22.c"  to use as input. The question will be repeated each time a name is supplied, allowing the user to create an output file consr generated by the compiler for it internal labels (which will typically be "ccXXXXX", where XXXXX is a decimal number increae since the "stdio.h" I/O header file contains unparsable lines for the small compiler, and the line defining NULL is the P D DAD D PUSH H LXI H,9 DAD SP CALL CCGINT XCHG;; LXI H,10 CALL CCDIV XCHG;; LXI D,48 DAD D POP D MOViler and the UNIX linker to create the runnable file "a.out". This file may be renamed as needed and used. No other files areHG;; LXI H,3 DAD SP CALL CCGINT CALL CCNEG CALL CCPINT JMP CC19 CC18: CC20: LXI H,5 DAD SP CALL CCGINT XCHisting of many separate input files (it behaves as if the user had appended them together and submitted only the one file). Asing with each label). This option allows modules to be compiled separately and later appended on the source level without geonly line of "stdio.h" needed by the compiler). -change the line of code #define eol 10 to #define eol 13 (this i A,L STAX D LXI H,7 DAD SP PUSH H LXI H,9 DAD SP CALL CCGINT XCHG;; LXI H,10 CALL CCDIV POP D CALL CCPIN needed. In order to create a compiler for a new machine, the user will need to compile the compiler into the language of the G;; LXI H,3 DAD SP CALL CCGINT DAD D CALL CCGCHAR MOV A,H ORA L JZ CC21 LXI H,3 DAD SP MOV D,H MOV E,L  null line response ends the compilation process. COMPILING THE COMPILER The power of the compiler lies in the fact itnerating multi-defined labels. Output filename? This question gets from the user the name of the file to be created. A s done since my 8080 system uses for the end of line character, and UNIX uses the "newline" character). (2) Invoke thT MOV A,H ORA L JNZ CC24 JMP CC23 CC24: JMP CC22 CC23: LXI H,3 DAD SP CALL CCGINT MOV A,H ORA L JZ CC25 destination processor. The procedure currently used to create the compiler for my 8080 system is as follows: (1) Edit the f CALL CCGINT INX H CALL CCPINT JMP CC20 CC21: CC19: CC17: CC22: LXI H,3 DAD SP CALL CCGINT MOV A,H ORA L J can compile itself. This allows a user to "bootstrap" the compiler onto a new machine without excessive recoding. To compilnull line sends output to the user's terminal. Input filename? This question gets from the user the name of the C modulee compiler (by typing "a.out" or whatever other name it was given. (3) Answer the questions by the compiler to use the file It is to be considered a temporary measure. Starting number for labels? This lets the user supply the first label numbeile C80.c to modify two lines of code: -change the line of code #include to #define NULL 0 (this is donZ CC23 LXI H,5 DAD SP CALL CCGINT PUSH H LXI H,5 DAD SP MOV D,H MOV E,L CALL CCGINT DCX H CALL CCPINT POe the compiler under the UNIX operating system, the appropriate command is: % cc C80.c -lS which will invoke the UNIX C-comp?  C80.c as input and to produce the file C80.I80 as output. (4) Append the files C80.I80 and C80LIB.I80 (the code for the en-bit registers. In the 8080 these are the HL register pair (the primary register to the compiler) and the DE register pairof the compiler. Routines used by the compiler to produce code are kept short and are commented. Changing this compiler to prt a wish-list. Time will be spent only when it becomes available. Any volunteer help in any of these areas would be appreciare a few symbol names within the compiler which are not unique until the 7th character and which have "upper-case twins". Th(3) Assignment operators (+=, &=, etc.) will be added. (4) Missing unary and binary operators and statements will be added.  compiler and the code for the runtime library, respectively). (5) Assemble the combined file using some 8080 assembler.  (the secondary register). (3) An assembler (or cross-assembler). Since the compiler is just now on its feet and subjectoduce code for any other machine is a matter of changing only these few routines, and does not entail digging around through tated. Questions should be directed to Ron Cain here at SRI either at extension 3860 or at CAIN@SRI-KL. $ ese discourage the use of the KL-10's MACN80 since it folds lower-case to upper case and does not recognize 8-character names.(5) The expression parser will create intermediate tree-structures of the expressions and will walk through them before gene (6) Execute the created run file. Currently, the 8080 assembler used must possess the abilities to handle symbol names uni to feedback from users, it is expected many changes will be made to it. Already planned changes (in order of expected additiohe internals of the program. I would expect the change to another machine could be made in an afternoon providing the target CGCHAR POP D MOV A,L STAX D MOV A,H ORA L JZ CC61 LXI H,11 DAD SP CALL CCGCHAR XCHG;; LXI H,37 CALL CCNE It may be used, however, if the user is aware of these limitations and chooses symbol names within these restrictions. rating any code. This will allow some optimization and will allow the function arguments to be passed on the stack in the sque to 8 characters and to recognize lower-case symbol names as unique from their upper-case equivalent. This is due to the fn) are: (1) Constants will be pre-evaluated by the compiler. Something like x=1+2*3 will become x=7 prior to generating machine had the following attributes: (1) A stack, preferably running backwards as items are pushed onto it. (2) Two sixte MOV A,H ORA L JZ CC62 LXI H,11 DAD SP CALL CCGCHAR PUSH H LXI H,1 PUSH H CALL COUT POP B POP B JMP CC THE FUTURE OF THE COMPILER That part of the compiler which produces code for the 8080 is all together in the final section ame sequence as UNIX. (6) A peep-hole optimizer will be added to improve the generated code. Many of these things represenact the compiler recognizes 8-character names and passes all static variable and function names intact to the assembler. There any code. (2) Structures will be added. This is one of the powers of C. Its omission has always been considered temporary. @ 60 CC62: LXI H,14 DAD SP CALL CCGINT CALL CCGCHAR XCHG;; LXI H,37 CALL CCEQ MOV A,H ORA L JZ CC63 LXI H,1C compiler in a couple of years. Enjoy!! some new library functions. See the SmallC.doc file on the disk for the features of the original version and SmallC2.doc fil and is configurable to systems with different memory capacities by deselecting some of the features. II. Features Small-DISK #17 SMALL C VERSION 2 Contributed by Bill Randle SMC.COM SMALLC2.DOC CC??.C . . This entire disk containL CCPINT LXI H,11 DAD SP CALL CCGCHAR XCHG;; LXI H,100 CALL CCEQ MOV A,H ORA L JZ CC74 LXI H,26 DAD SP C4 DAD SP MOV D,H MOV E,L CALL CCGINT INX H CALL CCPINT DCX H CALL CCGCHAR PUSH H LXI H,1 PUSH H CALL COUCALL CCGINT DAD D POP D CALL CCPINT JMP CC72 CC71: JMP CC60 CC72: JMP CC73 CC70: LXI H,20 DAD SP XCHG;; Le for the extensions contained in this version. Notice at the end of the SmallC.doc file are some suggestions by Ron Cain on eC version 2 has all of the features of the version 1 compiler, with the following additions: 1. Expressions "&&" s the substantially expanded version of Ron Cain's Small C. The additions to the language are substantial and include work botALL CCGINT PUSH H LXI H,5 DAD SP PUSH H LXI H,7 PUSH H CALL ITOD POP B POP B POP B JMP CC75 CC74: LXI HT POP B POP B JMP CC60 CC63: LXI H,12 DAD SP XCHG;; LXI H,14 DAD SP CALL CCGINT CALL CCPINT LXI H,12 DAXI H,0 CALL CCPINT CC73: LXI H,1 DAD SP XCHG;; LXI H,3 DAD SP CALL CCPINT LXI H,11 DAD SP PUSH H LXI H,14xtensions to SmallC. There are still some to go (Structures...) so if you want to try your hand feel free to bang at it a litt(logical 'and') "||" (logical 'or') "|=" "^=" "&=" "+=" "-=" "*="h by J.E. Hendrix who released this version to the public domain via Dr Dobbs, and by Bill Randle, a Big Board user in Bend, O SMALL-C VERSION 2.02 USERS NOTES I. Introduction Small-C version 2 is an extension of the version 1 compiler, wD SP CALL CCGINT CALL CCGCHAR XCHG;; LXI H,45 CALL CCEQ MOV A,H ORA L JZ CC64 LXI H,10 DAD SP XCHG;; LXI DAD SP MOV D,H MOV E,L CALL CCGINT INX H CALL CCPINT DCX H CALL CCGCHAR POP D MOV A,L STAX D LXI H,26 le. Then pass it back and perhaps someone else will continue on where you leave off. Who knows, maybe we'll have a full-blown  "/=" "%=" ">>=" "<<=" 2. Program Control for (expr1 ; expr2 ; expr3) statemenregon who added such important features as I/O redirection on STDIN and STDOUT, separate compilation of version 2 modules and ritten by J.E. Hendrix and placed in the public domain. The Small-C compiler supports a subset of the C programming languageBIG BOARD USERS DISK FROM: MICRO CORNUCOPIA THE SINGLE BOARD SYSTEMS JOURNAL PO BOX 223 BEND, OREGON 97709 BIG BOARD  DAD SP PUSH H LXI H,18 DAD SP MOV D,H MOV E,L CALL CCGINT DCX H DCX H CALL CCPINT CALL CCGINT POP D CALA t; do statement while (expression); switch (expression) { case constant-expr: default: ut of the compiler must then be run through an assembler and linker or loader. Using M80 and the above example, it would looke, e.g.: smc -c file.c >b:file.mac The following compiler switches are available: -a signal alarm  The I/O and runtime library supports the following functions: cpm(cpm_function#, input_parameter) exit() , below). III. Using the Compiler One of the first lines in your program should include the I/O library by using the "#in the file "stdioa.h" should be included instead of the file "stdiol.h". The first few lines of the C program, then would look } goto label; label: 3. External Declarations extern type name...; 4. Preprocessor  like: m80 =file.mac l80 iolib,file,call,file/n/e The file 'iolib.rel' contains the I/O library and runti(bell) on error -b# bump starting label numbers by # -c generate M80 compatable code -l#  abort(error_code) fopen(name, mode) fclose(file_des) unlink(name) getc(file_des) clude" command: #include "stdiol.h" If you are using the "printf" function, the C-library needs to be included a like: #include "stdioa.h" #include "iolib.asm" #include "call.asm" To compile and run would reqCommands #ifdef name #endif (note: #ifdef's may be nested) 5. Initializers Initializersme support. The file 'call.rel' contains the compiler library. If the "printf" function is being used, the C-library must a list device file descriptor (0-4) -m monitor. print function name as it's compiled -p pause on erro fgetc(file_des) getchar() gets(string) fgets(string, length, file_des) putc(char, file_s well: #include "libl.h" When command line processing is selected (the default), the compiler is invoked with a commanduire something similar to: smc file.c >b:file.asm asm file.xyz If you are using the C library routines -  are accepted for global declarations only: type name = {init_list}; 6. I/O Version 2 supports stdilso be linked: l80 iolib,file,call,lib,file/n/e IIIa. Using the Compiler With ASM When using the ASM assembler, the I/r, waiting for keyboard input Case is not significant and is internally converted to upper case for comparisons. The outpdes) fputc(char, file_des) putchar(char) puts(string) fputs(string, file_des) lddr( like: smc [switches] [file...] The output of the compiler is sent to standard out and can be redirected to a filsuch as printf - you want to append the contents of libasm.c onto the END of the source file. IV. I/O and Runtime Library n, stdout, stderr and stdlst. I/O redirection is also supported for stdin and stdout (see I/O library sectionO and compiler librarys must be included in the source as include files, since no linking facility is available. In addition,B source, dest, count) ldir(source, dest, count) The functions "lddr" and "ldir" perform the Z-80 instructions LDDR ae the #include "stdiol.h" to #include "std.h". This affects the files CC1.C, CC2.C, CC3.C and CC4.C. If a linker is not avaompile itself, but is included as convenience to the developer.] The #define's for the bootstrapping compiler are in the fileLE: CC41 .C CRC = AD 2C --> FILE: STRCMP .C CRC = B0 2C --> FILE: CC13 .C CRC = 28 D7 --> FILE: CC22 . "stdiol.h". (The compiler will also accept #include or just #include stdiol.h with no delimiters.) V. Bugs ARC = 63 95 --> FILE: CC21 .C CRC = F0 C1 --> FILE: DTOI .C CRC = 54 08 --> FILE: CC12 .C CRC = 52 4D --nd LDIR respectively. The function "fgets" keeps the terminating linefeed as part of the string, the other functions should bilable and the compiler is to be compiled as a single entity, comment out the #define SEPERATE line in CC.DEF.  "cc.def" and is currently setup to compile using the Small-C compiler itself. The file "cc80.def" is a cc.def file for compilC CRC = 62 5E --> FILE: UTOI .C CRC = 82 7D --> FILE: STDIOA .H CRC = 34 B9 --> FILE: CC4 .C CRC = 28 ll of the bugs that I am aware of have been fixed. This includes the while statement fixes that were submitted to Dr. Dobbs an> FILE: ITOD .C CRC = 9E B7 --> FILE: ITOU .C CRC = FC A6 --> FILE: ITOX .C CRC = 5A 83 --> FILE: LEFT ehave as you would expect them to. The names "stdin", "stdout", "stderr" or "stdlist" can be substituted for "file_des" in an PUSH H LXI H,10 DAD SP CALL CCGINT CALL CCGCHAR XCHG;; LXI H,102 CALL CCLE POP D CALL CCAND MOV A,H ORAing with C80; "smcc.def" is the cc.def file for compiling with Small-C. The files MAKE.SUB and MAKES.SUB show the compiler sw02 --> FILE: XTOI .C CRC = A1 87 --> FILE: CC31 .C CRC = F2 68 --> FILE: CC32 .C CRC = C4 0C --> FILE: d the optimizer bug. VI. Compiling The Compiler There are #ifdef's in the code to allow bootstrapping a version of the S .C CRC = DF 66 --> FILE: OUT .C CRC = C4 80 --> FILE: LIBASM .C CRC = 00 A4 --> FILE: CC42 .C CRC =y of the above functions. If standard I/O has been redirected, the appropriate file will be read from or written to. "Stderr" --> FILE: CRC .COM CRC = B2 07 --> FILE: D .COM CRC = 6A D7 --> FILE: IOLIB .ASM CRC = C3 C0 --> FILE: Sitches required for C80 and Small-C, respectively. Another change that needs to be made when compiling with C80 is to chang CC33 .C CRC = E1 76 --> FILE: CC1 .C CRC = 9F A9 --> FILE: CC3 .C CRC = B8 76 --> FILE: CC2 .C mall-C compiler by using Software Toolworks C80 C compiler. [This should no longer be necessary as the Small-C compiler will c 64 B5 --> FILE: PRINTF .C CRC = 16 DE --> FILE: SIGN .C CRC = 53 E7 --> FILE: CC .DEF CRC = 50 99 --> FI always writes to the console. "Fgetc" is identical to "getc" and "fputc" is identical to "putc". Don't forget to #includeMALLC .DOC CRC = 65 72 --> FILE: SMC .COM CRC = 16 12 --> FILE: CALL .ASM CRC = FC EE --> FILE: CC11 .C CC  CRC = 63 3E --> FILE: 17A-DISK.DOC CRC = 0A 79 --> FILE: SMALLC2 .DOC CRC = 8D 3B --> FILE: ABS .C CRC = EB FAties into a .COM file that may be run on any machine running standard CP/M. If you know nothing about C, the documentation guage. The output of this C compiler is an assembly language program. This version of SmallC2 produces assembly code suitablehis disk and is titled HELLO.C. You may either compile this program or re-write the program yourself using a text editor. ED.); MVI H,0 RET ; ; getchar() ; GETCHAR: LHLD RSTDIN ; if(rdstdin >= 128) { MOV A,H ; /* stdin has been redirected e .DOC files to compile programs so you may want to omit them from your system disk. After you have made your copy, put this dI H,13 PUSH H LXI H,4 DAD SP CALL CCGINT PUSH H CALL COUT POP B POP B RET XOUT: LXI H,CC126+0 PUSH H LXon this disk will seem incomplete to you. You will need to get a book about the language. The definitive source is: The C  for the ASM assembler that comes with CP/M. You will find this assembler on your CP/M distribution diskette. The output of ASCOM is supplied with CP/M and is suitable for program creation but it is somewhat awkward to use. If you are interested in an SAMPLE COMPILATION FOR BEGINNERS IN C This file describes step by step the creation of a program using this Small C compisk in a safe place and use your copy for compiling. Label your new copy C SYSTEM DISK and use SYSGEN to install your CP/M sysI H,2 PUSH H CALL FPUTS POP B POP B LXI H,7 PUSH H CALL ABORT POP B RET CC126: DB 111,117,116,112,117,116,32,Programming Language Brian W. Kernighan & Dennis Ritchie Prentice-Hall Publlishers ISBN 0-13-110163-3 But until then yoM is the program in Intel Hex Format. To create a .COM file you must use another utility that is on your CP/M distribution diother line editor, Micro Cornucopia has a public domain text editor (EDIT.COM) on User Disk K6. This is what the program looks iler. This example is by no means graceful or elegant but will provide the novice with model of a successful C compilation. tem on it. This is important since many of the programs you will run to create C programs end with a Warm Boot (including the101,114,114 DB 111,114,13,0 END u may still try this sample program. YOUR C SYSTEM DISK The first thing you should do is make a copy of this disk. You wilskette called LOAD.COM. The final result is that the program you write in C can be translated by the compiler and these utililike: #include #include #include main() { printf("hello, world\n"); } TheThe C programming language is a vehicle for writing a program in a high level language and then translating it into machine lan compiler itself). THE PROGRAM The sample program is the first example in The C Programming Language. The program is on tD MOV A,M ORI EOFFLG MOV M,A LXI H,-1 ; return(-1); RET ; } GTCIF4: MOV A,M MOV L,A ; return(*cp & 0377l need to have most of the files on the same disk as the C compiler (SMC.COM) when you compile a C program. You do not need thD  program uses a function called "printf" which is in the C function library. To use this function the library must be appendedful and you have the HELLO2.ASM file, you are ready to assemble the program. ASM.COM translates an assembly language file inter the command: SMC HELLO2.C >B:HELLO2.ASM This will place the output file (which will be named HELLO2.ASM) on the disk in to the destination for the .PRN file; or a Z will cause the assembler not to produce the print file. Thus the command Aou will learn how to shorten the compiler's output but this example will not go into that. The reason this needs to be mentio to direct the files to another disk. To do that you must add an extension to your command input file call: ASM HELL to the program. This library is called LIBASM.C and is also on this disk. To append it to HELLO.C using the CP/M utility PIP to machine code. To assemble a file you only need to type ASM filename. For this program we will need to take advantage of thedrive B. It will take the compiler quite some time to compile your program. When it is done you will get the A> prompt againSM HELLO2.ABB will cause the assembler to look on drive A for HELLO2.ASM and to output HELLO2.HEX to drive B and HELLO2.PRN toned is that the output file created by the compiler will be approximately 60K! The best way to handle it is to put a blank,forO2.123 where the numbers must be replaced with single letters, each one representing something different. 1 can betype the following command: PIP HELLO2.C=HELLO.C,LIBASM.C This creates a file called HELLO2.C which has LIBASM.C followin parameters available with ASM. ASM produces two files with the same name as your .ASM file but with different extensions. For. Look at drive B's directory and you should see the output file. If you are having problems or are getting errors from the drive B also. For this example we will skip the print file. So, put ASM.COM and LOAD.COM on the blank disk with HELLO2.ASM (anmatted disk into drive B and your C system disk into drive A. Then redirect the output file to the blank disk. 1. DRIVE A:  a letter from A to Y which will represent the disk that has the .ASM file 2 can be a letter from A to Y representing the g the program HELLO.C. Now we are ready to compile! The compiler will create a large assembly language file. This is because example if you would type: ASM HELLO2 ASM would produce a hex file called HELLO2.HEX and a print file called HELLO2.PRN compiler, recheck your work making sure you did not misspell the commands or omitted anything. If the compilation was successd leave it in drive B). Then log on to drive B (the B> prompt should be displayed) and enter the command: ASM HELLO2.BBZ Your C SYSTEM DISK 2. DRIVE B: Blank Formatted Disk 3. Log on to drive A--(the A> prompt should be displayed) 4. Endisk destination of the .HEX file; or a Z will suppress generation of a hex file 3 can be a letter from A to Y pointing  all the I/O routines are attached to the program, even though this program does not use them all. As you learn more about C y. The .PRN file for HELLO2 is over 100K long and the hex file is also large. To make everything fit on a diskette you may need E  This will take some time but when it is finished you should have a file on the disk in B called HELLO2.HEX. Now we almosC00020039545DCD8A0B23CDCA0BC1C1C9C167 :100E6C00E1E5C5C1C1C9C1C1C93B21070039CD8A62 :100E7C000BAFB4F2A10E21070039EB21070039CDDD 0C1E1E530 :100DAC00C5AFB4F2BA0DC1E1E5C5CD5D0CC9C1E169 :100DBC00E5C5C9C9C5C521080039CD8A0BCD7D0B48 :100DCC00EB212D00CDE50B7CB52106003907 :100FFC00CD8A0BE521060039545DCD8A0B2BCDCA69 :10100C000BD119EB2100007D12C3611021040039B2 :10101C00CD8A0BAFB4F239102am. Any way you may run it like any other .COM file by entering: HELLO2 As I mentioned at the start, as you grow with CA0B2BCDCA0BD119E52109003993 :100F4C00CD8A0BEB210A00CD890CEB11300019D1A5 :100F5C007D1221070039E521090039CD8A0BEB21DF :100F6C00t have an executable program. LOAD.COM will translate the .HEX file into a .COM file. To do this to your program enter: LO :100E8C008A0BCD5D0CCDCA0B21000039EB212D0056 :100E9C007D12C3AB0E21000039EB2120007D122105 :100EAC00030039CD8A0BAFB4FADB0EB5CADB#include #include #include main() { printf("hello, world\n"); } 1040039EB21040056 :10102C0039CD8A0BCD5D0CCDCA0BC36110210600E6 :10103C0039CD8A0BEB21040039CD8A0B19CD7D0BF0 :10104C007CB5CA6110 you will learn how to reduce the size of your final programs. I think you will enjoy C and gain a better understanding of th0A00CD890CD1CDCA0B7CB5C27D0FC380D4 :100F7C000FC3240F21030039CD8A0B7CB5CAAD0FEA :100F8C0021050039CD8A0BE521050039545DCD8A48 :1AD HELLO2 LOAD will look for a file named HELLO2 with a .HEX extension. When it is finished, look at the directory on B and 0E21C9 :100EBC00050039CD8A0BE521050039545DCD8A0B2F :100ECC002BCDCA0BD119EB2100007D12C3240F21AD :100EDC00030039CD8A0BAFB4F2FC09E5210A0039CD8A0BE52105 :100E0C000A0039CD8A0BE5CD0218C1C1D1CDCA0B70 :100E1C00AFB4F2270E21FEFFC1C1C921060039CDA6 :100E2C008A0B21040039545DCD8A0B23CDC7 :10105C00CA0BC3391021040039CD8A0B7CB5CAFFE9 :10106C001021000039E5210A0039CD8A0BEB210152 :10107C0000Ce transformation of programs from your keyboard to the .COM files on your disk. May you always C clearly! 00F9C000B2BCDCA0BD119EB21000039CD7D0B7D6C :100FAC001221030039CD8A0BAFB4FADD0FB5CADDBF :100FBC000F21050039CD8A0BE521050039545DCyou should see a file called HELLO2.COM This is what we are after. Now don't laugh when you run it. If it was really a gE21030039EBC1 :100EEC0021030039CD8A0BCD5D0CCDCA0BC3240F69 :100EFC0021050039CD8A0BEB21030039CD8A0B1962 :100F0C00CD7D0B7CB5CA24CD8A0BAFB4F23C0E21FEFFC1C1C9B7 :100E3C00E1E57CB5CA6B0E21060039CD8A0BEB219E :100E4C00060039CD8A0BCD8A0BCD5D0CCDCA0B219A :100E5DDE0BD1CDCA0B21080039E5210A00C9 :10108C0039CD8A0BEB210100CD410CEB21FF7FCD3B :10109C00DE0BD1CDCA0B21060039CD8A0BE521061A :101004 :100D7C006E672025730D0068657265277320746893 :100D8C006520646563696D616C20256420616E6407 :100D9C0020746865206865782025780D0D93 :100FCC008A0B2BCDCA0BD119EB2120007D12C3AD9E :100FDC000F21050039CD8A0B33C933C521040039E3 :100FEC00CD8A0BAFB4FA1810B5CA1810reat program this wouldn't be as much fun. After all, it is really amazing how much work your computer did for this small progr0F21030039545DCD8AED :100F1C000B23CDCA0BC3FC0E21030039CD8A0B7CED :100F2C00B5CA800F21050039CD8A0BE521050039A2 :100F3C00545DCD8F AC000039545DCD8A0B2BCDCA0BD119E5210A21 :1010BC000039CD8A0BEB210500CD890CEBEB21011E :1010CC0000CD4F0CEBC1E1E5C51911300019D17DF42FC000039E521200039EB211C0039CD8A0B295E :10130C0019EB210200CD560CD1CDCA0B210E0039A0 :10131C00EB21100039CD8A0BCD8A0BCDCA0B210BDB7CB5C2505B :10124C0012C35312C3B01121060039CD8A0B7CB5E1 :10125C00CA7F1221080039CD8A0BE52108003954C8 :10126C005DCD8A0B2BCDCA0BC1D1CDCA0B2B :10149C00AFB4FABD14210C0039E5210E0039CD8A08 :1014AC000BEB21160039CD8A0B19D1CDCA0BC3C059 :1014BC0014C32A13C3CE142EB21060039CD8A0B19CD7D0B7C5A :10119C00B5CAB01121060039545DCD8A0B23CDCAD6 :1011AC000BC3881121060039CD8A0B7CB5CA5312AA :1011BC0BC3EC13210A0039EB2101007D129D :1013EC00210C0039CD8A0BCD7D0BEB213000CDE5E6 :1013FC000B7CB5CA1C1421000039EB2130007D1286 :10140C :1010DC001221080039E5210A0039CD8A0BEB2105D4 :1010EC0000CD890CD1CDCA0B7CB5C2FC10C3FF104E :1010FC00C3611021040039CD8A0B7CB5CA2A :10132C000039E521100039545DCD8A0B23CDCA0B51 :10133C002BCD7D0BD17D127CB5CA6E17210B0039DC :10134C00CD7D0BEB212500CDEB0B7CB5CAD119EB2120007D1241 :10127C00C3531221080039CD8A0BC1C1C9C1C1C5E4 :10128C0021000039EB21040039CD8A0BCDCA0BE1CA :10129C00E5CD7D0BE1140039EB210000CD20 :1014CC00CA0B21010039EB21030039CDCA0B210BCA :1014DC000039E5210E0039545DCD8A0B23CDCA0BA2 :1014EC002BCD7D0B021020039E5210C0039CD8A0BEB210F00FF :1011CC00CDDE0BD1CDCA0B210A0039E5210C00393B :1011DC00CD8A0BEB210400CD410CEB21FF0FCDDEB2 :00210C0039545DCD8A0B23CDCA0BC3261495 :10141C0021000039EB2120007D12211A0039E52131 :10142C000E0039CD8A0BE5211C0039E5CD0218C11F B112198 :10110C00060039CD8A0BE521060039545DCD8A0BDA :10111C002BCDCA0BD119EB2120007D12C3FF10215E :10112C00060039CD8A0BC1C9C1C56F1321AA :10135C000B0039CD7D0BE5210100E5CD251AC1C16E :10136C00C32A13210E0039CD8A0BCD7D0BEB212521 :10137C0000CDE50B7CB5CAA3132B212000CDE50B7CB5CABC1256 :1012AC0021000039545DCD8A0B23CDCA0BC39B1290 :1012BC0021040039545DCD8A0B23CDCA0B2BE521BB :1012CC0002D17D12211A0039E5211200394B :1014FC00545DCD8A0B2B2BCDCA0BCD8A0BD1CDCA0B :10150C000B210B0039CD7D0BEB216400CDE50B7C61 :10151C00B1011EC000BD1CDCA0BC1D1D5C5210A00CD050C7CC4 :1011FC00B5CA0E1221000039EB213000CDCA0BC349 :10120C00191221000039EB213700CDCA0B2108:10143C00C1D1CDCA0BAFB4FA6214210C0039E5212D :10144C000E0039CD8A0BEB211C0039CD8A0B19D13A :10145C00CDCA0BC36514C32A13210C0039CD8C521060039CD10 :10113C008A0BAFB4FA6711B5CA671121080039CD13 :10114C008A0BE521080039545DCD8A0B2BCDCA0BD7 :10115C00D119EB210000710E0039545DCD0D :10138C008A0B23CDCA0B2BCD7D0BE5210100E5CDBE :10139C00251AC1C1C32A13210C0039EB210E0039C7 :1013AC00CD8A0BCDCA0B0039545DCD8A0B23CDCA0B2BCD7D0B7F :1012DC00D17D127CB5CAE712C3BC12C1C921E4FF8F :1012EC0039F9211A0039E5CD7E0BD1CDCA0B21106D :1015CA3A15211A0039CD8A0BE521050039D7 :10152C00E5210700E5CD750EC1C1C1C3EE15210B38 :10153C000039CD7D0BEB217800CDE50B7CB5CA676E :10003F :10121C0039CD8A0BE521080039545DCD8A0B2BCDD5 :10122C00CA0BD119E521040039CD8A0BEBC1E1E5DC :10123C00C519D17D12210A0039CD8A0A0BDA :10146C00CD7D0BEB212E00CDE50B7CB5CAC3142131 :10147C00140039E5210E0039545DCD8A0B23CDCAF9 :10148C000BE5211A0039E5CD0218C1D12C3B01121060039CD4D :10116C008A0BAFB4F2881121060039EB2106003945 :10117C00CD8A0BCD5D0CCDCA0BC3B0112108003943 :10118C00CD8A0B210C0039CD8A0BCD7D0B10 :1013BC00EB212D00CDE50B7CB5CAE213210A0039D7 :1013CC00EB2100007D12210C0039545DCD8A0B23DA :1013DC00CDCA0G 154C0015211A0039CD8A0BE521050039E5210753 :10155C0000E5CD3511C1C1C1C3EE15210B0039CD4C :10156C007D0BEB216300CDE50B7CB5CA991521030179C00E521080039545DCD8A0B23CDCA0B2BCD26 :1017AC007D0BD17D12E521020039E5210800395469 :1017BC005DCD8A0B23CDCA0B2BCD7D0BD17D12D100E5CD251A41 :1016EC00C1C1C3BB1621120039CD8A0B7CB5CA35DA :1016FC001721010039545DCD8A0B23CDCA0B2BCD9C :10170C007D0BE5210100E57D0BEB21410087 :10193C00CDFF0BE5210A0039CD8A0BCD7D0BEB21B8 :10194C004600CDF80BD1CDDE0B7CB5CA6819210051 :10195C000039EB213700C0B23CDCA0BC3101621120039EB2126 :10163C00FFFFCDCA0B21010039CD8A0BE521140027 :10164C0039545DCD8A0B23CDCA0BD119CD7D0B7CC2 :1016513000CD560CD119D1CDCA0BD1D521CD :10188C000000CDFF0BE521080039CD8A0BCD8A0B6A :10189C00EB210000CD050CD1CDDE0B7CB5CAB21806 :1018EE :10157C000039EB211A0039CD8A0B7D122103003979 :10158C0011010019EB2100007D12C3EE15210B0097 :10159C0039CD7D0BEB217300CDE50B7CB1E8 :1017CC00CDE50B7CB5CAE81721010039CD7D0B7C2A :1017DC00B5C2E517210000C1C9C398172101003912 :1017EC00CD7D0BEB21000039CD7D0BCDCD251AC1C1211200395F :10171C00545DCD8A0B2BCDCA0B21180039545DCDED :10172C008A0B2BCDCA0BC3F11621180039545DCD91 :10173C008A0B2BCDCA0BC3A519210800397A :10196C00CD8A0BCD7D0BEB216100CDFF0BE5210A60 :10197C000039CD8A0BCD7D0BEB216600CDF80BD158 :10198C00CDDE0BC00B5CA6316C34116210B0039CD7D0BEB21A6 :10166C007300CDE50BE521140039CD8A0BEB211865 :10167C000039CD8A0BCDF10BD1CDDE0BE521160057 AC0021FEFFC1C1C921020039545DCD8A0B2331 :1018BC00CDCA0B2B21060039CD8A0BEBE1E5CDCA45 :1018CC000BC31D18C1E1E5C5C1C1C9C1C1C5C521455CABE15A7 :1015AC0021010039EB211A0039CD8A0BCDCA0BC3AE :1015BC00EE15210B0039CD7D0BEB217500CDE50B24 :1015CC007CB5CAEB15211A0039560CE5CD1D :1017FC007417C1C1C9C1C5C521020039EB21000054 :10180C00CDCA0B21060039CD8A0BEB210000CDCAC5 :10181C000B21080039CD8A0BCDCA0B23EB21120039CD8A0BCD92 :10174C00560CAFB4FA6B17B5CA6B1721000039CD24 :10175C007D0BE5210100E5CD251AC1C1C33517C3A9 :10176C007CB5CAA21921000039EB21570022 :10199C00CDCA0BC3A519C31C1AC1D1D5C5210400CE :1019AC00CD050C7CB5CAC41921020039545DCD8A11 :1019BC0 :10168C0039CD8A0BEB210000CDF10BD1CDDE0B7CDB :10169C00B5CAAF1621120039EB21160039CD8A0BD1 :1016AC00CDCA0B210A0039CD7D0B7CB5CAF1 :1018DC00020039EB210000CDCA0B21060039CD8A5C :1018EC000BEB210000CDCA0B21080039CD8A0BCDA2 :1018FC007D0BEB213000CDFF0BE5210A003CD8A0BE521050033 :1015DC0039E5210700E5CDE70FC1C1C1C3EE15C345 :1015EC002A13210E0039EB210C0039CD8A0BCDCA00 :1015FC000B210B0039CD7D0BEB213000CD8F :10182C00FF0BE5210A0039CD8A0BCD7D0BEB21395D :10183C0000CDF80BD1CDDE0B7CB5CAD01821000041 :10184C0039EB2106002A13211C0039F9C9C1E1E5C5AFB4FA85CA :10177C0017B5CA8517210100C9C1E1E5C57CB5C201 :10178C009217210000C921FFFFC9C9C521010039E9 :100B23CDCA0BC3CA1921FEFFC1C1C9210615 :1019CC000039CD8A0BE521080039CD8A0BCD8A0B65 :1019DC00EB210400CD4F0CD1CDCA0B21060039CD23 :1621B0 :1016BC00180039545DCD8A0B2BCDCA0B23EB2112AC :1016CC000039CD8A0BCD560CAFB4FAF116B5CAF170 :1016DC001621000039CD7D0BE52109CD8AA1 :10190C000BCD7D0BEB213900CDF80BD1CDDE0B7C53 :10191C00B5CA2E1921000039EB213000CDCA0BC3FA :10192C00A51921080039CD8A0BCDD7D0BEB217300CDEB0B7C5C :10160C00B5CA361621010039CD8A0BCD7D0BEB21E5 :10161C002000CDE50B7CB5CA361621010039545D8E :10162C00CD8A39CD8A0BCD8A0BCDCA0B2181 :10185C00000039E5C1E1E5C5110A00CD690CE521AF :10186C000C0039545DCD8A0B23CDCA0B2BCD7D0BCF :10187C00EB2H 1019EC008A0BE521080039CD8A0BCD8A0BE5210C39 :1019FC000039545DCD8A0B23CDCA0B2BCD7D0BD179 :101A0C0019EBC1E1E5C5CD560CD1CDCA0BC3F4> s#r# \ ?ʻ w# !ͼ ? !ͼ !)ͼ PGMNAME2X<!g!c|X">uR|ʬ!͗P!9!9̓Ç]!R|ރ!͗P!9!9̓Ç]!džR|!ۆ͗P!9!$"** s#r** ͉*n&e *~rARj*Z*>!*s#r*~wxWµ*R|߁!ÄR|!)G!9!9̓&Ç܁! G!9!9̓Ç{:x w|`!˄R|!!͇  Aborted,ason = !m>7*!6!6! B6Mw rwxg>Oiolib: Un1809 :101A1C00C1E1E5C5C1C1C9C1C121040039CD7D0BEE :101A2C00E521040039CD8A0BE5CD9909C1C1EB2123 :101A3C00FFFFCDE50B7CB5CA491ACD9{O2X<!g!e|X">{O 2!gw#S X B6Mw rwx g>Oiolib: Un9̓Ç]!R|B!͗P!9!9̓Ç]!9T]̓#Ç+v*1"GQ{!9T]̓#Ç+v*1"GQ **>!*s#r*!>w*>!*"|.!"*!~K!*͙ *$"*͗P!9!9̓Ç]!R|N!͗P!9!9̓Ç]! R|ʀ!"͗P!9!9̓Ç]able to open < or > file$33;;33;;:g.*og*|:_*! ! 61AC9210416 :101A4C000039CD8A0BE521040039CD8A0BE5CDEBAD :101A5C000AC1C1EB21FFFFCDE50B7CB5CA6E1ACDD7 :101A6C00961AC921040039CDable to open < or > file$33;;33;;:g.*og*|:_*! ! LXI H,0 DAD SP CALL CCGINT XCHG;; LXI H,2 DAD SP CALL CCGINT XCHG;; DAD SP CALL CCGINTCALL CCDSGI DAD D CALL CCGINT^#V"*" ** z'3{3*6#"!* |K!"*^!"*>*!c"!.R|ʲ!C͗P!9!9̓Ç]!OR|!͗P!9!9̓;Ç]!R|!х͗P!!͇  Aborted,ason = !m>7*!6!6! B6Mw rxg>Oiolib: Un8A0BE521040039CD21 :101A7C008A0BE5CD4A1AC1C1210D00E521040039BC :101A8C00CD8A0BE5CD251AC1C1C921AC1AE52102BD :101A9C0000E5CDEB0!͇  Aborted, reason = !m>7*!6!6! B6Mw rwxg>Oiolib: Un!9"<2:g.!"!"!͊G{ O><͊x g>O>!*>:¦@ ک é:& ..&.! 6}.a{ -..}9!9̓;Ç]!݅R|H!͗P!9!9̓@Ç]!)R|z!i͗P!9!9̓@Ç]!able to open < or > file$33;;33;;:g.*og*|:_*""  "|AC1C1210700E5CDEE02C1C9BD :0E1AAC006F7574707574206572726F720D0024 :0000000000 able to open < or > file$33;;33;;:g.*og*|:_*! ! I  |-#} "#|2"!~C!*$"^#V"*~#’!* |{!* FGETC EXTRN FGETS EXTRN GETS EXTRN PUTC EXTRN PUTCHAR EXTRN F_zWn DMzz x >) ʶ }o{_zW=ʿ ß z/W{/_x/Gy/O{_zW{z| .!N#F#x ~#͊ !9͊ } |$!9T]͊ # !9͊ |ʀ!9͊ !9T]͊ + ! 9͊ ! ͉ 0}!9! 9͊ ! ͉ |}À$ s#r:*w&o*|ʤ ͙ ": ¿  *&*| ~ ^# ~# O͙ ~# `i!9! !9!c !g !> !w !9͊ >! !9͊ >123this is a test testing %s#r*"*^#Vr+s*#* s#r*~*!~w!~o&*| o&!  PUTC EXTRN FPUTS EXTRN PUTS EXTRN FOPEN EXTRN FCLOSE EXTRN ABOR /* ** stdioa.h -- header for resident STDIO/CALL, and VM interfaces (ASM) */ #define stdin 0 #define stdout 1 #define std!9͊ |ʭ!9͊ !9T]͊ + !9} }!9͊ !9͊ !9T]͊ + ! }í!9͊ 33!9͊ !9͊ | !""*n&e *$*M*~ "*|a !d !}u } ##9~os here's the decimal %d and the hex %x ů ] !9͊ } !- | !9! !9T]͊ # !9! !*| !PG "+V6+^6O *+^#6s#r# *33;;x\ "zʒ |ʇ *|’ }T EXTRN CPM EXTRN EXIT EXTRN UNLINK ; STD I/O ROUTINES MATCHING VM ROUTINES (not availaberr 2 #define stdport 3 #define stdlist 4 #define CCEOM 45062 #define ERR -2 #define EOF -1 #define YES 1 #define NO 0 #!9T]͊ + !}a!9͊ 9!9!9͊ ] a!9͊ !9͊ } |a!9T]͊ # 9!9͊ |!9! 9͊ ! gÊ ##9~#fo##9T]} +}##9T]} #}}##9T]͊ + ##9T]͊ # }|}o|g}o|g}o|g + + + +9! 9͊ ! 9͊  '!!9͊ ͊ <!|k!9͊ !9͊ ͊ ] !9T]͊ # ;!9͊  !}w# ` 6*z {° ͐ ¹ ͥ   | } !  | !": le) ; EXTRN GETARG ; EXTRN FFLUSH ; ARITHMETIC & LOGICAL ROUTINES EXTRN CCARGC EXTRN define NULL 0 #define CR 13 #define LF 10 define CCEOM 45062 #define ERR -2 #define EOF -1 #define YES 1 #define NO 0 # !9! 9͊ !A ! !9͊ !9T]͊ + ! 9͊ !͉ !O 0}!9! 9͊ !͉ |a! + +|gz {!6 +6 +6 +6 +z= {!||g}oB )P {ozgb #|/g}/oDM!yt xGyOȯ{!9!9͊ ] !9!-}ë!9! }!9͊ !9͊ !9T]͊ + !}$!9͊ !9!9͊ ] $!9  *&""$"^#V"*~#h !* |Q !*s#r*"*^#Vr+s*#* CCSXT EXTRN CCDSGI EXTRN CCDDGI EXTRN CCINCI EXTRN CCDECI EXTRN CCJ 9͊ |+!9͊ !9T]͊ + ! }!9͊ !9͊ gg!9͊ !9T]͊ + !}ð!9͊ !9!9͊ !|’!!!9!9T]͊ # +} }!9!9T]͊ # +} } |!9} |!Ø!9} !9} V t9͊ }!9!}! 9} !s |ʾ!9!9͊ ! 9} !u |!9͊ !9!*!9! 9͊ ! gz {!*+*+*+*+z1{!||g}o6)D{ozgV#|/g}/oDM!yhxGyOȯ{_zWbDMz|ʣ!9T]͊ # +} !%*! 9!9͊ ! 9͊ } !- |! 9!}! 9T]͊ # ! 9!}! 9͊ } !0 |͊ # +} V !9} !9͊ ͙ ! |I͖!9͊ !9͊ ! |n͖!9͊ !9͊ ] ð!9͊ !9͊ } |ʰ!9T]͊ # È!9͊ |S!9! 9͊ ! ! 9! 9͊ !A ! !  |!9! !9͊ ! !9͊ } !0 ! 9͊ } !9 |!9!9͊ ͊ !9 i ! 9T]͊ # +} !09} !s |6!9͊ } ! |6!9T]͊ # !9! !9͊ !9T]͊ # } |cA! 9} !s !9͊ !9͊zxƈ>)Έʪֈ}o{_zW=ʳÓ;;z/W{/_x/Gy/O{_zW{z|.!N#F#x~#~#鈺`i!9!0}! 9T]͊ # &!9! }!9!9͊ !9 b! 9!9͊ !9͊  e*! 9͊ } !. |!9J! !9͊ %!! !output error !9!0 !9!7 !9͊ !9T]͊ + !9͊ }! 9͊ |PSð!9͊ |!9͊ !9T]͊ + ! }S!V  ! !9͊ ͊ ! |ʲ!!9T]͊ # +!9͊ !9! !9͊ ! !9͊ } ! !9͊ ! |ʯ!9!9͊ ! 9} |!9T]͊ + #!9͊ V !9} !%û!9͊ |5!#define ERRCODE 7 /* op sys return code */ cout(c, fd) char c; int fd; { if(fputc(c, fd)==EOF) xout(); } sout(string!9T]͊ # !9 ! 9!9͊ !9͊  *!9! !9!9 ! 9!9T]͊ # +} }!9!9T]͊CPDPC!͒P!͒PPOP HPUSH H!5͒P!;͒PPOP DPUSH D!]͒P!T!c͒PPOP BPUSH Bq##9~og~##9~#9͊ !9!9͊ } ! |ʼ!9T]͊ # Û!9T]͊ # +!9T]͊ # +} }|ü!9!9~ !9!0 ! 9͊ } !9 |.!9!0 å!9͊ } !A ! 9͊ } !F |h!9!7 å!9͊ } !a ! 9͊9T]͊ # +} !%!9T]͊ + !9T]͊ + !9T]͊ + #!9͊ V kk!9} !%5*!9ůʅ, fd) char *string; int fd; { if(fputs(string, fd)==EOF) xout(); } lout(line, fd) char *line; int fd; { sout(line, f ++ ͊ ! 9} !d |:!9͊ !9!u! 9} !x |g!9͊ !9!5! 9} !c |ʙ!9!fo##9T]q+}##9T]q#}}##9T]~+þ##9T]~#þ}|}o|g}o|g}o|g++++++| 9!9͊ )!V !9!9͊ ͊ ! 9!9T]͊ # +} }|n! 9} !% |o! 9} !%*!9͊ } !%  } !f |ʢ!9!W å! |!9T]͊ # !!9͊ !9͊ ͊ !O !9͊ !9͊ ͊ ! 9T]K d); cout('\n', fd); } xout() { fputs("output error\n", stderr); abort(ERRCODE); }  { clearstage(lval[7], 0); /* purge conventional code */ (*oper)(label); } #else /* FULLC */ zerojump(oper, label, ld(); outstr("$+5"); nl(); swapstk(); ol("PCHL"); csp=csp+BPW; } /* ** jump to internal label number */ j==EOF) POP D POP B MOV A,H ORA A JZ FPUTS2 POP B RET ; return(EOF); FPUTS2: POP H JMP FPUTS1 ; } FPUTS3: L /* ** pop stack to the secondary register */ pop() { ol("POP D"); csp=csp+BPW; } /* ** swap primary register if(k&1) { ol("INX SP"); k--; } while(k) { ol("POP B"); k=k-BPW;  /* peephole() uses trailing ";;" */ #endif /* TAB */ while(*sour) *dest++ = *sour++; sour=stagenext; while(--sour /* ** libl.h -- invoke a local copy of the function library */ #define PASSARGC /* pass arg count to called functions */ #aump(label) int label; { ot("JMP "); printlabel(label); nl(); } /* ** test primary register and jump if false *XI H,0 RET ; return(NULL); ; ; cpmio(fn,unit) ; CPMIO: POP B POP D POP H SHLD FN XCHG SHLD UNIT PUSH D P/* ** libl.h -- invoke a local copy of the function library */ #define PASSARGC /* pass arg count to called functions */ #a } return newsp; } } if(k<0) { if(k>-7) { if(k&1) { ol("DCX SP"); k++; > dest) { /* adjust stack references */ #ifdef TAB if(streq(sour,"\tDAD SP")) { #else /* TAB */ if(streq(sour,"DADsm EXTRN ABS EXTRN DTOI EXTRN ITOD EXTRN ITOU EXTRN ITOX EXTRN LEFT EXTRN PRINTF EXTRN SIGN EXTRN STRCMP EXT/ testjump(label) int label; { ol("MOV A,H"); ol("ORA L"); ot("JZ "); printlabel(label); nl(); } /* ** tUSH H PUSH B LHLD UNIT ; cpmdisk(*unit); MOV L,M MVI H,0 PUSH H CALL CPMDISK POP H LHLD UNIT ; ip = unit+FCBsm EXTERN ABS EXTERN DTOI EXTERN ITOD EXTERN ITOU EXTERN ITOX EXTERN LEFT EXTERN PRINTF EXTERN SIGN EXTERN STR } while(k) { ol("PUSH B"); k=k+BPW; } return newsp; } } if(save)  SP")) { #endif /* TAB */ --sour; i=BPW; while(numeric(*(--sour))) { if((*sour = *sour-i) < '0'RN UTOI EXTRN XTOI #endasm est primary register against zero and jump if false */ #ifdef FULLC zerojump(oper, label, lval) int (*oper)(), label, lval[];SIZE; LXI D,FCBSIZE ; cpm(DMA,&ip[BUFFER]); DAD D LXI D,BUFFER DAD D XCHG MVI C,DMA CALL BDOS LHLD FN ; t = cCMP EXTERN UTOI EXTERN XTOI #endasm swap(); const(k); ol("DAD SP"); ol("SPHL"); if(save) swap(); return newsp; } /* ** double primary register) { *sour = *sour+10; i=1; } else i=0; } } } csp=csp+BPW; }en */ modstk(newsp, save) int newsp, save; { int k; k=newsp-csp; if(k==0)return newsp; if(k>=0) { if(k<7) { L pm(fn,unit); MOV C,L LHLD UNIT XCHG CALL BDOS CALL CCSXT SHLD ZT MVI C,DMA ; cpm(DMA,TBUFF); LXI D,TBUFF CAL*/ #define STAGESIZE 800 #define STAGELIMIT (STAGESIZE-1) /* ** macro (define) pool */ #ifdef HASH #define MACNBR  7 #define STDO 8 /* compile "do" logic */ #define STFOR 9 /* compile "for" logic */ #define STSWITCH 10 /* compi*/ #define STAGESIZE 800 #define STAGELIMIT (STAGESIZE-1) /* ** macro (define) pool */ #ifdef HASH #define MACNBR le "switch/case/default" logic */ #define STCASE 11 #define STDEF 12 #define STGOTO 13 /* compile "goto" logic */ L BDOS LHLD ZT ; if(t~=0) return(-1); MOV A,H ; else return(0); ORA L JNZ CPMIF1 LXI H,0 JMP CPMIF2 CPMIF1:  90 #define MACNSIZE 990 /* 90*(NAMESIZE+2) */ #define MACNEND (macn+MACNSIZE) #define MACQSIZE 450 /* 90*5 */ #else le "switch/case/default" logic */ #define STCASE 11 #define STDEF 12 #define STGOTO 13 /* compile "goto" logic */ pi 90 #define MACNSIZE 990 /* 90*(NAMESIZE+2) */ #define MACNEND (macn+MACNSIZE) #define MACQSIZE 450 /* 90*5 */ #else o zero */ eq0(label) int label; { ol("MOV A,H"); ol("ORA L"); ot("JNZ "); printlabel(label); nl(); } /*  LXI H,-1 CPMIF2: RET ; ; cpmdisk(disk) ; CPMDISK: POP D POP H PUSH H PUSH D MOV A,L ; if(d~=0) ORA H JZ/* HASH */ #define MACQSIZE 950 #endif /* HASH */ #define MACMAX (MACQSIZE-1) /* ** statement types */ #define STIF */ #define LITABSZ 700 #define LITMAX (LITABSZ-1) /* ** input line */ #define LINEMAX 100 #define LINESIZE 101 /* HASH */ #define MACQSIZE 950 #endif /* HASH */ #define MACMAX (MACQSIZE-1) /* ** statement types */ #define STIF DISKIF1 XCHG ; cpm(SELECT,d-1); DCX D MVI C,SELECT CALL BDOS DISKIF1: RET ; ;----------- End of Small-c library 1 #define STWHILE 2 #define STRETURN 3 #define STBREAK 4 #define STCONT 5 #define STASM 6 #define STEXPR/* ** command line */ #define MAXARGS 32 /* maximum number of option arguments */ /* ** output staging buffer size  1 #define STWHILE 2 #define STRETURN 3 #define STBREAK 4 #define STCONT 5 #define STASM 6 #define STEXPR ----------- ; #endasm  7 #define STDO 8 /* compile "do" logic */ #define STFOR 9 /* compile "for" logic */ #define STSWITCH 10 /* compi