schrein (03/14/83)
#N:uiucdcs:12600001:000:65535 uiucdcs!schrein Mar 11 16:08:00 1983 When I announced this in 'net.micro', I was asked by a number of people to make it publically available, so.... smallC V2 a C subset (??) compiler for the 8080 family csh a CP/M MACRO-80 environment for it As is noted below, this is not complete -- mostly due to the fact that the compiler still needs a lot of work. The runtime support, however, is quite compatible with UN*X and thus should be a good starting point for reworking the compiler. Good luck to the next author... Axel Schreiner -- University of Illinois. %%%%%%%%%% scc/READ_ME %%%%%%%%%% smallC V2 -- a C subset compiler for the 8080 family originally by Ron Cain V2 by Jim Hendrix (Dr. Dobb's Journal 12/82, 1/83) these sources (slightly modified) from 'net.sources' CP/M MACRO-80 runtime support by Axel Schreiner This directory contains a LIB-80 listing of the runtime library for CP/M, the announcement placed into 'net.micro', a status report listing some known problems, and subdirectories with the sources. announce from net.micro c.rel runtime library listing rtl runtime library sources scc slightly modified smallC V2 sources status known problems uty some useful programs This is not a finished product, but the current author is leaving for Germany... %%%%%%%%%% scc/announce %%%%%%%%%% smallC V2 under CP/M and MACRO-80 I can make a runtime support for Hendrix' smallC V2 available that runs under CP/M 2.2, likes to be used with Microsoft MACRO-80, and supports the following: full BIOS and BDOS interface with exercising programs all stdio calls, but for fread, fwrite, ftell, scanf string functions, isalpha.. functions memory management through calloc and cfree CP/M aids, e.g., mkfcb, mkfilename, dumpfcb, ... i/o redirection from the command line, including append command line in lower case, with \ escapes and '..' ".." strings NUL:, DKA:, DKB:, CON:, RDR:, PUN:, and LST: devices cat, cp, cmp, entab, hex (dump anything), get (unarchive) utilities Shortcomings are the multitude of bugs in Hendrix' compiler, the fact that file i/o is buffered in sectors (i.e., is slow), and that the console is not buffered (i.e., has no line editing facility), and certain problems in accessing large files (i.e., arithmetic problems). If there is sufficient interest, I can place the sources (including a slightly improved version of smallC) into net.sources -- about 200K. Axel Schreiner, University of Illinois. %%%%%%%%%% scc/c.rel %%%%%%%%%% Module CRTL of B:C REL Length of Program 757 Length of Data area 0 Entry point(s): ?AND 016C' ?ASL 01DD' ?ASR 01CF' ?COM 01F0' ?DDGC 02B1' ?DDGI 02BE' ?DDPPC 02CA' ?DDPPI 02D1' ?DECC 0281' ?DECI 0299' ?DIV 0217' ?DSGC 02B5' ?DSGI 02C2' ?EQ 0173' ?GCHAR 02B8' ?GE 018D' ?GINT 02C5' ?GT 017F' ?INCC 028D' ?INCI 02A5' ?LE 0186' ?LNEG 0275' ?LT 0193' ?MULT 01F7' ?NE 0179' ?NEG 01EB' ?OR 015E' ?PDPC 02CB' ?PDPI 02D2' ?PINT 02D5' ?SMALL 0000' ?SUB 01E4' ?SWITC 02DB' ?SXT 02B9' ?UGE 01AA' ?UGT 01B6' ?ULE 01BD' ?ULT 01B0' ?XOR 0165' _BITMA 0091' _CHMOD 00A0' _CLOSE 005A' _CONIN 00E8' _CONOU 00ED' _CONST 00E3' _CREAT 0078' _CSTAT 0041' _DELET 0069' _DIRIO 0028' _DISKM 00A5' _DRIVE 0087' _EXIT 0007' _GETCH 000F' _GETS 003C' _GIOB 002D' _GLOB 005F' _HOME 0101' _LOGIN 0082' _LPUTC 0023' _LSTOU 00F2' _LSTST 0124' _MOUNT 0050' _NARG 02B9' _NGLOB 0064' _OPEN 0055' _PPUTC 001E' _PROTE 0096' _PUNOU 00F7' _PUTCH 0014' _PUTS 0037' _RDRIN 00FC' _READ 006E' _RECOR 00BE' _RENAM 007D' _RESET 004B' _RGETC 0019' _ROMAP 009B' _RREAD 00AF' _RWRIT 00B4' _RZWRI 00C8' _SECTR 0129' _SELDS 0106' _SETBU 008C' _SETDM 0115' _SETSE 0110' _SETTR 010B' _SIOB 0032' _SREAD 011A' _STAT 00B9' _SWRIT 011F' _UID 00AA' _UMOUN 00C3' _VERS 0046' _WBOOT 00DE' _WRITE 0073' ABORT 000A' External reference(s): ?30217 0000 _SHELL 0005' Module DTAB of B:C REL Length of Program 1289 Length of Data area 158 Entry point(s): _DBLIN 0255' _DBLIO 013C' _DBLOU 028D' _DBR 005E" _DBW 006E" _DCL 008E" _DCLOS 04B6' _DNM 0000" _DOP 002E" _DOPEN 0000' _DRD 003E" _DSEEK 02CA' _DSK 007E" _DWR 004E" External reference(s): ?30217 0000 ?AND 04C5' ?ASL 00EB' ?DDGC 04BE' ?DDPPI 04AC' ?DIV 0227' ?DSGI 04DE' ?EQ 03FC' ?GCHAR 02D8' ?GE 01D1' ?GINT 03A8' ?GT 0411' ?LT 03D2' ?MULT 036E' ?NE 04E6' ?OR 02BD' ?PINT 046C' ?SMALL 0000 ?SWITC 03BB' _BGETC 004C" _BINIT 038B' _BPUTC 005C" _FBLIN 005E" _FBLOU 006E" _FCLOS 008E" _FOPEN 002E" _FSEEK 007E" _GETCH 0040" _LPUTC 0056" _NGETC 0048" _NOP 0058" _PPUTC 0054" _PUTCH 0050" _RGETC 0042" _ROMAP 00DB' _SECTR 0205' _SELDS 02E0' _SETDM 024A' _SETSE 023B' _SETTR 0234' _SREAD 0268' _SWRIT 02A4' MKDRIV 001B' WORD 04D6' Module CSH of B:C REL Length of Program 4986 Length of Data area 751 Entry point(s): _BGETC 11C5' _BINIT 1195' _BPUTC 1292' _CFP 0283" _CTYPE 0000" _FBERR 01D6" _FBIN 0080" _FBLOC 0281" _FBOUT 012B" _NGETC 1360' _NOP 1379' _SHELL 0000' CALLOC 033F' CFREE 05A4' EXIT 0310' FCLOSE 0F07' FOPEN 0C08' FPUTC 1036' FPUTS 113F' FREOPE 0C6C' ISALNU 077C' ISASCI 0728' ISLOWE 0767' ISSPAC 0791' ISUPPE 0752' MKARG 082D' MKDRIV 098C' MKFCB 0BB8' MKFIEL 09E1' MKFILE 0A89' STRCMP 07CA' TOLOWE 07A6' TOUPPE 07B8' WORD 0825' External reference(s): ?30217 0000 ?AND 1289' ?DDGC 12D1' ?DDGI 12D6' ?DDPPC 0AF7' ?DDPPI 132F' ?DECI 11A5' ?DSGC 1358' ?DSGI 133F' ?EQ 117E' ?GCHAR 1369' ?GE 0731' ?GINT 1344' ?GT 042C' ?INCI 11B7' ?LNEG 0286' ?LT 0BCB' ?MULT 0357' ?OR 1370' ?PINT 134D' ?SMALL 0000 ?SUB 09DA' ?SWITC 0EAB' ?UGE 12BA' ?UGT 0519' _DBR 1217' _DBW 12C7' _DCL 0F47' _DNM 0D8B' _DOP 0EC4' _DRD 0E47' _DRIVE 0AF1' _DSK 0000 _DWR 10BF' _END 05BA' _EXIT 1091' MAIN 0303' Module FTAB of B:C REL Length of Program 4986 Length of Data area 118 Entry point(s): _DBR 0046" _DBW 0052" _DCL 006A" _DNM 0000" _DOP 0022" _DRD 002E" _DSK 005E" _DWR 003A" External reference(s): ?30217 0000 ?SMALL 0000 _BGETC 002E" _BINIT 0000 _BPUTC 003A" _FBLIN 0046" _FBLOU 0052" _FCLOS 006A" _FOPEN 0022" _FSEEK 005E" _GETCH 0030" _LPUTC 0042" _NGETC 0038" _NOP 0044" _PPUTC 0040" _PUTCH 003C" _RGETC 0032" _ROMAP 0000 MKDRIV 0000 WORD 0000 Module FIO of B:C REL Length of Program 1749 Length of Data area 0 Entry point(s): _FBLIN 01A9' _FBLOU 023A' _FCLOS 0632' _FOPEN 0000' _FSEEK 02CB' External reference(s): ?30217 0000 ?AND 0644' ?ASL 0052' ?ASR 06AE' ?DDGC 063D' ?DDPPI 062A' ?DECI 049D' ?DSGI 06A2' ?EQ 0580' ?GCHAR 02A5' ?GE 04AD' ?GINT 04F6' ?GT 0595' ?INCI 04CB' ?LT 0556' ?MULT 009E' ?NE 0667' ?OR 02AD' ?PINT 069C' ?SMALL 0000 ?SUB 04C1' ?SWITC 052F' _BINIT 0528' _CLOSE 06A6' _CREAT 0156' _DELET 013C' _GLOB 007C' _OPEN 00DB' _ROMAP 003B' _RREAD 05F7' _RZWRI 0257' _SETBU 02D8' _STAT 02E3' WORD 0657' Module DUMPDH of B:C REL Length of Program 301 Length of Data area 58 Entry point(s): DUMPDH 0000' External reference(s): ?30217 0000 ?DSGI 00DE' ?SMALL 0000 _FBERR 0000 _FBIN 0000 _FBOUT 00F1' DUMPBI 0129' DUMPDP 0113' PRINTF 0072' PUTHEX 00F7' WORD 0122' Module DUMPBI of B:C REL Length of Program 235 Length of Data area 18 Entry point(s): DUMPBI 0000' External reference(s): ?30217 0000 ?AND 0090' ?ASL 00AB' ?DECI 00B4' ?DSGC 0089' ?DSGI 00D4' ?GCHAR 00A4' ?INCI 009B' ?LNEG 00B7' ?LT 0071' ?PINT 0066' ?SMALL 0000 ?SUB 00DA' _FBERR 0000 _FBIN 0000 _FBOUT 0015' PRINTF 00E0' PUTBIT 001B' Module DUMPDP of B:C REL Length of Program 218 Length of Data area 145 Entry point(s): DUMPDP 0000' External reference(s): ?30217 0000 ?ASL 0036' ?DSGI 00C4' ?SMALL 0000 _FBERR 0000 _FBIN 0000 _FBOUT 0000 BYTE 002F' PRINTF 00D5' RWORD 0094' WORD 00CE' Module DUMPFC of B:C REL Length of Program 513 Length of Data area 119 Entry point(s): DUMPFC 0000' External reference(s): ?30217 0000 ?AND 010E' ?ASR 00B6' ?DSGI 01D7' ?INCI 01C9' ?LT 01BB' ?PINT 01B2' ?SMALL 0000 _FBERR 0000 _FBIN 0000 _FBOUT 0000 BYTE 01E7' PRINTF 01EE' PUTCHA 01FC' WORD 0187' Module ABS of B:C REL Length of Program 22 Length of Data area 0 Entry point(s): ABS 0000' External reference(s): ?30217 0000 ?NEG 000E' ?SMALL 0000 Module ATOI of B:C REL Length of Program 506 Length of Data area 0 Entry point(s): ATOI 0000' External reference(s): ?30217 0000 ?DDPPI 01D6' ?DSGI 01E5' ?EQ 00EC' ?GCHAR 0136' ?GINT 019B' ?INCI 0133' ?LT 01B4' ?MULT 01EB' ?PINT 01A6' ?SMALL 0000 ?SUB 01A2' ISDIGI 0145' ISSPAC 0039' ISUPPE 0177' ISXDIG 0169' Module INDEX of B:C REL Length of Program 53 Length of Data area 0 Entry point(s): INDEX 0000' External reference(s): ?30217 0000 ?DSGC 000E' ?DSGI 001C' ?EQ 0011' ?GCHAR 0027' ?INCI 0023' ?SMALL 0000 Module STRCAT of B:C REL Length of Program 79 Length of Data area 0 Entry point(s): STRCAT 0000' External reference(s): ?30217 0000 ?DECI 0025' ?DSGI 000A' ?GCHAR 0037' ?INCI 0033' ?PINT 000D' ?SMALL 0000 Module STRCPY of B:C REL Length of Program 49 Length of Data area 0 Entry point(s): STRCPY 0000' External reference(s): ?30217 0000 ?DSGI 000A' ?GCHAR 001F' ?INCI 001B' ?PINT 000D' ?SMALL 0000 Module STRLEN of B:C REL Length of Program 48 Length of Data area 0 Entry point(s): STRLEN 0000' External reference(s): ?30217 0000 ?GCHAR 0014' ?INCI 0025' ?PINT 000A' ?SMALL 0000 Module PUTBIT of B:C REL Length of Program 314 Length of Data area 6 Entry point(s): PUTBIT 0000' External reference(s): ?30217 0000 ?AND 00D5' ?ASL 0110' ?DECI 0119' ?DSGC 00CE' ?DSGI 0129' ?GCHAR 0109' ?INCI 00C5' ?LT 00A9' ?PINT 0095' ?SMALL 0000 _FBERR 0000 _FBIN 0000 _FBOUT 0000 FPRINT 0023' FPUTC 012F' Module PUTHEX of B:C REL Length of Program 383 Length of Data area 17 Entry point(s): PUTHEX 0000' External reference(s): ?30217 0000 ?AND 0086' ?DDGC 007F' ?DDPPI 015B' ?DSGC 0114' ?DSGI 0145' ?GCHAR 00CA' ?GINT 0163' ?INCI 00C6' ?LNEG 00FB' ?LT 00AA' ?PINT 016E' ?SMALL 0000 ?SUB 016A' _FBERR 0000 _FBIN 0000 _FBOUT 0000 FPRINT 008C' FPUTC 014B' ISASCI 00D3' ISCNTR 00F7' ISPRIN 00E5' Module CSHOW of B:C REL Length of Program 318 Length of Data area 44 Entry point(s): CSHOW 0000' External reference(s): ?30217 0000 ?AND 00BD' ?ASL 00F8' ?ASR 00A4' ?DSGI 0115' ?EQ 0032' ?GINT 0118' ?INCI 002B' ?PINT 010F' ?SMALL 0000 ?SUB 009D' _END 000B' _FBERR 0123' CAVAIL 012D' FPRINT 0133' FPUTC 0044' Module CAVAIL of B:C REL Length of Program 104 Length of Data area 0 Entry point(s): CAVAIL 0000' External reference(s): ?30217 0000 ?AND 005C' ?ASR 0055' ?PINT 003E' ?SMALL 0000 ?SUB 0063' _END 0007' WORD 0032' Module PRINTF of B:C REL Length of Program 2113 Length of Data area 15 Entry point(s): _ITOD 0054' _ITOU 0137' _ITOX 0206' _PFEMI 0000' _PFSTR 0000" _PRINT 039B' _UTOI 02E2' FPRINT 07B1' PRINTF 0786' SPRINT 07F6' External reference(s): ?30217 0000 ?AND 025D' ?ASL 01B6' ?ASR 0256' ?DDGC 0662' ?DDPPC 02AC' ?DDPPI 050C' ?DECI 0751' ?DIV 01D3' ?DSGC 076B' ?DSGI 0812' ?EQ 0689' ?GCHAR 072F' ?GE 034C' ?GINT 0824' ?GT 06BE' ?INCI 072B' ?LT 0361' ?MULT 032D' ?NE 0615' ?NEG 0078' ?PINT 081F' ?SMALL 0000 ?SUB 0836' ?SWITC 05CF' _FBERR 0048' _FBIN 0000 _FBOUT 0794' _NARG 07FE' ABORT 0051' FPUTC 0033' FPUTS 004C' ISDIGI 0307' Module MKWFCB of B:C REL Length of Program 80 Length of Data area 0 Entry point(s): MKWFCB 0000' External reference(s): ?30217 0000 ?DSGI 0045' ?INCI 0021' ?LT 0013' ?PINT 000A' ?SMALL 0000 _FBERR 0000 _FBIN 0000 _FBOUT 0000 MKWFIL 0049' Module MKWFIL of B:C REL Length of Program 303 Length of Data area 0 Entry point(s): MKWFIL 0000' External reference(s): ?30217 0000 ?DDGC 000B' ?DDPPC 006E' ?DDPPI 005B' ?DSGI 011A' ?EQ 00A3' ?GCHAR 011D' ?GINT 0055' ?INCI 00F6' ?LT 00E8' ?PINT 00DF' ?SMALL 0000 _DRIVE 0068' _FBERR 0000 _FBIN 0000 _FBOUT 0000 MKDRIV 0026' MKWFIE 00CA' Module MKWFIE of B:C REL Length of Program 265 Length of Data area 0 Entry point(s): MKWFIE 0000' External reference(s): ?30217 0000 ?DECI 00EC' ?EQ 00A6' ?GCHAR 009F' ?INCI 00F8' ?SMALL 0000 _FBERR 0000 _FBIN 0000 _FBOUT 0000 ISASCI 0009' ISDIGI 002B' ISLOWE 0075' ISUPPE 001A' TOUPPE 0091' Module ISPRIN of B:C REL Length of Program 21 Length of Data area 0 Entry point(s): ISPRIN 0000' External reference(s): ?30217 0000 ?AND 0012' ?DDGC 000B' ?DSGC 0008' ?SMALL 0000 _CTYPE 0001' Module ISCNTR of B:C REL Length of Program 21 Length of Data area 0 Entry point(s): ISCNTR 0000' External reference(s): ?30217 0000 ?AND 0012' ?DDGC 000B' ?DSGC 0008' ?SMALL 0000 _CTYPE 0001' Module ISALPH of B:C REL Length of Program 21 Length of Data area 0 Entry point(s): ISALPH 0000' External reference(s): ?30217 0000 ?AND 0012' ?DDGC 000B' ?DSGC 0008' ?SMALL 0000 _CTYPE 0001' Module ISDIGI of B:C REL Length of Program 21 Length of Data area 0 Entry point(s): ISDIGI 0000' External reference(s): ?30217 0000 ?AND 0012' ?DDGC 000B' ?DSGC 0008' ?SMALL 0000 _CTYPE 0001' Module ISXDIG of B:C REL Length of Program 21 Length of Data area 0 Entry point(s): ISXDIG 0000' External reference(s): ?30217 0000 ?AND 0012' ?DDGC 000B' ?DSGC 0008' ?SMALL 0000 _CTYPE 0001' Module ISPUNC of B:C REL Length of Program 21 Length of Data area 0 Entry point(s): ISPUNC 0000' External reference(s): ?30217 0000 ?AND 0012' ?DDGC 000B' ?DSGC 0008' ?SMALL 0000 _CTYPE 0001' Module TOASCI of B:C REL Length of Program 12 Length of Data area 0 Entry point(s): TOASCI 0000' External reference(s): ?30217 0000 ?AND 0009' ?SMALL 0000 Module FEOF of B:C REL Length of Program 30 Length of Data area 0 Entry point(s): FEOF 0000' External reference(s): ?30217 0000 ?AND 000F' ?DDGC 0008' ?SMALL 0000 _FBERR 0000 _FBIN 0000 _FBOUT 0000 Module FERROR of B:C REL Length of Program 18 Length of Data area 0 Entry point(s): FERROR 0000' External reference(s): ?30217 0000 ?AND 000F' ?DDGC 0008' ?SMALL 0000 _FBERR 0000 _FBIN 0000 _FBOUT 0000 Module CLEARE of B:C REL Length of Program 23 Length of Data area 0 Entry point(s): CLEARE 0000' External reference(s): ?30217 0000 ?AND 0011' ?GCHAR 000A' ?SMALL 0000 _FBERR 0000 _FBIN 0000 _FBOUT 0000 Module REWIND of B:C REL Length of Program 20 Length of Data area 0 Entry point(s): REWIND 0000' External reference(s): ?30217 0000 ?SMALL 0000 _FBERR 0000 _FBIN 0000 _FBOUT 0000 FSEEK 000E' Module FSEEK of B:C REL Length of Program 807 Length of Data area 0 Entry point(s): FSEEK 0000' External reference(s): ?30217 0000 ?AND 02B4' ?ASR 00E9' ?DDGC 02CC' ?DDGI 02D1' ?DDPPI 01C2' ?DECI 0155' ?DSGI 030A' ?EQ 0267' ?GCHAR 02AD' ?GE 0161' ?GINT 01B8' ?INCI 017F' ?NE 0229' ?PINT 02D5' ?SMALL 0000 ?SUB 0175' ?SWITC 01D6' _BINIT 0000 _DBW 0244' _DSK 02BF' _FBERR 0000 _FBIN 0000 _FBOUT 0000 _RREAD 0000 _SETBU 0000 _STAT 0000 WORD 0219' Module GETS of B:C REL Length of Program 111 Length of Data area 0 Entry point(s): GETS 0000' External reference(s): ?30217 0000 ?DSGI 0060' ?EQ 0036' ?INCI 004F' ?NE 0026' ?PINT 0046' ?SMALL 0000 _FBERR 0000 _FBIN 0016' _FBOUT 0000 FGETC 001A' Module FGETS of B:C REL Length of Program 152 Length of Data area 0 Entry point(s): FGETS 0000' External reference(s): ?30217 0000 ?DECI 0014' ?DSGI 0089' ?EQ 005C' ?INCI 0078' ?PINT 006C' ?SMALL 0000 _FBERR 0000 _FBIN 0000 _FBOUT 0000 FGETC 002C' Module GETW of B:C REL Length of Program 359 Length of Data area 17 Entry point(s): GETW 0000' External reference(s): ?30217 0000 ?AND 015C' ?ASL 014E' ?DDGC 012F' ?DDGI 0096' ?DSGC 0155' ?DSGI 0129' ?EQ 0032' ?GCHAR 00C0' ?OR 0160' ?PINT 009A' ?SMALL 0000 _CFP 007C' _DRD 0084' _EXIT 0055' _FBERR 004C' _FBIN 0000 _FBOUT 0000 FPUTS 0050' Module GETCHA of B:C REL Length of Program 9 Length of Data area 0 Entry point(s): GETCHA 0000' External reference(s): ?30217 0000 ?SMALL 0000 _FBERR 0000 _FBIN 0001' _FBOUT 0000 FGETC 0005' Module FGETC of B:C REL Length of Program 417 Length of Data area 17 Entry point(s): FGETC 0000' External reference(s): ?30217 0000 ?AND 00AE' ?DDGC 0102' ?DDGI 00DC' ?DSGI 015E' ?EQ 0109' ?GCHAR 0166' ?NE 0128' ?OR 016D' ?PINT 0121' ?SMALL 0000 ?SWITC 0183' _CFP 00C2' _DRD 00CA' _EXIT 0055' _FBERR 004C' _FBIN 0000 _FBOUT 0000 FPUTS 0050' UNGETC 014A' Module UNGETC of B:C REL Length of Program 109 Length of Data area 0 Entry point(s): UNGETC 0000' External reference(s): ?30217 0000 ?AND 0025' ?DDGC 001E' ?DSGC 0068' ?EQ 002C' ?GCHAR 004F' ?OR 0056' ?SMALL 0000 _FBERR 0000 _FBIN 0000 _FBOUT 0000 Module PUTS of B:C REL Length of Program 114 Length of Data area 0 Entry point(s): PUTS 0000' External reference(s): ?30217 0000 ?DSGC 002B' ?DSGI 000B' ?EQ 005E' ?GCHAR 001D' ?INCI 0019' ?PINT 000E' ?SMALL 0000 _FBERR 0000 _FBIN 0000 _FBOUT 0051' FPUTC 0055' Module PUTW of B:C REL Length of Program 276 Length of Data area 17 Entry point(s): PUTW 0000' External reference(s): ?30217 0000 ?AND 00FF' ?ASR 00E4' ?DDGC 00F8' ?DDGI 009B' ?DSGI 010F' ?EQ 0038' ?PINT 009F' ?SMALL 0000 _CFP 0081' _DWR 0089' _EXIT 005B' _FBERR 0052' _FBIN 0000 _FBOUT 0000 FPUTS 0056' Module PUTCHA of B:C REL Length of Program 17 Length of Data area 0 Entry point(s): PUTCHA 0000' External reference(s): ?30217 0000 ?DSGC 0004' ?SMALL 0000 _FBERR 0000 _FBIN 0000 _FBOUT 0008' FPUTC 000C' Module BYTE of B:C REL Length of Program 15 Length of Data area 0 Entry point(s): BYTE 0000' External reference(s): ?30217 0000 ?AND 000C' ?GCHAR 0005' ?SMALL 0000 Module RWORD of B:C REL Length of Program 39 Length of Data area 0 Entry point(s): RWORD 0000' External reference(s): ?30217 0000 ?AND 0020' ?ASL 000C' ?DDGC 0019' ?DSGI 0013' ?GCHAR 0005' ?OR 0024' ?SMALL 0000 Module END of B:C REL Length of Program 6 Length of Data area 6 Entry point(s): ?30217 0000" _EDATA 0006" _END 0006' _EPROG 0006' Symbol Value Defined Referenced ?30217 0000" END CRTL DTAB CSH FTAB FIO DUMPDH DUMPBI DUMPDP DUMPFC ABS ATOI INDEX STRCAT STRCPY STRLEN PUTBIT PUTHEX CSHOW CAVAIL PRINTF MKWFCB MKWFIL MKWFIE ISPRIN ISCNTR ISALPH ISDIGI ISXDIG ISPUNC TOASCI FEOF FERROR CLEARE REWIND FSEEK GETS FGETS GETW GETCHA FGETC UNGETC PUTS PUTW PUTCHA BYTE RWORD ?AND 016C' CRTL DTAB CSH FIO DUMPBI DUMPFC PUTBIT PUTHEX CSHOW CAVAIL PRINTF ISPRIN ISCNTR ISALPH ISDIGI ISXDIG ISPUNC TOASCI FEOF FERROR CLEARE FSEEK GETW FGETC UNGETC PUTW BYTE RWORD ?ASL 01DD' CRTL DTAB FIO DUMPBI DUMPDP PUTBIT CSHOW PRINTF GETW RWORD ?ASR 01CF' CRTL FIO DUMPFC CSHOW CAVAIL PRINTF FSEEK PUTW ?COM 01F0' CRTL ?DDGC 02B1' CRTL DTAB CSH FIO PUTHEX PRINTF MKWFIL ISPRIN ISCNTR ISALPH ISDIGI ISXDIG ISPUNC FEOF FERROR FSEEK GETW FGETC UNGETC PUTW RWORD ?DDGI 02BE' CRTL CSH FSEEK GETW FGETC PUTW ?DDPPC 02CA' CRTL CSH PRINTF MKWFIL ?DDPPI 02D1' CRTL DTAB CSH FIO ATOI PUTHEX PRINTF MKWFIL FSEEK ?DECC 0281' CRTL ?DECI 0299' CRTL CSH FIO DUMPBI STRCAT PUTBIT PRINTF MKWFIE FSEEK FGETS ?DIV 0217' CRTL DTAB PRINTF ?DSGC 02B5' CRTL CSH DUMPBI INDEX PUTBIT PUTHEX PRINTF ISPRIN ISCNTR ISALPH ISDIGI ISXDIG ISPUNC GETW UNGETC PUTS PUTCHA ?DSGI 02C2' CRTL DTAB CSH FIO DUMPDH DUMPBI DUMPDP DUMPFC ATOI INDEX STRCAT STRCPY PUTBIT PUTHEX CSHOW PRINTF MKWFCB MKWFIL FSEEK GETS FGETS GETW FGETC PUTS PUTW RWORD ?EQ 0173' CRTL DTAB CSH FIO ATOI INDEX CSHOW PRINTF MKWFIL MKWFIE FSEEK GETS FGETS GETW FGETC UNGETC PUTS PUTW ?GCHAR 02B8' CRTL DTAB CSH FIO DUMPBI ATOI INDEX STRCAT STRCPY STRLEN PUTBIT PUTHEX PRINTF MKWFIL MKWFIE CLEARE FSEEK GETW FGETC UNGETC PUTS BYTE RWORD ?GE 018D' CRTL DTAB CSH FIO PRINTF FSEEK ?GINT 02C5' CRTL DTAB CSH FIO ATOI PUTHEX CSHOW PRINTF MKWFIL FSEEK ?GT 017F' CRTL DTAB CSH FIO PRINTF ?INCC 028D' CRTL ?INCI 02A5' CRTL CSH FIO DUMPBI DUMPFC ATOI INDEX STRCAT STRCPY STRLEN PUTBIT PUTHEX CSHOW PRINTF MKWFCB MKWFIL MKWFIE FSEEK GETS FGETS PUTS ?LE 0186' CRTL ?LNEG 0275' CRTL CSH DUMPBI PUTHEX ?LT 0193' CRTL DTAB CSH FIO DUMPBI DUMPFC ATOI PUTBIT PUTHEX PRINTF MKWFCB MKWFIL ?MULT 01F7' CRTL DTAB CSH FIO ATOI PRINTF ?NE 0179' CRTL DTAB FIO PRINTF FSEEK GETS FGETC ?NEG 01EB' CRTL ABS PRINTF ?OR 015E' CRTL DTAB CSH FIO GETW FGETC UNGETC RWORD ?PDPC 02CB' CRTL ?PDPI 02D2' CRTL ?PINT 02D5' CRTL DTAB CSH FIO DUMPBI DUMPFC ATOI STRCAT STRCPY STRLEN PUTBIT PUTHEX CSHOW CAVAIL PRINTF MKWFCB MKWFIL FSEEK GETS FGETS GETW FGETC PUTS PUTW ?SMALL 0000' CRTL DTAB CSH FTAB FIO DUMPDH DUMPBI DUMPDP DUMPFC ABS ATOI INDEX STRCAT STRCPY STRLEN PUTBIT PUTHEX CSHOW CAVAIL PRINTF MKWFCB MKWFIL MKWFIE ISPRIN ISCNTR ISALPH ISDIGI ISXDIG ISPUNC TOASCI FEOF FERROR CLEARE REWIND FSEEK GETS FGETS GETW GETCHA FGETC UNGETC PUTS PUTW PUTCHA BYTE RWORD ?SUB 01E4' CRTL CSH FIO DUMPBI ATOI PUTHEX CSHOW CAVAIL PRINTF FSEEK ?SWITC 02DB' CRTL DTAB CSH FIO PRINTF FSEEK FGETC ?SXT 02B9' CRTL ?UGE 01AA' CRTL CSH ?UGT 01B6' CRTL CSH ?ULE 01BD' CRTL ?ULT 01B0' CRTL ?XOR 0165' CRTL _BITMA 0091' CRTL _CHMOD 00A0' CRTL _CLOSE 005A' CRTL FIO _CONIN 00E8' CRTL _CONOU 00ED' CRTL _CONST 00E3' CRTL _CREAT 0078' CRTL FIO _CSTAT 0041' CRTL _DELET 0069' CRTL FIO _DIRIO 0028' CRTL _DISKM 00A5' CRTL _DRIVE 0087' CRTL CSH MKWFIL _EXIT 0007' CRTL CSH GETW FGETC PUTW _GETCH 000F' CRTL DTAB FTAB _GETS 003C' CRTL _GIOB 002D' CRTL _GLOB 005F' CRTL FIO _HOME 0101' CRTL _LOGIN 0082' CRTL _LPUTC 0023' CRTL DTAB FTAB _LSTOU 00F2' CRTL _LSTST 0124' CRTL _MOUNT 0050' CRTL _NARG 02B9' CRTL PRINTF _NGLOB 0064' CRTL _OPEN 0055' CRTL FIO _PPUTC 001E' CRTL DTAB FTAB _PROTE 0096' CRTL _PUNOU 00F7' CRTL _PUTCH 0014' CRTL DTAB FTAB _PUTS 0037' CRTL _RDRIN 00FC' CRTL _READ 006E' CRTL _RECOR 00BE' CRTL _RENAM 007D' CRTL _RESET 004B' CRTL _RGETC 0019' CRTL DTAB FTAB _ROMAP 009B' CRTL DTAB FTAB FIO _RREAD 00AF' CRTL FIO FSEEK _RWRIT 00B4' CRTL _RZWRI 00C8' CRTL FIO _SECTR 0129' CRTL DTAB _SELDS 0106' CRTL DTAB _SETBU 008C' CRTL FIO FSEEK _SETDM 0115' CRTL DTAB _SETSE 0110' CRTL DTAB _SETTR 010B' CRTL DTAB _SHELL 0000' CSH CRTL _SIOB 0032' CRTL _SREAD 011A' CRTL DTAB _STAT 00B9' CRTL FIO FSEEK _SWRIT 011F' CRTL DTAB _UID 00AA' CRTL _UMOUN 00C3' CRTL _VERS 0046' CRTL _WBOOT 00DE' CRTL _WRITE 0073' CRTL ABORT 000A' CRTL PRINTF _BGETC 11C5' CSH DTAB FTAB _BINIT 1195' CSH DTAB FTAB FIO FSEEK _BPUTC 1292' CSH DTAB FTAB _DBLIN 0255' DTAB _DBLIO 013C' DTAB _DBLOU 028D' DTAB _DBR 005E" DTAB _DBR 0046" FTAB CSH _DBW 006E" DTAB _DBW 0052" FTAB CSH FSEEK _DCL 008E" DTAB _DCL 006A" FTAB CSH _DCLOS 04B6' DTAB _DNM 0000" DTAB _DNM 0000" FTAB CSH _DOP 002E" DTAB _DOP 0022" FTAB CSH _DOPEN 0000' DTAB _DRD 003E" DTAB _DRD 002E" FTAB CSH GETW FGETC _DSEEK 02CA' DTAB _DSK 007E" DTAB _DSK 005E" FTAB CSH FSEEK _DWR 004E" DTAB _DWR 003A" FTAB CSH PUTW _FBLIN 01A9' FIO DTAB FTAB _FBLOU 023A' FIO DTAB FTAB _FCLOS 0632' FIO DTAB FTAB _FOPEN 0000' FIO DTAB FTAB _FSEEK 02CB' FIO DTAB FTAB _NGETC 1360' CSH DTAB FTAB _NOP 1379' CSH DTAB FTAB MKDRIV 098C' CSH DTAB FTAB MKWFIL WORD 0825' CSH DTAB FTAB FIO DUMPDH DUMPDP DUMPFC CAVAIL FSEEK _CFP 0283" CSH GETW FGETC PUTW _CTYPE 0000" CSH ISPRIN ISCNTR ISALPH ISDIGI ISXDIG ISPUNC _END 0006' END CSH CSHOW CAVAIL _FBERR 01D6" CSH DUMPDH DUMPBI DUMPDP DUMPFC PUTBIT PUTHEX CSHOW PRINTF MKWFCB MKWFIL MKWFIE FEOF FERROR CLEARE REWIND FSEEK GETS FGETS GETW GETCHA FGETC UNGETC PUTS PUTW PUTCHA _FBIN 0080" CSH DUMPDH DUMPBI DUMPDP DUMPFC PUTBIT PUTHEX PRINTF MKWFCB MKWFIL MKWFIE FEOF FERROR CLEARE REWIND FSEEK GETS FGETS GETW GETCHA FGETC UNGETC PUTS PUTW PUTCHA _FBLOC 0281" CSH _FBOUT 012B" CSH DUMPDH DUMPBI DUMPDP DUMPFC PUTBIT PUTHEX PRINTF MKWFCB MKWFIL MKWFIE FEOF FERROR CLEARE REWIND FSEEK GETS FGETS GETW GETCHA FGETC UNGETC PUTS PUTW PUTCHA CALLOC 033F' CSH CFREE 05A4' CSH EXIT 0310' CSH FCLOSE 0F07' CSH FOPEN 0C08' CSH FPUTC 1036' CSH PUTBIT PUTHEX CSHOW PRINTF PUTS PUTCHA FPUTS 113F' CSH PRINTF GETW FGETC PUTW FREOPE 0C6C' CSH ISALNU 077C' CSH ISASCI 0728' CSH PUTHEX MKWFIE ISLOWE 0767' CSH MKWFIE ISSPAC 0791' CSH ATOI ISUPPE 0752' CSH ATOI MKWFIE MAIN CSH MKARG 082D' CSH MKFCB 0BB8' CSH MKFIEL 09E1' CSH MKFILE 0A89' CSH STRCMP 07CA' CSH TOLOWE 07A6' CSH TOUPPE 07B8' CSH MKWFIE DUMPBI 0000' DUMPBI DUMPDH DUMPDH 0000' DUMPDH DUMPDP 0000' DUMPDP DUMPDH PRINTF 0786' PRINTF DUMPDH DUMPBI DUMPDP DUMPFC PUTHEX 0000' PUTHEX DUMPDH PUTBIT 0000' PUTBIT DUMPBI BYTE 0000' BYTE DUMPDP DUMPFC RWORD 0000' RWORD DUMPDP DUMPFC 0000' DUMPFC PUTCHA 0000' PUTCHA DUMPFC ABS 0000' ABS ATOI 0000' ATOI ISDIGI 0000' ISDIGI ATOI PRINTF MKWFIE ISXDIG 0000' ISXDIG ATOI INDEX 0000' INDEX STRCAT 0000' STRCAT STRCPY 0000' STRCPY STRLEN 0000' STRLEN FPRINT 07B1' PRINTF PUTBIT PUTHEX CSHOW ISCNTR 0000' ISCNTR PUTHEX ISPRIN 0000' ISPRIN PUTHEX CAVAIL 0000' CAVAIL CSHOW CSHOW 0000' CSHOW _ITOD 0054' PRINTF _ITOU 0137' PRINTF _ITOX 0206' PRINTF _PFEMI 0000' PRINTF _PFSTR 0000" PRINTF _PRINT 039B' PRINTF _UTOI 02E2' PRINTF SPRINT 07F6' PRINTF MKWFCB 0000' MKWFCB MKWFIL 0000' MKWFIL MKWFCB MKWFIE 0000' MKWFIE MKWFIL ISALPH 0000' ISALPH ISPUNC 0000' ISPUNC TOASCI 0000' TOASCI FEOF 0000' FEOF FERROR 0000' FERROR CLEARE 0000' CLEARE FSEEK 0000' FSEEK REWIND REWIND 0000' REWIND FGETC 0000' FGETC GETS FGETS GETCHA GETS 0000' GETS FGETS 0000' FGETS GETW 0000' GETW GETCHA 0000' GETCHA UNGETC 0000' UNGETC FGETC PUTS 0000' PUTS PUTW 0000' PUTW _EDATA 0006" END _EPROG 0006' END %%%%%%%%%% scc/rtl/2.sub %%%%%%%%%% ; ; putchar ; $3 #$$p <$1:c0.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp1=$1:tmp ; ; getw ; $3 #$$q <$1:c0.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp2=$1:tmp ; ; putw ; $3 #$$r <$1:c0.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp3=$1:tmp ; ; gets needs fgetc ; $3 #$$s <$1:c0.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp4=$1:tmp ; ; fgets needs fgetc ; $3 #$$t <$1:c0.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp5=$1:tmp $6 $2:tmp=$2:clib,$2:tmp1,$2:tmp2,$2:tmp3,$2:tmp4,$2:tmp5/e era $2:clib.rel ren $2:clib.rel=$2:tmp.rel ; ; puts ; $3 #$$u <$1:c0.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp1=$1:tmp $6 $2:tmp=$2:clib,$2:tmp1/e era $2:clib.rel ren $2:clib.rel=$2:tmp.rel ; ; abs ; $3 #$$a <$1:c1.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp1=$1:tmp ; ; atoi needs is* ; $3 #$$b <$1:c1.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp2=$1:tmp ; ; isprint ; $3 #$$cd <$1:c1.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp3=$1:tmp ; ; iscntrl ; $3 #$$ce <$1:c1.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp4=$1:tmp ; ; isalpha ; $3 #$$cf <$1:c1.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp5=$1:tmp $6 $2:tmp=$2:clib,$2:tmp1,$2:tmp2,$2:tmp3,$2:tmp4,$2:tmp5/e era $2:clib.rel ren $2:clib.rel=$2:tmp.rel submit 3 $1 $2 $3 $4 $5 $6 %%%%%%%%%% scc/rtl/3.sub %%%%%%%%%% ; ; isdigit ; $3 #$$cg <$1:c1.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp1=$1:tmp ; ; isxdigit ; $3 #$$ch <$1:c1.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp2=$1:tmp ; ; ispunct ; $3 #$$ci <$1:c1.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp3=$1:tmp ; ; toascii ; $3 #$$j <$1:c1.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp4=$1:tmp ; ; index ; $3 #$$k <$1:c1.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp5=$1:tmp $6 $2:tmp=$2:clib,$2:tmp1,$2:tmp2,$2:tmp3,$2:tmp4,$2:tmp5/e era $2:clib.rel ren $2:clib.rel=$2:tmp.rel ; ; strcat ; $3 #$$m <$1:c1.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp2=$1:tmp ; ; strcpy ; $3 #$$p <$1:c1.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp5=$1:tmp $6 $2:tmp=$2:clib,$2:tmp2,$2:tmp5/e era $2:clib.rel ren $2:clib.rel=$2:tmp.rel ; ; strlen ; $3 #$$r <$1:c1.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp2=$1:tmp ; ; byte ; $3 #$$s <$1:c1.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp3=$1:tmp ; ; rword ; $3 #$$t <$1:c1.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp4=$1:tmp ; ; cshow needs cavail printf fputc ; $3 #u <$1:c1.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp5=$1:tmp $6 $2:tmp=$2:clib,$2:tmp2,$2:tmp3,$2:tmp4,$2:tmp5/e era $2:clib.rel ren $2:clib.rel=$2:tmp.rel ; ; cavail ; $3 #$$v <$1:c1.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp1=$1:tmp ; ; dumpdhd needs printf word puthex dumpbit dumpdpb ; $3 #\A <$1:c0.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp2=$1:tmp ; ; putbit needs fputc fprintf ; $3 #\B <$1:c0.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp3=$1:tmp ; ; puthex needs fputc fprintf is* ; $3 #\C <$1:c0.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp4=$1:tmp $6 $2:tmp=$2:clib,$2:tmp1,$2:tmp2,$2:tmp3,$2:tmp4/e era $2:clib.rel ren $2:clib.rel=$2:tmp.rel era $1:tmp.* era $2:tmp?.* %%%%%%%%%% scc/rtl/READ_ME %%%%%%%%%% This directory contains the 'csh' runtime support for smallC V2. The files are meant to be processed by the smallC compiler and by Microsoft's MACRO-80 assembler. A listing of the runtime library is included -- order is relatively crucial for correct resolution in one pass. The 'end' module must definitely be linked last. Most of this has been tested, but... make.sub submit files to process c[01].get [23].sub called by make.sub adlib.sub adds these modules to initial library c[01].get (process using 'get') small auxiliary modules crtl.mac Hendrix' assembler stuff, plus BIOS and BDOS interface csh.c main environment module def.h header file, mostly for c[01].get [fd]tab.c two variants of the driver table end.mac the very last module fio.c file i/o for CP/M io.h actual contents of driver table printf.c Hendrix' printf, extended to [sf]printf Consult 'c.rel' to see in what order the modules should be in a library. Consult 'def.h' as well as some utilities to see what a 'stdio.h' header file should contain... The 'wc' utility noted the following: 0x4119 1260 175 76 2.sub 0xD228 1770 240 104 3.sub 0x9633 550 40 28 adlib.sub 0xE80F 13039 2381 628 c0.get 0xDC08 4861 951 285 c1.get 0x5260 14474 2788 871 crtl.mac 0xED52 14450 2607 667 csh.c 0x1F53 2990 553 92 def.h 0x55E3 332 58 20 end.mac 0x9CE8 4542 777 221 fio.c 0x25E7 146 29 7 ftab.c 0x7404 8002 1341 423 io.h 0xC3E9 1734 246 99 make.sub 0x4D00 4314 798 269 printf.c %%%%%%%%%% scc/rtl/adlib.sub %%%%%%%%%% ; smallC runtime support ; ; c.rel: indisk($1) outdisk($2) ; lib-80($3) ; ; ats 2/83 ; xsub $3 $1:tmp=$2:c/e era $2:c.rel $3 $2:c=$1:tmp<..FIO> $1:clib<DUMPDH,DUMPBI,DUMPDP,DUMPFC> $1:clib<ABS,ATOI> $1:clib<INDEX,STRCAT,STRCPY,STRLEN> $1:clib<PUTBIT,PUTHEX> $1:clib<CSHOW,CAVAIL> $1:printf $1:clib<MKWFCB,MKWFIL,MKWFIE> $1:clib<ISPRIN,ISCNTR,ISALPH> $1:clib<ISDIGI,ISXDIG,ISPUNC,TOASCI> $1:clib<FEOF,FERROR,CLEARE,REWIND,FSEEK> $1:clib<GETS,FGETS,GETW,GETCHA,FGETC,UNGETC> $1:clib<PUTS,PUTW,PUTCHA> $1:clib<BYTE,RWORD> $1:tmp<END> /E era $1:tmp.rel %%%%%%%%%% scc/rtl/c0.get %%%%%%%%%% /* * c?.get -- smallC runtime library for CP/M and MACRO-80 * ats 2/83, in part adapted from Jim Hendrix' code */ $#define NOCCARGC ##include def.h /* TO BE FIXED */ /* * module names */ ##asm a NAME ('mkwfield') ; needs is* b NAME ('mkwfilename') ; needs mkwfield c NAME ('mkwfcb') ; needs mkwfilename d NAME ('dumpbit') ; needs putbit printf e NAME ('dumpdpb') ; needs putchar printf byte f NAME ('dumpfcb') ; needs putchar printf byte g NAME ('feof') h NAME ('ferror') i NAME ('clearerr') j NAME ('fseek') k NAME ('rewind') ; needs fseek l m NAME ('getchar') ; needs fgetc n NAME ('fgetc') ; needs ungetc o NAME ('ungetc') p NAME ('putchar') q NAME ('getw') r NAME ('putw') s NAME ('gets') ; needs fgetc t NAME ('fgets') ; needs fgetc u NAME ('puts') A NAME ('dumpdhd') ; needs printf, word, dumpdpb, puthex, putbit B NAME ('putbit') ; needs fputc, fprintf C NAME ('puthex') ; needs fputc, fprintf, is* ##endasm /* * globally external things (in csh) */ #extern char _fbin[]; /* stdin */ #extern char _fbout[]; /* stdout */ #extern char _fberr[]; /* stderr */ /**** **** CP/M utility routines ****/ /* * wildcard parser routines: * * mkwfield(&c,i,&c) upper-case, copy, pad, return -> next * mkwfilename(&c,&c) fix-format filename, return success * mkwfcb(&c,&c) init fcb with file name, return success * * all permit '*' for arbitrary tail and '?' for arbitrary letter */ aextern isascii(), isupper(), isdigit(), islower(), toupper(); a aCHAR_P mkwfield(f,l,s) /* copy isalnum() or ?/* */ a char *f; /* upper-cased to this buffer */ a int l; /* blank padded to this length */ a char *s; /* from this string */ a{ a do a if (isascii(*s)) a if (isupper(*s) || isdigit(*s) || *s == '?') a *f++ = *s++; a else if (islower(*s)) a *f++ = toupper(*s++); a else if (*s == '*') a { do a *f++ = '?'; a while (--l); a return s+1; a } a else a break; a else a break; a while (--l); a while (l--) a *f++ = ' '; a return s; a} bextern mkdrive(), mkwfield(), _drive(); b bINT mkwfilename(fnb, fnm) b char fnb[16]; /* to be filled */ b char *fnm; /* with this file name/wildcard */ b{ int i; b b if (fnm[1] == ':') b { if ((i = mkdrive(fnm)) == ERR) b return ERR; b fnb[FCB_ET] = i+1; b fnm += 2; b } b else /* make sure to set current drive */ b fnb[FCB_ET] = _drive()+1; b fnm = mkwfield(fnb+FCB_FN,8,fnm); b if (*fnm == '.') b fnm = mkwfield(fnb+FCB_FT,3,fnm+1); b else b for (i=0; i<3; i++) b fnb[FCB_FT+i] = ' '; b if (*fnm != NUL) b return ERR; b return NULL; b} cextern mkwfilename(); c cINT mkwfcb(fcb,fnm) c char fcb[FCB_]; /* to be initialized */ c char *fnm; /* with this file name/wildcard */ c{ int i; c c for (i=0; i<FCB_; i++) c fcb[i] = NUL; c return mkwfilename(fcb,fnm); c} /* * display routines: * * dumpbit(_bitmap()) allocation vector (Osborne-1 size) * dumpdhd(_seldsk()) disk header block * dumpdpb(_diskmap()) disk parameter block * dumpfcb(&fcb) file control block (Osborne-1 map) * * BUG: dumpbit knows about Osborne-1 disk size * dumpfcb knows about Osborne-1 using 16 byte pointers */ d#define BLOCKS 46 /* reservation blocks (Osborne-1) */ d dextern putbit(), printf(); d ddumpbit(bitmap) d char *bitmap; d{ char c; d int i,j,k; d d putbit(0,bitmap,BLOCKS,stdout); d k = 0; d for(i=BLOCKS; i; ) d { c = *bitmap++; d for (j=0; j<8; j++) d { if (c & 128) d k++; d c <<= 1; d if (! --i) d break; d } d } d printf("used/free: %d/%d\n", k, BLOCKS-k); d} Aextern printf(), word(), puthex(), dumpdpb(), dumpbit(); A Adumpdhd(dhd) A char *dhd; A{ A printf("\tXLT DBF DPB CST RBR\n"); A printf("%04x:\t%04x %04x %04x %04x %04x\n", A dhd, A word(dhd+DHD_XLT), A word(dhd+DHD_DBF), A word(dhd+DHD_DPB), A word(dhd+DHD_CST), A word(dhd+DHD_RBR)); A puthex(word(dhd+DHD_XLT), word(dhd+DHD_XLT), A word(word(dhd+DHD_DPB)+DPB_SPT), stdout); A puthex(word(dhd+DHD_DBF), word(dhd+DHD_DBF), SLEN, stdout); A dumpdpb(word(dhd+DHD_DPB)); A dumpbit(word(dhd+DHD_RBR)); A} eextern printf(), word(), byte(), rword(); e edumpdpb(dpb) e char *dpb; e{ e printf("%6u\tsectors/track\n", word(dpb+DPB_SPT)); e printf("%6u\tbytes/block\n", SLEN << byte(dpb+DPB_BSH)); e printf("%6u\tblocks/disk\n", 1 + word(dpb+DPB_DSM)); e printf("%6u\tdirectory slots\n", 1 + word(dpb+DPB_DRM)); e printf("directory allocation mask: %04x\n", rword(dpb+DPB_ALB)); e printf("check area size: %u\n", word(dpb+DPB_CKS)); e printf("first track: %u\n", word(dpb+DPB_OFF)); e} fextern printf(), putchar(), byte(), word(); f fdumpfcb(fcb) f char *fcb; f{ int i; f f printf("%04x ET FILENAME rs EXT EX S1 S2 RC NR RAND OV\n", fcb); f printf(" %02x ", byte(fcb+FCB_ET)); f for (i=0; i<8; i++) f printf("%c", byte(fcb+FCB_FN+i)); f printf(" %d%d ", byte(fcb+FCB_RO)>>7 &1, byte(fcb+FCB_SY)>>7 &1); f for (i=0; i<3; i++) f printf("%c", byte(fcb+FCB_FT+i)&127); f printf(" %02x %02x %02x %02x %02x %04x %02x\n DM:", f byte(fcb+FCB_EX), f byte(fcb+FCB_S1), f byte(fcb+FCB_S2), f byte(fcb+FCB_RC), f byte(fcb+FCB_NR), f word(fcb+FCB_RR), f byte(fcb+FCB_OV)); f for (i=0; i<16; i++) f printf(" %02x", byte(fcb+FCB_DM+i)); f putchar('\n'); f} /**** **** UN*X compatible file management for CP/M ****/ /* * file management routines: * * feof return EOF for physical end of file, or NULL * ferror return last error code (but not EOF), or NULL * clearerr remove error code * fseek position in (buffered) file * rewind reposition (buffered) file at beginning * * fflush, setbuf * not implemented (not needed??) * fileno, fdopen * not implemented / not needed * ftell * not implemented / impossible... * * BUGS: fseek has CP/M's idea of end of file for * character files (modes 0,1,2), and does sector * couting on modes 8,9,10. It also cannot handle * unsigned offsets. Any 'ungetc' character is lost. * If seeking is implemented, the file must be buffered. * One may not seek outside the existing file. */ gINT feof(fp) g FILE *fp; g{ g if (fp[FB_FLG] & FB_EOF) g return EOF; g return NULL; g} hINT ferror(fp) h FILE *fp; h{ h return fp[FB_FLG] & FB_ERM; h} iclearerr(fp) i FILE *fp; i{ i fp[FB_FLG] &= ~FB_ERM; i} jextern _dsk[], _dbw[]; jextern word(), _setbuf(), _stat(), _binit(), _rread(); j jINT fseek(fp, off, mode) j FILE *fp; /* to be positioned */ j int off; /* offset */ j int mode; /* 0,1,2 or 8,9,10 */ j{ int f; /* for cuntion call */ j int csec, cpos; /* current sector/position */ j int ssec, spos; /* seek sector/position */ j j if ((fp[FB_FLG] & FB_OPF) == 0 || _dsk[fp[FB_DRV]] == NULL) j return -1; /* unable */ j csec = word(fp+FCB_RR); j cpos = fp; j if ((cpos = word(fp+FB_NCP) - (cpos+FB_BUF)) >= SLEN) j { cpos -= SLEN; j ++csec; j } j switch(mode) { j case 0: /* char-relative to begin */ j case 1: /* char-relative to present-char */ j case 2: /* char-relative to char-EOF */ j ssec = off >> LSLEN; j spos = off & SLEN-1; j if (mode != 1) j break; j ssec += csec; j if ((spos += cpos) < 0) j { spos += SLEN; j --ssec; j } j else if (spos >= SLEN) j { spos -= SLEN; j ++ssec; j } j break; j case 8: /* sector-relative to begin */ j case 9: /* sector-relative to present-sector */ j case 10: /* sector-relative to sector-EOF */ j ssec = off; j spos = 0; j if (mode != 9) j break; j ssec += csec; j break; j default: j return -1; j } j if (fp[FB_FLG] & FB_OUF && word(fp+FB_NCP) != fp+FB_BUF) j { f = _dbw[fp[FB_DRV]]; j if (f == NULL || (f)(fp)) j return -1; /* couldn't flush */ j } j fp[FB_FLG] &= ~FB_UNF; /* drop any FB_UNC */ j f = _dsk[fp[FB_DRV]]; j return (f)(fp,mode,csec,cpos,ssec,spos); j} kextern fseek(); k kINT rewind(fp) k FILE *fp; k{ k return fseek(fp,0,0); k} /* l reserved */ /**** **** UN*X compatible i/o transfer routines for CP/M ****/ /* * character i/o: * * getchar() from stdin * getc(fp) from fp * fgetc(fp) from fp * return EOF or character, * return '\n' for RETURN LINEFEED in file, * return '\r' for RETURN in file, * return '\n' for RETURN from device, * return EOF for ^Z or ^D, * set feof() signal only on physical EOF. * * ungetc(ch,fp) push character back, return it or EOF * * BUG: can't push right after '\r' was returned by get * * putchar(ch) to stdout * putc(ch,fp) to fp (#define as fputc!) * map '\n' to RETURN LINEFEED, * return EOF on hard error. */ mextern fgetc(); m mINT getchar() m{ m return fgetc(stdin); m} nextern fputs(), _exit(), _cfp, _drd[], ungetc(); n nINT fgetc(fp) n FILE *fp; n{ int ch; n int f; /* to cast a function call */ n n if (fp[FB_FLG] & FB_OUF || (fp[FB_FLG] & FB_OPF) == 0) n { fputs("reading bad file", stderr); n _exit(); n } n if (fp[FB_FLG] & FB_UNF) n { fp[FB_FLG] &= ~FB_UNF; n return fp[FB_UNC] & 255; n } n if (fp[FB_FLG] & FB_EOF) n return EOF; /* hard end of file */ n _cfp = fp; /* pass to byte driver */ n f = _drd[fp[FB_DRV]]; n switch (ch = (f)()) { n case CR: n if (fp[FB_DRV] == 0 && n (ch = (f)()) != LF) n { ungetc(ch,fp); n return '\r'; n } n case LF: n return '\n'; n case EOF: /* hard end of file */ n fp[FB_FLG] |= FB_EOF; n case EOT: /* ^D soft end of file */ n case SUB: /* ^Z soft end of file */ n return EOF; n default: n return ch; n } n} oINT ungetc(ch,fp) o char ch; o FILE *fp; o{ o if (fp[FB_FLG] & (FB_OUF | FB_UNF | FB_EOF | FB_OUF) || o (fp[FB_FLG] & FB_OPF) == 0) o return EOF; o fp[FB_FLG] |= FB_UNF; o return fp[FB_UNC] = ch; o} pextern fputc(); p pINT putchar(ch) p char ch; p{ p return fputc(ch, stdout); p} /* * word i/o: * * getw(fp) return word from fp * putw(w,fp) write to fp, return word or EOF * * always check feof/ferror to discover errors */ qextern fputs(), _exit(), _cfp, _drd[]; q qINT getw(fp) q FILE *fp; q{ char low, high; q int f; /* to cast a function call */ q q if (fp[FB_FLG] & FB_OUF || (fp[FB_FLG] & FB_OPF) == 0) q { fputs("reading bad file", stderr); q _exit(); q } q if (fp[FB_FLG] & FB_EOF) q return EOF; /* hard end of file */ q _cfp = fp; /* pass to _fgetchar() */ q f = _drd[fp[FB_DRV]]; q if (fp[FB_FLG] & FB_UNF) q { fp[FB_FLG] &= ~FB_UNF; q low = fp[FB_UNC]; q } q else q low = (f)(); q if (fp[FB_FLG] & (FB_EOF | FB_ERM)) q return EOF; q high = (f)(); q if (fp[FB_FLG] & (FB_EOF | FB_ERM)) q return EOF; q return (high << 8) | (low & 255); q} rextern fputs(), _exit(), _cfp, _dwr[]; r rINT putw(w,fp) r int w; r FILE *fp; r{ int f; /* to cast a function call */ r r if ((fp[FB_FLG] & FB_OUF) == 0 || (fp[FB_FLG] & FB_OPF) == 0) r { fputs("writing bad file", stderr); r _exit(); r } r if (fp[FB_FLG] & FB_EOF) r return EOF; /* hard end of file */ r _cfp = fp; /* pass to _fputchar */ r f = _dwr[fp[FB_DRV]]; r (f)(w & 255); /* low */ r if (fp[FB_FLG] & (FB_EOF | FB_ERM)) r return EOF; r (f)(w >> 8); /* high */ r if (fp[FB_FLG] & (FB_EOF | FB_ERM)) r return EOF; r return w; r} /* * other i/o: * * gets string from stdin, '\n' becomes NUL * fgets string from fp, '\n' is kept * puts string to stdout, appends '\n' * * return NULL on error, else string. * * fread, fwrite * to be implemented */ sextern fgetc(); s sCHAR_P gets(s) s char *s; s{ int ch; s char *str; s s str = s; s while ((ch = fgetc(stdin)) != '\n') s { if (ch == EOF) s { str = NULL; s break; s } s *s++ = ch; s } s *s = NUL; s return str; s} textern fgetc(); t tCHAR_P fgets(s, n, fp) t char *s; t int n; t FILE *fp; t{ int ch; t char *str; t t str = s; t while (--n > 0) t if ((ch = fgetc(fp)) == '\n') t { *s++ = ch; t break; t } t else if (ch == EOF) t { str = NULL; t break; t } t else t *s++ = ch; t *s = NUL; t return str; t} uextern fputc(); u uCHAR_P puts(s) u char *s; u{ char ch; u char *str; u u str = s; u while (ch = *s++) u if (fputc(ch, stdout) == EOF) u return NULL; u if (fputc('\n', stdout) == EOF) u return NULL; u return str; u} /**** **** memory display routines ****/ /* * putbit show bits in groups of 1 byte * puthex show bytes in groups of 8 words */ Bextern fputc(), fprintf(); B Bputbit(add, buf, bits, fp) B char *add; /* first address to show */ B char *buf; /* -> first byte */ B int bits; /* # bits */ B FILE *fp; /* for output */ B{ char c; /* current byte */ B int i,j; B B while (bits) B { fprintf(fp, "%04x:", add); B for (i=0; bits && i<4; ++i) B { fputc(' ',fp); B c = *buf++; B for (j=0; bits && j<8; ++j) B { if (c & 128) B fputc('1',fp); B else B fputc('0',fp); B c <<= 1; B --bits; B } B } B fputc('\n',fp); B } B} Cextern fprintf(), fputc(), isprint(), isascii(), iscntrl(); C Cputhex(add, buf, bytes, fp) C char *add; /* first address to show */ C char *buf; /* -> first byte to show */ C int bytes; /* # bytes (minimum) */ C FILE *fp; /* for output */ C{ char c; /* current byte */ C int i; C C do C { fprintf(fp,"%04x: ", add); C for (i=0; i<16; i += 2) C fprintf(fp,"%02x%02x ", buf[i] & 255, buf[i+1] & 255); C for (i=0; i<16; ++i) C if (isascii(c = *buf++) && isprint(c) && ! iscntrl(c)) C fputc(c,fp); C else C fputc('.',fp); C fputc('\n',fp); C add += 16; C } while ((bytes -= 16) > 0); C} %%%%%%%%%% scc/rtl/c1.get %%%%%%%%%% /* * c?.get -- smallC runtime library for CP/M and MACRO-80 * ats 2/83, in part adapted from Jim Hendrix' code */ $#define NOCCARGC ##include def.h /* TO BE FIXED */ /* * module names */ ##asm a NAME ('abs') b NAME ('atoi') ; needs is* c ; _ctype external d NAME ('isprint') e NAME ('iscntrl') f NAME ('isalpha') g NAME ('isdigit') h NAME ('isxdigit') i NAME ('ispunct') c ; end of _ctype needed j NAME ('toascii') k NAME ('index') l m NAME ('strcat') n o p NAME ('strcpy') q r NAME ('strlen') s NAME ('byte') t NAME ('rword') u NAME ('cshow') ; needs cavail printf fputs v NAME ('cavail') ##endasm /**** **** UN*X compatible math functions ****/ /* * abs absolute value of integer */ aINT abs(i) a int i; a{ a if (i<0) a return -i; a return i; a} /* * atoi integer value in string * * optional sign * 0?? base 8 * 0x?? base 16 * other base 10 */ bextern isspace(), isdigit(), isxdigit(), isupper(); b bINT atoi(string) b char *string; b{ int mult; b int base; b int ch; b int atoi; b b mult = 1; b base = 10; b atoi = 0; b while (isspace(ch = *string)) b string++; b if ((ch = *string) == '-') b { mult = -1; b ch = *++string; b } b else if (ch == '+') b ch = *++string; b if (ch == '0') b { base = 8; b if ((ch = *++string) == 'x' || ch == 'X') b { base = 16; b ch = *++string; b } b } b for( ; ch; ch = *++string) b { if (isdigit(ch)) b ch -= '0'; b else if (isxdigit(ch)) b if (isupper(ch)) b ch -= 'A' - 10; b else b ch -= 'a' - 10; b if (ch < base) b atoi = atoi*base + ch; b else b break; b } b return mult*atoi; b} /**** **** UN*X compatible character functions ****/ /* * character type functions: * * isprint(c) c is printing * iscntrl(c) c is control character * isalpha(c) c is alphabetic * isdigit(c) c is (decimal) digit * isxdigit(c) c is base 16 digit * ispunct(c) c is punctuation character */ /* 128 64 32 16 8 4 2 1 */ /* special upper lower num hex space punct cntrl */ c#define C_PRINT (128+64+32+16 +4 ) /* printing character */ c#define C_CNTRL ( 1) /* control character */ c#define C_ALPHA ( 64+32 ) /* alphabetic */ c#define C_UPPER ( 64 ) /* upper case */ c#define C_LOWER ( 32 ) /* lower case */ c#define C_DIGIT ( 16 ) /* digit */ c#define C_XDIGI ( 16+8 ) /* base 16 digit */ c#define C_ALNUM ( 64+32+16 ) /* alpha or numeric */ c#define C_SPACE ( 4 ) /* white space */ c#define C_PUNCT ( 2 ) /* punctuation */ c cextern char _ctype[]; dINT isprint(c) char c; { return _ctype[c] & C_PRINT; } eINT iscntrl(c) char c; { return _ctype[c] & C_CNTRL; } fINT isalpha(c) char c; { return _ctype[c] & C_ALPHA; } gINT isdigit(c) char c; { return _ctype[c] & C_DIGIT; } hINT isxdigit(c) char c; { return _ctype[c] & C_XDIGI; } iINT ispunct(c) char c; { return _ctype[c] & C_PUNCT; } /* * character conversion functions: * * toascii(i) return i mapped into ASCII character set */ jCHAR toascii(i) int i; { return i & 127; } /**** **** UN*X compatible string functions ****/ /* * index NULL or -> first 'c' in 's' */ kCHAR_P index(s,c) k char *s; k char c; k{ k do k if (*s == c) k return s; k while (*s++); k return NULL; k} /* l reserved */ /* * strcat copy `v' to end of 'n' including \0 */ mCHAR_P strcat(n,v) m char *n, *v; m{ char *nach; m m nach = n; m while (*n++) m ; m for (--n; *n++ = *v++; ) m ; m return nach; m} /* no reserved */ /* * strcpy copy `v' to 'n' including \0 */ pCHAR_P strcpy(n,v) p char *n, *v; p{ char *nach; p p nach = n; p while (*n++ = *v++) p ; p return nach; p} /* q reserved */ /* * strlen length of `s' sans \0 */ rINT strlen(s) r char *s; r{ int len; r r for (len = 0; *s++; ) r len++; r return len; r} /**** **** routines to approximate C features ****/ /* * byte(&c) return byte * rword(&i) return byte-reversed word */ sCHAR byte(bp) s char *bp; s{ s return *bp & 255; s} tINT rword(wp) t char *wp; t{ t return (*wp << 8) | *(wp+1) & 255; t} /**** **** dynamic memory allocation ****/ /* * cavail return approximate KB still free * cshow display heap on stderr */ uextern fprintf(), cavail(), fputc(); uextern char _fberr[], _end[]; u ucshow() u{ int *p, *np, l, i; u u p = _end+1 & ~1; u i = 0; u do u { if (++i == 6) u { fputc('\n', stderr); u i = 1; u } u np = *p & ~1; u fprintf(stderr, "%04x ", p); u if (l = np-1 - p) u if (*p & 1) u fprintf(stderr, "(%u) ", l << 1); u else u fprintf(stderr, "[%u] ", l << 1); u p = np; u } while (*np); u fprintf(stderr, "\nabout %d KB below stack\n", cavail()); u} vextern char _end[]; vextern word(); v vINT cavail() v{ char *p; v v for (p = _end+1 & ~1; word(p); p = word(p) & ~1) v ; v return ((&p - p) >> 10 & (1 << 6)-1) - 1; v} %%%%%%%%%% scc/rtl/crtl.mac %%%%%%%%%% ; crtl.mac -- smallC runtime environment module ; for CP/M ; for MACRO/80 ; ats 2/83 ; in part adapted from Jim Hendrix' code ; global name conventions: ; ======================== ; ; ? starts an internal routine name ; _ starts an internal C-callable name ; other starts a published C-callable name ; ; This file is organized so that all references ; to global symbols are forward. ; smallC CP/M environment: ; ======================== ; ; Set up stack to run from top of memory downward, ; and call smallC environment routine _shell(). ; ; Upon return, connect to BIOS warm start. ; ; _exit entry point to BIOS warm start, ; i.e., no file management wrapup. ; ; If the END module is linked last (and it must be): ; ; _edata follows the last static data area, ; is preceded by the 6 character production date mmddyy ; ; _eprog follows the last code area ; is preceded by the 6 character compiler logo ; ; _end follows the end of code and data ; ; The smallC compiler is expected to supply a reference ; to the ?smallC routine to arrange for proper library search. ENTRY ?smallC ENTRY _exit EXTRN _shell ; outermost C runtime routine EXTRN ?30217 ; version reference V.BIOS EQU 0 ; entry vector for BIOS warm start V.BDOS EQU 5 ; entry vector for BDOS CSEG ?smallC: LHLD V.BDOS+1 ; stack starts at top of memory SPHL CALL _shell ; call C environment routine _exit: JMP V.BIOS ; return to system ; BDOS calls: ; =========== ; ; BDOS C call return entry description ; code value value ; ------------------------------------------------------------- ; 0 abort() system reset ; 1 i = _getchar() char console read ; 2 _putchar(c) char console write ; 3 i = _rgetchar() char reader read ; 4 _pputchar(c) char punch write ; 5 _lputchar(c) char list write ; 6 i = _dirio(c) char 0xFF direct input ; 0=busy char direct output ; 7 i = _giob() byte get i/o byte ; 8 _siob(c) byte set i/o byte ; 9 _puts(&c) address print string to next $ ; 10 _gets(&buf) address read console buffer ; 11 i = _cstat() 0=busy get console status ; 12 i = _vers() word get version number (in hex) ; 13 _reset() reset disk ; 14 i = _mount(c) 0=ok drive# select disk ; 15 i = _open(&f) dir [1] address open file ; 16 i = _close(&f) dir address close file ; 17 i = _glob(&f) dir [2] address search for first file name ; 18 i = _nglob() dir [2] search for next file name ; 19 i = _delete(&f) dir address delete file ; 20 i = _read(&f) err [3] address read next record ; 21 i = _write(&f) err [3] address write next record ; 22 i = _create(&f) dir [1] address create file ; 23 i = _renam(&fn) dir address rename file ; 24 i = _login() vector get login vector ; 25 i = _drive() drive# get disk number ; 26 _setbuf(&c) address set DMA address (of 128 bytes) ; 27 i = _bitmap() bitmap get allocate vector ; 28 _protect() write protect ; 29 i = romap() vector get R/O vector ; 30 i = _chmod(&f) dir address set file attributes ; 31 i = _diskmap() diskmap get disk header address ; 32 i = _uid(c) user# 0xFF get user number ; 0=ok user# set user number ; 33 i = _rread(&f) err [4] address read random ; 34 i = _rwrite(&f) err [4] address write random ; 35 _stat(&f) [5] address compute file size ; 36 _record(&f) [5] address set random record ; 37 i = _umount(i) 0=ok vector reset selected drives ; 40 i = _rzwrite(&f) err[4] address write random zero fill ; ------------------------------------------------------------- ; ; bitmap from left to right, set bits indicate allocated ; reservation blocks ; ; buf console buffer has the following format: ; ; byte (in) maximum length available for text ; byte (out) length actually filled ; byte... (out) text read, without trailing newline ; ; c character (byte) parameter ; ; dir position in directory sector, 0..3 ; not found: 0xFF ; ; diskmap CP/M disk description ; ; drive# disk drive number, 0==A, 1==B, ... ; ; err error code: ; ; 0 ok ; 1 reading unwritten data (end of file) ; ; f file control block ; can usually contain wildcard file name ; ; fn file control block, ; new name begins at offset 17 ; ; i integer (word) result, possibly byte sign-extended ; ; vector bit vector indicating disk drives, ; least significant bit is drive 0 ; ; [1] modifies argument file control block ; ; [2] requires _setbuf(), ; result indicates directory entry in this buffer ; ; [3] requires _setbuf(), ; i/o happens from the DMA area set up by _setbuf() ; ; [4] [3], additionally, the random record position ; must have been set in the argument file control block ; ; [5] result is returned to the random record position ; in the file control block ; macro to dispatch BDOS calls: ; ----------------------------- ; ; t action ; ------------------------------------------------------------- ; 0 jump to BDOS ; 1 call BDOS, return HL = (int) A ; 2 DE = parm, call BDOS ; 3 DE = parm, call BDOS, return HL = (int) A BDOS MACRO func,t,code &func:: ;; entry point from C MVI C,&code ;; set BDOS function code JMP ?BD&t ;; goto executor ENDM BDOS abort,0,0 BDOS _getch,1,1 BDOS _putch,2,2 BDOS _rgetc,1,3 BDOS _pputc,2,4 BDOS _lputc,2,5 BDOS _dirio,3,6 BDOS _giob,1,7 BDOS _siob,2,8 BDOS _puts,2,9 BDOS _gets,2,10 BDOS _cstat,1,11 BDOS _vers,0,12 BDOS _reset,0,13 BDOS _mount,3,14 BDOS _open,3,15 BDOS _close,3,16 BDOS _glob,3,17 BDOS _nglob,1,18 BDOS _delete,3,19 BDOS _read,3,20 BDOS _write,3,21 BDOS _create,3,22 BDOS _rename,3,23 BDOS _login,0,24 BDOS _drive,1,25 BDOS _setbuf,2,26 BDOS _bitmap,0,27 BDOS _protect,0,28 BDOS _romap,0,29 BDOS _chmod,3,30 BDOS _diskmap,0,31 BDOS _uid,3,32 BDOS _rread,3,33 BDOS _rwrite,3,34 BDOS _stat,2,35 BDOS _record,2,36 BDOS _umount,3,37 BDOS _rzwrite,3,40 ; BDOS interface: ; --------------- ; type 0: ; ; jump to BDOS ; i.e., either no return, or return HL ?BD0 EQU V.BDOS ; type 2: ; ; C in BDOS function ; DE local int parameter ; HL local ?BD2: POP H ; return POP D ; int parameter PUSH D PUSH H JMP V.BDOS ; return through BDOS ; type 3: ; ; A local from BDOS ; C in BDOS function ; DE local int parameter ; HL out = (int) A ?BD3: POP H ; return POP D ; int parameter PUSH D PUSH H ; JMP ?BD1 ; BDOS, return HL = (int) A ; type 1: ; ; A local from BDOS ; C in BDOS function ; HL out = (int) A ?BD1: CALL V.BDOS JMP ?SXT ; HL = (int) A ; BIOS calls: ; =========== ; ; BIOS C call return entry description ; offset value value ; ------------------------------------------------------------- ; 0 complete cold start ; 3 _wboot() warm start ; 6 i = _const() ff=ready console status ; 9 c = _conin() char console input (no echo) ; 12 _conout(c) char console output ; 15 _lstout(c) char printer output ; 18 _punout(c) char punch output ; 21 c = _rdrin() char reader input ; 24 _home() set track zero ; 27 i = _seldsk(c,b) 0=no drive#, select disk ; diskmap first ; 30 _settrk(i) track select track ; 33 _setsec(i) sector set sector ; 36 _setdma(&c) address set DMA address ; 39 i = _sread() 0=ok read CP/M sector ; 42 i = _swrite(c) 0=ok all write CP/M sector ; 45 i = _lstst() ff=ready printer status ; 48 i = _sectran(i,&c) phys log, translate sector ; ttable ; ------------------------------------------------------------- ; ; all 0: write to previously allocated block ; 1: write to directory (always to disk) ; 2: write to first sector of unallocated data block ; ; b bit parameter ; ; c character (byte) parameter ; ; diskmap CP/M disk description (0==
schrein (03/14/83)
#R:uiucdcs:12600001:uiucdcs:12600002:000:51453 uiucdcs!schrein Mar 12 09:22:00 1983 (smallC V2 CP/M runtime support continued) (part 2) %%%%%%%%%% scc/rtl/crtl.mac %%%%%%%%%% ; crtl.mac -- smallC runtime environment module ; for CP/M ; for MACRO/80 ; ats 2/83 ; in part adapted from Jim Hendrix' code ; global name conventions: ; ======================== ; ; ? starts an internal routine name ; _ starts an internal C-callable name ; other starts a published C-callable name ; ; This file is organized so that all references ; to global symbols are forward. ; smallC CP/M environment: ; ======================== ; ; Set up stack to run from top of memory downward, ; and call smallC environment routine _shell(). ; ; Upon return, connect to BIOS warm start. ; ; _exit entry point to BIOS warm start, ; i.e., no file management wrapup. ; ; If the END module is linked last (and it must be): ; ; _edata follows the last static data area, ; is preceded by the 6 character production date mmddyy ; ; _eprog follows the last code area ; is preceded by the 6 character compiler logo ; ; _end follows the end of code and data ; ; The smallC compiler is expected to supply a reference ; to the ?smallC routine to arrange for proper library search. ENTRY ?smallC ENTRY _exit EXTRN _shell ; outermost C runtime routine EXTRN ?30217 ; version reference V.BIOS EQU 0 ; entry vector for BIOS warm start V.BDOS EQU 5 ; entry vector for BDOS CSEG ?smallC: LHLD V.BDOS+1 ; stack starts at top of memory SPHL CALL _shell ; call C environment routine _exit: JMP V.BIOS ; return to system ; BDOS calls: ; =========== ; ; BDOS C call return entry description ; code value value ; ------------------------------------------------------------- ; 0 abort() system reset ; 1 i = _getchar() char console read ; 2 _putchar(c) char console write ; 3 i = _rgetchar() char reader read ; 4 _pputchar(c) char punch write ; 5 _lputchar(c) char list write ; 6 i = _dirio(c) char 0xFF direct input ; 0=busy char direct output ; 7 i = _giob() byte get i/o byte ; 8 _siob(c) byte set i/o byte ; 9 _puts(&c) address print string to next $ ; 10 _gets(&buf) address read console buffer ; 11 i = _cstat() 0=busy get console status ; 12 i = _vers() word get version number (in hex) ; 13 _reset() reset disk ; 14 i = _mount(c) 0=ok drive# select disk ; 15 i = _open(&f) dir [1] address open file ; 16 i = _close(&f) dir address close file ; 17 i = _glob(&f) dir [2] address search for first file name ; 18 i = _nglob() dir [2] search for next file name ; 19 i = _delete(&f) dir address delete file ; 20 i = _read(&f) err [3] address read next record ; 21 i = _write(&f) err [3] address write next record ; 22 i = _create(&f) dir [1] address create file ; 23 i = _renam(&fn) dir address rename file ; 24 i = _login() vector get login vector ; 25 i = _drive() drive# get disk number ; 26 _setbuf(&c) address set DMA address (of 128 bytes) ; 27 i = _bitmap() bitmap get allocate vector ; 28 _protect() write protect ; 29 i = romap() vector get R/O vector ; 30 i = _chmod(&f) dir address set file attributes ; 31 i = _diskmap() diskmap get disk header address ; 32 i = _uid(c) user# 0xFF get user number ; 0=ok user# set user number ; 33 i = _rread(&f) err [4] address read random ; 34 i = _rwrite(&f) err [4] address write random ; 35 _stat(&f) [5] address compute file size ; 36 _record(&f) [5] address set random record ; 37 i = _umount(i) 0=ok vector reset selected drives ; 40 i = _rzwrite(&f) err[4] address write random zero fill ; ------------------------------------------------------------- ; ; bitmap from left to right, set bits indicate allocated ; reservation blocks ; ; buf console buffer has the following format: ; ; byte (in) maximum length available for text ; byte (out) length actually filled ; byte... (out) text read, without trailing newline ; ; c character (byte) parameter ; ; dir position in directory sector, 0..3 ; not found: 0xFF ; ; diskmap CP/M disk description ; ; drive# disk drive number, 0==A, 1==B, ... ; ; err error code: ; ; 0 ok ; 1 reading unwritten data (end of file) ; ; f file control block ; can usually contain wildcard file name ; ; fn file control block, ; new name begins at offset 17 ; ; i integer (word) result, possibly byte sign-extended ; ; vector bit vector indicating disk drives, ; least significant bit is drive 0 ; ; [1] modifies argument file control block ; ; [2] requires _setbuf(), ; result indicates directory entry in this buffer ; ; [3] requires _setbuf(), ; i/o happens from the DMA area set up by _setbuf() ; ; [4] [3], additionally, the random record position ; must have been set in the argument file control block ; ; [5] result is returned to the random record position ; in the file control block ; macro to dispatch BDOS calls: ; ----------------------------- ; ; t action ; ------------------------------------------------------------- ; 0 jump to BDOS ; 1 call BDOS, return HL = (int) A ; 2 DE = parm, call BDOS ; 3 DE = parm, call BDOS, return HL = (int) A BDOS MACRO func,t,code &func:: ;; entry point from C MVI C,&code ;; set BDOS function code JMP ?BD&t ;; goto executor ENDM BDOS abort,0,0 BDOS _getch,1,1 BDOS _putch,2,2 BDOS _rgetc,1,3 BDOS _pputc,2,4 BDOS _lputc,2,5 BDOS _dirio,3,6 BDOS _giob,1,7 BDOS _siob,2,8 BDOS _puts,2,9 BDOS _gets,2,10 BDOS _cstat,1,11 BDOS _vers,0,12 BDOS _reset,0,13 BDOS _mount,3,14 BDOS _open,3,15 BDOS _close,3,16 BDOS _glob,3,17 BDOS _nglob,1,18 BDOS _delete,3,19 BDOS _read,3,20 BDOS _write,3,21 BDOS _create,3,22 BDOS _rename,3,23 BDOS _login,0,24 BDOS _drive,1,25 BDOS _setbuf,2,26 BDOS _bitmap,0,27 BDOS _protect,0,28 BDOS _romap,0,29 BDOS _chmod,3,30 BDOS _diskmap,0,31 BDOS _uid,3,32 BDOS _rread,3,33 BDOS _rwrite,3,34 BDOS _stat,2,35 BDOS _record,2,36 BDOS _umount,3,37 BDOS _rzwrite,3,40 ; BDOS interface: ; --------------- ; type 0: ; ; jump to BDOS ; i.e., either no return, or return HL ?BD0 EQU V.BDOS ; type 2: ; ; C in BDOS function ; DE local int parameter ; HL local ?BD2: POP H ; return POP D ; int parameter PUSH D PUSH H JMP V.BDOS ; return through BDOS ; type 3: ; ; A local from BDOS ; C in BDOS function ; DE local int parameter ; HL out = (int) A ?BD3: POP H ; return POP D ; int parameter PUSH D PUSH H ; JMP ?BD1 ; BDOS, return HL = (int) A ; type 1: ; ; A local from BDOS ; C in BDOS function ; HL out = (int) A ?BD1: CALL V.BDOS JMP ?SXT ; HL = (int) A ; BIOS calls: ; =========== ; ; BIOS C call return entry description ; offset value value ; ------------------------------------------------------------- ; 0 complete cold start ; 3 _wboot() warm start ; 6 i = _const() ff=ready console status ; 9 c = _conin() char console input (no echo) ; 12 _conout(c) char console output ; 15 _lstout(c) char printer output ; 18 _punout(c) char punch output ; 21 c = _rdrin() char reader input ; 24 _home() set track zero ; 27 i = _seldsk(c,b) 0=no drive#, select disk ; diskmap first ; 30 _settrk(i) track select track ; 33 _setsec(i) sector set sector ; 36 _setdma(&c) address set DMA address ; 39 i = _sread() 0=ok read CP/M sector ; 42 i = _swrite(c) 0=ok all write CP/M sector ; 45 i = _lstst() ff=ready printer status ; 48 i = _sectran(i,&c) phys log, translate sector ; ttable ; ------------------------------------------------------------- ; ; all 0: write to previously allocated block ; 1: write to directory (always to disk) ; 2: write to first sector of unallocated data block ; ; b bit parameter ; ; c character (byte) parameter ; ; diskmap CP/M disk description (0==no such drive) ; ; drive# disk drive number, 0==A, 1==B, ... ; ; first bit 0: 0==first call for this disk ; ; i integer (word) result, possibly byte sign-extended ; ; ttable translation table address (0==none) ; macro to dispatch BIOS calls: ; ----------------------------- ; ; t action ; ------------------------------------------------------------- ; 0 jump to BIOS ; 1 call BIOS, return HL = (int) A ; 2 BC = parm, call BIOS ; 3 BC = parm, DE = parm, call BIOS ; 4 BC = parm, call BIOS, return HL = (int) A BIOS MACRO func,t,offset &func:: ;; entry point from C MVI A,&offset ;; set BIOS offset JMP ?BI&t ;; goto executor ENDM BIOS _wboot,0,3 BIOS _const,1,6 BIOS _conin,1,9 BIOS _conou,2,12 BIOS _lstou,2,15 BIOS _punou,2,18 BIOS _rdrin,1,21 BIOS _home,0,24 BIOS _selds,3,27 BIOS _settr,2,30 BIOS _setse,2,33 BIOS _setdm,2,36 BIOS _sread,1,39 BIOS _swrit,4,42 BIOS _lstst,1,45 BIOS _sectr,3,48 ; BIOS interface: ; --------------- ; type 1: ; ; A in offset in BIOS page ; local BIOS return ; HL out = (int) A ?BI1: LHLD V.BIOS+1 ; H = BIOS page number MOV L,A ; L = BIOS offset PUSH H LXI H,$+5 ; return address XTHL ; to stack PCHL JMP ?SXT ; HL = (int) A ; type 2: ; ; A in offset in BIOS page ; BC local int parameter ; HL local ?BI2: POP H ; return POP B ; parameter PUSH B PUSH H JMP ?BI0 ; go and return through BIOS ; type 3: ; ; A in offset in BIOS page ; BC local int parameter (first) ; DE local int parameter (second) ; HL local ?BI3: POP H ; return POP D ; second parameter POP B ; first parameter PUSH B PUSH D PUSH H ; JMP ?BI0 ; go and return through BIOS ; type 0: ; ; A in offset in BIOS page ; HL local ?BI0: LHLD V.BIOS+1 ; H = BIOS page number MOV L,A ; L = BIOS offset PCHL ; type 4: ; ; A in offset in BIOS page ; local BIOS return ; BC local int parameter ; HL out = (int) A ?BI4: POP H ; return POP B ; parameter PUSH B PUSH H LHLD V.BIOS+1 ; H = BIOS page number MOV L,A ; L = BIOS offset PUSH H LXI H,$+5 ; return address XTHL ; to stack PCHL JMP ?SXT ; HL = (int) A ; Jim Hendrix' arithmetic and logic library: ; ========================================== ; routine headers: ; ---------------- ENTRY ?OR ; hl |= de ENTRY ?XOR ; hl ^= de ENTRY ?AND ; hl &= de ENTRY ?EQ ; hl = hl == de ENTRY ?NE ; hl = hl != de ENTRY ?GT ; hl = (int) de > hl ENTRY ?LE ; hl = (int) de <= hl ENTRY ?GE ; hl = (int) de >= hl ENTRY ?LT ; hl = (int) de < hl ENTRY ?UGE ; hl = (unsigned) de >= hl ENTRY ?ULT ; hl = (unsigned) de < hl ENTRY ?UGT ; hl = (unsigned) de > hl ENTRY ?ULE ; hl = (unsigned) de <= hl ENTRY ?ASR ; hl = de >> hl ENTRY ?ASL ; hl = de << hl ENTRY ?SUB ; hl = de - hl ENTRY ?NEG ; hl = - hl ENTRY ?COM ; hl = ~ hl ENTRY ?MULT ; hl *= de ENTRY ?DIV ; hl = de / hl, de %= hl ENTRY ?LNEG ; hl = ! hl ENTRY ?DECC ; (byte) *(hl+top()) -- ENTRY ?INCC ; (byte) *(hl+top()) ++ ENTRY ?DECI ; (word) *(hl+top()) -- ENTRY ?INCI ; (word) *(hl+top()) ++ ENTRY ?DDGC ; hl = (int) (byte) *(hl+de) ENTRY ?DSGC ; hl = (int) (byte) *(hl+top()) ENTRY ?GCHAR ; hl = (int) (byte) *hl ENTRY ?SXT ; hl = (int) a ENTRY _narg ; hl = (int) a /* number of arguments */ ENTRY ?DDGI ; hl = (word) *(hl+de) ENTRY ?DSGI ; hl = (word) *(hl+top()) ENTRY ?GINT ; hl = (word) *hl ENTRY ?DDPPC ; (byte) *(pop()) = de+hl ENTRY ?PDPC ; (byte) *(pop()) = hl ENTRY ?DDPPI ; (word) *(pop()) = de+hl ENTRY ?PDPI ; (word) *(pop()) = hl ENTRY ?PINT ; (word) *de = hl ENTRY ?SWITCH ; switch selector execution ; code region: ; ------------ ; ; Blank lines separate potential modules. ?OR: MOV A,L ORA E MOV L,A MOV A,H ORA D MOV H,A RET ?XOR: MOV A,L XRA E MOV L,A MOV A,H XRA D MOV H,A RET ?AND: MOV A,L ANA E MOV L,A MOV A,H ANA D MOV H,A RET ?EQ: CALL CMP0 RZ DCX H RET ?NE: CALL CMP0 RNZ DCX H RET ?GT: XCHG CALL CMP0 RC DCX H RET ?LE: CALL CMP0 RZ RC DCX H RET ?GE: CALL CMP0 RNC DCX H RET ?LT: CALL CMP0 RC DCX H RET CMP0: MOV A,H ; INVERT SIGN OF HL XRI 80H MOV H,A MOV A,D ; INVERT SIGN OF DE XRI 80H CMP H ; COMPARE MSBS JNZ CMP1 ; DONE IF NEQ MOV A,E ; COMPARE LSBS CMP L CMP1: LXI H,1 ; PRESET TRUE COND RET ?UGE: CALL UCMP0 RNC DCX H RET ?ULT: CALL UCMP0 RC DCX H RET ?UGT: XCHG CALL UCMP0 RC DCX H RET ?ULE: CALL UCMP0 RZ RC DCX H RET UCMP0: MOV A,D CMP H JNZ UCMP1 MOV A,E CMP L UCMP1: LXI H,1 RET ?ASR: XCHG DCR E RM MOV A,H RAL MOV A,H RAR MOV H,A MOV A,L RAR MOV L,A JMP ?ASR+1 ?ASL: XCHG DCR E RM DAD H JMP ?ASL+1 ?SUB: MOV A,E SUB L MOV L,A MOV A,D SBB H MOV H,A RET ?NEG: CALL ?COM INX H RET ?COM: MOV A,H CMA MOV H,A MOV A,L CMA MOV L,A RET ?MULT: MOV B,H MOV C,L LXI H,0 MULT1: MOV A,C RRC JNC MULT2 DAD D MULT2: XRA A MOV A,B RAR MOV B,A MOV A,C RAR MOV C,A ORA B RZ XRA A MOV A,E RAL MOV E,A MOV A,D RAL MOV D,A ORA E RZ JMP MULT1 ?DIV: MOV B,H MOV C,L MOV A,D XRA B PUSH PSW MOV A,D ORA A CM DENEG MOV A,B ORA A CM BCNEG MVI A,16 PUSH PSW XCHG LXI D,0 DIV1: DAD H CALL RDEL JZ DIV2 CALL CMPBCDE JM DIV2 MOV A,L ORI 1 MOV L,A MOV A,E SUB C MOV E,A MOV A,D SBB B MOV D,A DIV2: POP PSW DCR A JZ DIV3 PUSH PSW JMP DIV1 DIV3: POP PSW RP CALL DENEG XCHG CALL DENEG XCHG RET DENEG: ;NEGATE THE INTEGER IN DE MOV A,D CMA MOV D,A MOV A,E CMA MOV E,A INX D RET BCNEG: ;NEGATE THE INTEGER IN BC MOV A,B CMA MOV B,A MOV A,C CMA MOV C,A INX B RET RDEL: ;ROTATE DE LEFT ONE BIT MOV A,E RAL MOV E,A MOV A,D RAL MOV D,A ORA E RET CMPBCDE: ;COMPARE BC TO DE MOV A,E SUB C MOV A,D SBB B RET ?LNEG: MOV A,H ORA L JNZ $+6 MVI L,1 RET LXI H,0 RET ?DECC: INX H INX H DAD SP MOV D,H MOV E,L CALL ?GCHAR DCX H MOV A,L STAX D RET ?INCC: INX H INX H DAD SP MOV D,H MOV E,L CALL ?GCHAR INX H MOV A,L STAX D RET ?DECI: INX H INX H DAD SP MOV D,H MOV E,L CALL ?GINT DCX H JMP ?PINT ?INCI: INX H INX H DAD SP MOV D,H MOV E,L CALL ?GINT INX H JMP ?PINT ?DDGC: DAD D JMP ?GCHAR ?DSGC: INX H INX H DAD SP ?GCHAR: MOV A,M _narg: ?SXT: MOV L,A RLC SBB A MOV H,A RET ?DDGI: DAD D JMP ?GINT ?DSGI: INX H INX H DAD SP ?GINT: MOV A,M INX H MOV H,M MOV L,A RET ?DDPPC: DAD D ?PDPC: POP B ; RET ADDR POP D PUSH B ;PCHAR: MOV A,L STAX D RET ?DDPPI: DAD D ?PDPI: POP B ; RET ADDR POP D PUSH B ?PINT: MOV A,L STAX D INX D MOV A,H STAX D RET ; EXECUTE "SWITCH" STATEMENT ; ; HL = SWITCH VALUE ; (SP) -> SWITCH TABLE ; DW ADDR1, VALUE1 ; DW ADDR2, VALUE2 ; ... ; DW 0 ; [JMP default] ; continuation ; ?SWITCH: XCHG ; DE = SWITCH VALUE POP H ; HL -> SWITCH TABLE SWLOOP: MOV C,M INX H MOV B,M ; BC -> CASE ADDR, ELSE 0 INX H MOV A,B ORA C JZ SWEND ; DEFAULT OR CONTINUATION CODE MOV A,M INX H CMP E MOV A,M INX H JNZ SWLOOP CMP D JNZ SWLOOP MOV H,B ; CASE MATCHED MOV L,C SWEND: PCHL END ?smallC %%%%%%%%%% scc/rtl/csh.c %%%%%%%%%% /* * csh.c -- smallC runtime environment for CP/M and MACRO-80 * ats 2/83, in part adapted from Jim Hendrix' code */ #define NOCCARGC #include def.h /* TO BE FIXED */ /* * external references */ extern _exit(); /* termination point in ?smallC */ extern main(); /* user's main program */ extern char _end[]; /* begin of heap */ extern _dnm[], _dop[], /* CP/M driver table */ _drd[], _dwr[], _dbr[], _dbw[], _dsk[], _dcl[]; extern _drive(); /* BDOS /* current drive number */ /**** **** global data regions ****/ /* * character classification table */ /* 128 64 32 16 8 4 2 1 */ /* special upper lower num hex space punct cntrl */ #define C_PRINT (128+64+32+16 +4 ) /* printing character */ #define C_CNTRL ( 1) /* control character */ #define C_ALPHA ( 64+32 ) /* alphabetic */ #define C_UPPER ( 64 ) /* upper case */ #define C_LOWER ( 32 ) /* lower case */ #define C_DIGIT ( 16 ) /* digit */ #define C_XDIGI ( 16+8 ) /* base 16 digit */ #define C_ALNUM ( 64+32+16 ) /* alpha or numeric */ #define C_SPACE ( 4 ) /* white space */ #define C_PUNCT ( 2 ) /* punctuation */ char _ctype[128] = { 1, 1, 1, 1, 1, 1, 1, 1, /* nul soh stx etx eot enq ack bel */ 1, 5, 5, 1, 1, 5, 1, 1, /* es ht lf vt ff cr so si */ 1, 1, 1, 1, 1, 1, 1, 1, /* dle ^q ^r ^s ^t nak syn etb */ 1, 1, 1, 1, 1, 1, 1, 1, /* can em sub esc fs gs rs us */ 4,130,130,128,128,128,128,130, /* sp ! " # $ % & ' */ 130,130,128,128,130,130,130,128, /* ( ) * + , - . / */ 16, 16, 16, 16, 16, 16, 16, 16, /* 0 1 2 3 4 5 6 7 */ 16, 16,130,130,128,128,128,130, /* 8 9 : ; < = > ? */ 128, 72, 72, 72, 72, 72, 72, 64, /* \@ A B C D E F G */ 64, 64, 64, 64, 64, 64, 64, 64, /* H I J K L M N O */ 64, 64, 64, 64, 64, 64, 64, 64, /* P Q R S T U V W */ 64, 64, 64,128,128,128,128,128, /* X Y Z [ \ ] ^ _ */ 130, 40, 40, 40, 40, 40, 40, 32, /* ` a b c d e f g */ 32, 32, 32, 32, 32, 32, 32, 32, /* h i j k l m n o */ 32, 32, 32, 32, 32, 32, 32, 32, /* p q r s t u v w */ 32, 32, 32,128,128,128,128, 1}; /* x y z { | } ~ del */ /* * file blocks: * * These are the center of file activity. * 'stdin', 'stdout', and 'stderr' are dedicated. */ char _fbin[FB_]; /* standard input (first!!) */ char _fbout[FB_]; /* standard output */ char _fberr[FB_]; /* diagnostic output */ STATIC FILE *_fblocks; /* -> chain of open file blocks */ STATIC FILE *_cfp; /* i/o transfer: -> current file block */ /**** **** smallC MACRO-80 CP/M runtime environment ****/ /* * _shell called from the ?smallC code * sets up environment and calls main() * * exit close all files and terminate program execution. * * BUG: more than 19 arguments cause great trouble... * fewer waste space. */ _shell() { char *cp, *fnp, ch; int argc, argv[20]; int *wp; /* for casting */ wp = _end+1 & ~1; /* even */ *wp = wp+1; /* blind heap element */ *++wp = NULL; /* terminal heap element */ _fblocks = NULL; /* no open file block */ _fbin[FB_FLG] = 0; /* stdio closed */ _fbout[FB_FLG] = 0; _fberr[FB_FLG] = 0; freopen("con:", "r", stdin); freopen("con:", "w", stdout); freopen("con:", "w", stderr); argv[0] = "*"; /* argument vector passed at 0x81 */ for (cp = 129, argc=1; ch = *cp++; ) switch(ch) { case '\'': cp = mkarg(argv[argc++] = cp, '\''); continue; case '\"': cp = mkarg(argv[argc++] = cp, '\"'); continue; case '>': if (*cp == '>') { ch = '+'; /* append */ cp++; } case '<': while (isspace(*cp)) cp++; if (! *cp) { fputs("bad redirect", stderr); _exit(); } cp = mkarg(fnp = cp, 0); switch (ch) { case '<': if (freopen(fnp, "r", stdin) == stdin) continue; break; case '>': if (freopen(fnp, "w", stdout) == stdout) continue; break; case '+': if (freopen(fnp, "a", stdout) == stdout) continue; } fputs("cannot access ", stderr); fputs(fnp, stderr); _exit(); default: if (! isspace(ch)) cp = mkarg(argv[argc++] = cp-1, 0); continue; } argv[argc] = NULL; main(argc,argv); exit(); } exit() { while (_fblocks) fclose(_fblocks); fclose(stdin); fclose(stdout); fclose(stderr); _exit(); } /**** **** UN*X compatible dynamic memory allocation ****/ /* * calloc return pointer to vector of 0, or NULL * cfree free previously allocated area * * The heap starts at _end and runs upward toward the stack. * Each area in the heap is preceded by a word at an even address; * a pointer chain runs from _end through these words to NULL; * The low bit in each word is 1 if the following area is free. * There is a blind, allocated element at the front of the chain. * * BUG: very unreasonable demands (e.g., wraparound) * will corrupt memory. */ #define SLACK 1024 /* at least 1KB stack to be free */ CHAR_P calloc(n,len) int n; /* number of elements */ int len; /* length of element */ { int cell; /* current allocation chain cell */ char *p; /* -> cell */ char *np; /* pointer in cell */ int *ip, *wp; /* for casting */ len = (len*n + 1) & ~1; /* even */ if (len == 0) return NULL; for (ip = p = word(_end+1 & ~1) & ~1; np = (cell = *ip) & ~1; ip = p = np) if (cell & 1) /* lowbit == 1 means free */ { if ((n = np-p - 2) > len+2) { wp = p + len+2; *wp = cell; *ip = wp; } else if (n >= len) *ip = np; else continue; for (wp = p+2; len; len -= 2) *wp++ = 0; return p+2; } if ((wp = p + len+2) > &n - SLACK) return NULL; *ip = wp; *wp = NULL; for (wp = p+2; len; len -= 2) *wp++ = 0; return p+2; } cfree(fp) int *fp; /* to be freed */ { int *p, *np; --fp; /* to cell */ for (p = _end+1 & ~1; np = word(p) & ~1; p = np) /* p-> previous cell */ if (np == fp) /* fp-> cell to free */ { np = *fp; /* np-> following cell */ if ((*fp & 1) || np == NULL) break; /* he does not own it */ if (*p & 1) if (*np & 1) *p = *np; else if (*np == NULL) *p = NULL; else { *p = np; *p |= 1; } else if (*np & 1) *fp = *np; else if (*np == NULL) *fp = NULL; else *fp |= 1; return; } fputs("cfree botch", stderr); _exit(); } /**** **** UN*X compatible character functions ****/ /* * character type functions: * * isascii(i) i is ASCII character * isupper(c) c is upper case * islower(c) c is lower case * isalnum(c) c is alphabetic or digit * isspace(c) c is white space */ INT isascii(i) int i; { return i >= 0 && i < 128; } INT isupper(c) char c; { return _ctype[c] & C_UPPER; } INT islower(c) char c; { return _ctype[c] & C_LOWER; } INT isalnum(c) char c; { return _ctype[c] & C_ALNUM; } INT isspace(c) char c; { return _ctype[c] & C_SPACE; } /* * character conversion functions: * * tolower(u) return lower case version of u * toupper(l) return upper case version of l */ CHAR tolower(u) char u; { return u + 'a'-'A'; } CHAR toupper(l) char l; { return l + 'A'-'a'; } /**** **** UN*X compatible string functions ****/ /* * strcmp 0 if `a' == `b' * <0 if `a' < `b' * >0 if `a' > `b' */ INT strcmp(a,b) char *a, *b; { while (*a == *b && *a) a++, b++; return *a - *b; } /**** **** routines to approximate C features ****/ /* * word(&i) return word */ INT word(wp) int *wp; { return *wp; } /**** **** CP/M utility routines ****/ /* * mkarg massage argument text, return -> unused char * * convert upper case to lower, unless preceded by \ * terminate on stop character or white space, * append NUL to resulting text. * * mkdrive(&c) return 0.. for A.. * mkfield(&c,i,&c) upper-case, copy, pad, return -> next * mkfilename(&c,&c) fix-format filename, return success * mkfcb(&c,&c) init fcb with file name, return success */ CHAR_P mkarg(str, stop) char *str; /* -> (first) result character */ char stop; /* 0: space, other: terminator */ { char *cp, ch; for(cp = str; ; ) { switch (ch = *cp++) { case NUL: if (stop == 0) { *str = NUL; return cp-1; } fputs("missing ", stderr); fputc(stop, stderr); _exit(); case '\\': if (*cp) { *str++ = *cp++; continue; } fputs("trailing \\", stderr); _exit(); } if (ch == stop || isspace(ch) && stop == 0) { *str = NUL; return cp; } if (isupper(ch)) *str++ = tolower(ch); else *str++ = ch; } } INT mkdrive(cp) char *cp; { if (isascii(*cp)) if (isupper(*cp)) return *cp - 'A'; else if (islower(*cp)) return *cp - 'a'; return ERR; } CHAR_P mkfield(f,l,s) /* copy isalnum() */ char *f; /* upper-cased to this buffer */ int l; /* blank padded to this length */ char *s; /* from this string */ { do if (isascii(*s) && isalnum(*s)) if (islower(*s)) *f++ = toupper(*s++); else *f++ = *s++; else break; while (--l); while (l--) *f++ = ' '; return s; } INT mkfilename(fnb, fnm) char fnb[16]; /* to be filled */ char *fnm; /* with this file name */ { int i; if (fnm[1] == ':') { if ((i = mkdrive(fnm)) == ERR) return ERR; fnb[FCB_ET] = i+1; fnm += 2; } else /* make sure to set current drive */ fnb[FCB_ET] = _drive()+1; fnm = mkfield(fnb+FCB_FN,8,fnm); if (*fnm == '.') fnm = mkfield(fnb+FCB_FT,3,fnm+1); else for (i=0; i<3; i++) fnb[FCB_FT+i] = ' '; if (*fnm != NUL) return ERR; return NULL; } INT mkfcb(fcb,fnm) char fcb[FCB_]; /* to be initialized */ char *fnm; /* with this file name */ { int i; for (i=0; i<FCB_; i++) fcb[i] = NUL; return mkfilename(fcb,fnm); } /**** **** UN*X compatible file management for CP/M ****/ /* * file management routines: * * fopen connect to file or device, return fp, or NULL * freopen change connection, return given fp, or NULL * fclose disconnect, return NULL, or EOF * * BUG: < 1<<16 sectors(records) per file */ FILE_P fopen(fnm,mode) char *fnm; /* CP/M logical device or file name */ char *mode; /* "r", "w", or "a" */ { FILE *fp; int *wp; /* for casting */ if ((fp = calloc(1, FB_)) == NULL) return NULL; wp = fp+FB_NXT; /* link new block in */ *wp = _fblocks; _fblocks = fp; return freopen(fnm, mode, fp); } FILE_P freopen(fnm,mode,fp) char *fnm; /* CP/M logical device or file name */ char *mode; /* "r", "w", or "a" */ FILE *fp; /* -> FB, need not be open */ { int i; /* # in driver table */ int f; /* for function call */ int *wp; /* for casting */ if (fp[FB_FLG] & FB_OPF && fclose(fp) == EOF) return NULL; /* cannot close */ if (fnm[0] && fnm[1] && fnm[2] && fnm[3] == ':' && fnm[4] == NUL) { mkfield(fp+FCB_FN,3,fnm); /* upper-case */ fp[FCB_FN+3] = NUL; /* terminate */ for(i=1; ;i++) if (_dnm[i] == 0) return NULL; /* unknown device */ else if (strcmp(fp+FCB_FN, _dnm[i]) == 0) break; } else if (mkfcb(fp, fnm) == ERR) return NULL; /* bad file name */ else i = 0; fp[FB_DRV] = i; /* point to driver */ fp[FCB_OV] = 0; /* set record 0 */ wp = fp + FCB_RR; *wp = 0; wp = fp + FB_NCP; /* set buffer empty */ *wp = fp + FB_BUF; switch (*mode) { case 'r': if (_drd[i] == NULL) return NULL; /* illegal to read */ fp[FB_FLG] = FB_OPF; break; case 'a': case 'w': if (_dwr[i] == NULL) return NULL; /* illegal to write */ fp[FB_FLG] = FB_OPF|FB_OUF; break; default: return NULL; /* illegal mode */ } if (f = _dop[i]) return (f)(fp,mode); return fp; /* no special open */ } INT fclose(fp) FILE *fp; { int f; /* for function call */ FILE *p; int *wp; /* for casting */ if ((fp[FB_FLG] & FB_OPF) == 0) return EOF; /* not open */ fp[FB_FLG] &= ~FB_OPF; /* reset open flag */ if (f = _dcl[fp[FB_DRV]]) f = (f)(fp); /* f is NULL or return */ if (fp == _fblocks) _fblocks = word(fp+FB_NXT); else { p = _fblocks; while (p) { wp = p+FB_NXT; if (fp == *wp) { *wp = word(fp+FB_NXT); break; } p = *wp; } if (p == NULL) return f; /* stdio ?? */ } cfree(fp); return f; } /**** **** UN*X compatible i/o transfer routines for CP/M ****/ /* * character i/o: * * fputc(ch,fp) to fp * map '\n' to RETURN LINEFEED, * return EOF on hard error. */ INT fputc(ch,fp) char ch; FILE *fp; { int f; /* to cast a function call */ if ((fp[FB_FLG] & FB_OUF) == 0 || (fp[FB_FLG] & FB_OPF) == 0) { fputs("writing bad file", stderr); _exit(); } if (fp[FB_FLG] & FB_EOF) return EOF; /* hard end of file */ _cfp = fp; /* pass to _fputchar */ f = _dwr[fp[FB_DRV]]; if (ch == '\n') /* map '\n' to RETURN LINEFEED */ { (f)(CR); (f)(LF); } else (f)(ch); if (fp[FB_FLG] & (FB_EOF | FB_ERM)) return EOF; return ch; } /* * other i/o: * * fputs string to fp * * return NULL on error, else string. */ CHAR_P fputs(s, fp) char *s; FILE *fp; { char ch; char *str; str = s; while (ch = *s++) if (fputc(ch, fp) == EOF) return NULL; return str; } /**** **** CP/M drivers to execute i/o operations ****/ /* * general routines: * * _binit clear buffer * _bgetchar return one character from buffer * _bputchar enter one character to buffer * _ngetchar return EOF * _nop do nothing (accept anything) * * BUG: assumes at most 16-bit record address * i.e., FCB_OV is not used. */ _binit(cp) /* initialize buffer */ char *cp; { int len; for (len = SLEN; len--; ) *cp++ = SUB; /* to end of file character */ } INT _bgetchar() /* use _cfp */ { int *wp; /* for casting */ char *cp; /* for casting */ int f; /* for function call */ wp = _cfp+FB_NCP; if (*wp >= _cfp + FB_BUF+SLEN) { wp = _cfp+FCB_RR; ++*wp; /* next record */ f = _dbr[_cfp[FB_DRV]]; if ((f)(_cfp)) return EOF; wp = _cfp+FB_NCP; *wp = _cfp+FB_BUF; /* at begin */ } cp = (*wp)++; return *cp & 255; } _bputchar(ch) /* use _cfp */ char ch; { int *wp; /* for casting */ char *cp; /* for casting */ int f; /* for function call */ wp = _cfp+FB_NCP; if (*wp >= _cfp + FB_BUF+SLEN) { f = _dbw[_cfp[FB_DRV]]; if ((f)(_cfp)) return EOF; wp = _cfp+FCB_RR; ++*wp; wp = _cfp+FB_NCP; _binit(*wp = _cfp+FB_BUF); } cp = (*wp)++; *cp = ch; } INT _ngetchar() { _cfp[FB_FLG] |= FB_EOF; return EOF; } _nop() { } %%%%%%%%%% scc/rtl/def.h %%%%%%%%%% /* * def.h -- definitions for smallC runtime support * ats 3/83, in part adapted from Jim Hendrix' code */ /* * return types for functions */ #define STATIC /* object is internal */ #define INT /* int */ #define CHAR /* char */ #define CHAR_P /* char * */ #define FILE_P /* FILE * */ /* * constants */ #define NULL 0 /* null pointer */ #define NUL 0 /* nul character */ #define EOF (-1) /* end of file */ #define ERR (-2) /* error return a la Hendrix */ /* * file management */ #define FILE char /* file pointer is char * */ #define stdin (_fbin) /* elsewhere, must be addresses */ #define stdout (_fbout) #define stderr (_fberr) /* * CP/M related definitions */ #define EOT 4 /* ^D marks end of file at console */ #define LF 10 /* line feed */ #define CR 13 /* carriage return */ #define SUB 26 /* ^Z marks end of text */ #define SLEN 128 /* sector length */ #define LSLEN 7 /* log2 of SLEN */ /* /* offset to... */ #define DHD_ 16 /* next disk header block */ #define DHD_XLT 0 /* -> translate table */ #define DHD_DBF 8 /* -> directory buffer */ #define DHD_DPB 10 /* -> disk parameter block */ #define DHD_CST 12 /* -> directory checksum table */ #define DHD_RBR 14 /* -> allocation table */ #define DPB_ 15 /* next disk parameter block */ #define DPB_SPT 0 /* sectors per track */ #define DPB_BSH 2 /* block shift */ #define DPB_BLM 3 /* block shift mask */ #define DPB_EXM 4 /* extent mask */ #define DPB_DSM 5 /* disk size - 1 in blocks */ #define DPB_DRM 7 /* directory size - 1 in entries */ #define DPB_ALB 9 /* directory allocation */ #define DPB_CKS 11 /* check area size */ #define DPB_OFF 13 /* offset to first track */ #define FCB_ 36 /* next file control block */ #define FCB_ET 0 /* entry type/drive code/user number */ #define FCB_FN 1 /* file name */ #define FCB_FT 9 /* file type (extension) */ #define FCB_RO 9 /* high bit is read only flag */ #define FCB_SY 10 /* high bit is system file flag */ #define FCB_EX 12 /* file extent */ #define FCB_S1 13 /* 00 */ #define FCB_S2 14 /* system use */ #define FCB_RC 15 /* record count in extent */ #define FCB_DM 16 /* 16 record allocation bytes */ #define FCB_NR 32 /* next record number in this extent */ #define FCB_RR 33 /* random record number */ #define FCB_OV 35 /* RR overflow */ /*define FB_FCB 0 /* FCB is first */ #define FB_FLG (FCB_) /* (char) flags */ #define FB_OPF (1<<7) /* 0: closed, 1: open */ #define FB_OUF (1<<6) /* 0: input, 1: output */ #define FB_EOF (1<<5) /* hard end of file */ #define FB_UNF (1<<4) /* ungetc buffer full */ #define FB_ERM (FB_UNF-1) /* mask to get error code */ #define FB_UNC (FCB_+1) /* (char) ungetc buffer */ #define FB_NXT (FCB_+2) /* (FILE *) -> next file block */ #define FB_DRV (FCB_+4) /* (char) index into driver table */ #define FB_NCP (FCB_+5) /* (char *) -> next character */ #define FB_BUF (FB_NCP+2) /* (char[SLEN]) buffer */ #define FB_ (FB_BUF+SLEN) /* next file block */ %%%%%%%%%% scc/rtl/dtab.c %%%%%%%%%% /* * dtab.c -- driver table with raw disk interface * ats 3/83 */ #include def.h /* TO BE FIXED */ %%%%%%%%%% scc/rtl/end.mac %%%%%%%%%% ; end.mac -- smallC runtime library - last module ; for CP/M ; for MACRO/80 ENTRY _edata ; end of all DSEG ENTRY _eprog ; end of all CSEG ENTRY _end ; end of code and data ENTRY ?30217 ; version reference DSEG ?30217: DB "021783" ; production date _edata: CSEG DB 115,109,97,108,108,67 ; smallC _eprog: _end: END %%%%%%%%%% scc/rtl/fio.c %%%%%%%%%% /* * fio.c -- file driver for CP/M * ats 3/83 */ #define NOCCARGC #include def.h /* TO BE FIXED */ /* * external references */ extern word(), /* CSH /* return word at pointer */ _binit(), /* initialize buffer to EOF character */ _open(), /* BDOS /* connect to existing file */ _romap(), /* return r/o vector */ _setbuf(), /* set DMA address */ _glob(), /* search for first name */ _close(), /* disconnect from file */ _delete(), /* remove file */ _create(), /* make file, connect */ _rread(), /* read random record */ _rzwrite(), /* write random record, zero new block */ _stat(); /* determine file size */ /**** **** CP/M file driver ****/ /* * _fopen connect, get buffer, return given fp or NULL * _fblin input one CP/M sector * _fblout output one CP/M sector * _fseek position to offset, return NULL or -1 * _fclose write last buffer, disconnect, return NULL or EOF * * There is a problem in positioning to end of file, * since CP/M marks this using SUB -- see _fseek. */ FILE_P _fopen(fp,mode) FILE *fp; /* available file block */ char *mode; { int i; switch(*mode) { case 'r': if (_open(fp) >> 2) break; _fblin(fp); /* read first buffer */ return fp; case 'a': case 'w': if (_romap() & 1 << fp[FCB_ET]-1) break; /* disk read only */ _setbuf(fp+FB_BUF); if ((i = _glob(fp)) >> 2 == 0) if (fp[FB_BUF + 32*i + FCB_RO] & 128) break; /* file read only */ else if (*mode == 'a') { if (_open(fp) >> 2) break; /* * issue a trick call to position to * char-EOF without reading first */ if (_fseek(fp, 2, -1,-1, 0,0) == -1) { _close(fp); break; } return fp; } else if (_delete(fp) >> 2) break; /* unable to delete */ if (_create(fp) >> 2) break; /* unable to create */ _binit(fp+FB_BUF); return fp; } fp[FB_FLG] = 0; /* nothing */ return NULL; } INT _fblin(fp) FILE *fp; { int code; _setbuf(fp+FB_BUF); switch(code = _rread(fp)) { case 0: /* read ok */ return NULL; case 1: /* reading unwritten data */ fp[FB_FLG] |= FB_EOF; break; default: /* other error */ fp[FB_FLG] &= ~FB_ERM; fp[FB_FLG] |= code; } return EOF; } INT _fblout(fp) FILE *fp; { int code; _setbuf(fp+FB_BUF); switch(code = _rzwrite(fp)) { case 0: return NULL; case 5: /* directory overflow */ fp[FB_FLG] |= FB_EOF; break; default: /* other error */ fp[FB_FLG] &= ~FB_ERM; fp[FB_FLG] |= code; } return EOF; } INT _fseek(fp,mode,csec,cpos,ssec,spos) FILE *fp; /* to position */ int mode; /* checked to be 0,1,2,8,9,10 */ int csec,cpos; /* current position */ int ssec,spos; /* to be attained, relative for modes 2,10 */ { int *wp; /* for casting */ /* * csec/cpos is current position, * current position was flushed, * now position to end of file * * note that mode==2, csec==-1 will * position to char-EOF without worrying * about buffer contents first. */ _setbuf(fp+FB_BUF); _stat(fp); /* file size to RR */ wp = fp+FCB_RR; switch(mode) { case 0: case 1: case 2: if (*wp == 0) { csec = cpos = 0; wp = fp+FB_NCP; _binit(*wp = fp+FB_BUF); break; } if (--(*wp) != csec) if (_rread(fp)) return -1; /* ouch!!! */ csec = *wp; /* last sector is buffered */ for (cpos = 0; cpos < SLEN; cpos++) if (fp[FB_BUF+cpos] == SUB) break; if (cpos >= SLEN) /* last byte found */ { cpos = 0; *wp = ++csec; wp = fp+FB_NCP; _binit(*wp = fp+FB_BUF); } else { wp = fp+FB_NCP; *wp = fp+FB_BUF + cpos; } if (mode != 2) break; ssec += csec; /* make absolute */ if ((spos += cpos) < 0) { spos += SLEN; --ssec; } else if (spos >= SLEN) { spos -= SLEN; ++ssec; } break; case 10: ssec += *wp; /* make absolute */ spos = 0; /* sector-relative! */ case 8: case 9: csec = *wp; /* buffer end of file */ cpos = 0; wp = fp+FB_NCP; _binit(*wp = fp+FB_BUF); } /* * csec/cpos is end of file * buffer contents reflect this * now position to ssec/spos (absolute) */ if (ssec < 0 || ssec > csec || ssec == csec && spos > cpos) return -1; /* not inside file */ if (ssec != csec) /* i.e., before EOF */ { wp = fp+FCB_RR; *wp = ssec; if (_rread(fp)) return -1; /* ouch!!! */ } wp = fp+FB_NCP; *wp = fp+FB_BUF + spos; return 0; } INT _fclose(fp) FILE *fp; { int result; if (fp[FB_FLG] & FB_OUF && word(fp+FB_NCP) != fp+FB_BUF) result = _fblout(fp); else result = 0; if (_close(fp) >> 2 || result) return EOF; return NULL; } %%%%%%%%%% scc/rtl/ftab.c %%%%%%%%%% /* * ftab.c -- driver table without raw disk interface * ats 3/83 */ #include def.h /* TO BE FIXED */ #define FTAB /**/ /* signal to io.h */ %%%%%%%%%% scc/rtl/io.h %%%%%%%%%% /* * io.h -- disk and file driver tables for CP/M * ats 3/83 */ /* * define... * * FTAB to create a driver table without the raw disk interface. */ /* * C.REL: CRTL DTAB CSH FTAB FIO ... END * * The first external reference to the driver table * is (officially) in CSH, thus FTAB is the default table. * If the user's program contains a reference like * `extern _dopen();' DTAB will instead be included. */ #define NOCCARGC /* * external references */ extern mkdrive(), /* CSH /* convert letter to drive # */ word(), /* return word from pointer */ _binit(), /* set buffer to EOF character */ _bgetchar(), /* read byte from buffer */ _bputchar(), /* write byte to buffer */ _ngetchar(), /* set+return end of file */ _nop(), /* do nothing */ _fopen(), /* FIO /* complete open */ _fblin(), /* read buffer */ _fblout(), /* write buffer */ _fseek(), /* seek */ _fclose(), /* complete close */ _getchar(), /* BDOS /* console read (+echo) */ _rgetchar(), /* reader read */ _putchar(), /* console write (+tab) */ _pputchar(), /* punch write */ _lputchar(), /* printer write */ _romap(); /* return r/o vector */ #ifndef FTAB extern _seldsk(), /* BIOS /* select disk drive */ _sectran(), /* translate sector address */ _settrk(), /* set track */ _setsec(), /* set sector */ _setdma(), /* set DMA address */ _sread(), /* read sector */ _swrite(); /* write sector */ /* special argument to... */ #define SELDSK2 0 /* _seldsk: ignored by Osborne CBIOS */ #define SWRITE 0 /* _swrite: regular write */ #endif /**** **** driver table ****/ /* * _dnm permissible device names, 0-terminated * _dop open &func, NULL if none needed * _drd read byte &func, NULL if not allowed * _dwr write byte &func, NULL if not allowed * _dbr block read &func, NULL if read byte unbuffered * _dbw block write &func, NULL if write byte unbuffered * _dsk seek &func, NULL if not permitted * _dcl close &func, NULL if none needed * * File manager is entry 0, other entries are devices. * Device names are known (in freopen) to be 3 letters. * Disk names are known (in _dopen) to have a legal and * existing drive name as third character. * * con: read/write console, as set by i/o byte * rdr: read reader, as set by i/o byte * pun: write punch, as set by i/o byte * lst: write list device, as set by i/o byte * nul: EOF on read, no operation on write * dka: disk A: under BIOS * dkb: disk B: under BIOS */ /* * Due to bugs in smallC, this is done in assembler. char *_dnm[] ={"", "CON", "RDR", "PUN", "LST", "NUL", "DKA", "DKB", 0}; int (*_dop[])() ={_fopen,NULL, NULL, NULL, NULL, NULL, _dopen,_dopen }; int (*_drd[])() ={_bgetc,_getch,_rgetc,NULL, NULL, _ngetc,_bgetc,_bgetc }; int (*_dwr[])() ={_bputc,_putch,NULL, _pputc,_lputc,_nop, _bputc,_bputc }; int (*_dbr[])() ={_fblin,NULL, NULL, NULL, NULL, NULL, _dblin,_dblin }; int (*_dbw[])() ={_fblou,NULL, NULL, NULL, NULL, NULL, _dblou,_dblou }; int (*_dsk[])() ={_fseek,NULL, NULL, NULL, NULL, NULL, _dseek,_dseek }; int (*_dcl[])() ={_fclos,NULL, NULL, NULL, NULL, NULL, NULL, NULL }; * */ STATIC int _dnm[1]; #asm DSEG ORG _dnm DW ..1 DW ..2 DW ..3 DW ..4 DW ..5 DW ..6 #endasm #ifndef FTAB #asm DW ..7 DW ..8 #endasm #endif #asm DW 0 ..2: DB 'CON' ..1: DB 0 ..3: DB 'RDR',0 ..4: DB 'PUN',0 ..5: DB 'LST',0 ..6: DB 'NUL',0 #endasm #ifndef FTAB #asm ..7: DB 'DKA',0 ..8: DB 'DKB',0 #endasm #endif STATIC int _dop[1]; #asm DSEG ORG _dop DW _fopen DW 0 DW 0 DW 0 DW 0 DW 0 #endasm #ifndef FTAB #asm DW _dopen DW _dopen #endasm #endif int _drd[1]; #asm DSEG ORG _drd DW _bgetcha DW _getchar DW _rgetcha DW 0 DW 0 DW _ngetcha #endasm #ifndef FTAB #asm DW _bgetcha DW _bgetcha #endasm #endif int _dwr[1]; #asm DSEG ORG _dwr DW _bputcha DW _putchar DW 0 DW _pputcha DW _lputcha DW _nop #endasm #ifndef FTAB #asm DW _bputcha DW _bputcha #endasm #endif STATIC int _dbr[1]; #asm DSEG ORG _dbr DW _fblin DW 0 DW 0 DW 0 DW 0 DW 0 #endasm #ifndef FTAB #asm DW _dblin DW _dblin #endasm #endif STATIC int _dbw[1]; #asm DSEG ORG _dbw DW _fblout DW 0 DW 0 DW 0 DW 0 DW 0 #endasm #ifndef FTAB #asm DW _dblout DW _dblout #endasm #endif int _dsk[1]; #asm DSEG ORG _dsk DW _fseek DW 0 DW 0 DW 0 DW 0 DW 0 #endasm #ifndef FTAB #asm DW _dseek DW _dseek #endasm #endif STATIC int _dcl[1]; #asm DSEG ORG _dcl DW _fclose DW 0 DW 0 DW 0 DW 0 DW 0 #endasm #ifndef FTAB #asm DW _dclose DW _dclose #endasm #endif #ifndef FTAB /**** **** CP/M raw disk driver ****/ /* * _dopen connect, get buffer, return given fp or NULL * _dblin input one CP/M sector * _dblout output one CP/M sector * _dseek position to offset, return NULL or -1 * _dclose write last buffer, disconnect, return NULL or EOF * * BUGS: <= 127 sectors/track, <=127 first track, * sectors before first directory track are not translated, * <= 32767 sectors/disk, * _dseek only knows sector-EOF */ #define DSK_DR FCB_ET /* drive #, 0==A, ... */ #define DSK_NM (FCB_FN+2) /* (existing) drive name */ #define DSK_ST FCB_S1 /* sectors/track */ #define DSK_FT FCB_S2 /* first directory track */ #define DSK_XL FCB_DM /* (word) -> translate table */ FILE_P _dopen(fp,mode) FILE *fp; /* available file block */ char *mode; { int *wp; /* for casting */ char *cp; /* for casting */ int i; if ((cp = _seldsk(fp[DSK_DR] = mkdrive(fp+DSK_NM), SELDSK2)) != NULL) { wp = fp+DSK_XL; *wp = word(cp+DHD_XLT); cp = word(cp+DHD_DPB); fp[DSK_ST] = word(cp+DPB_SPT); fp[DSK_FT] = word(cp+DPB_OFF); switch(*mode) { case 'r': if (_dblin(fp)) break; return fp; case 'w': if (_romap() & 1 << fp[DSK_DR]) break; _binit(fp+FB_BUF); return fp; } } fp[FB_FLG] = 0; /* nothing */ return NULL; } STATIC INT _dblio(fp) /* setup for disk i/o */ FILE *fp; { int track, sector; if (_seldsk(fp[DSK_DR], SELDSK2) == NULL) { fp[FB_FLG] &= ~FB_ERM; fp[FB_FLG] |= 1; /* BUG, really */ return EOF; } sector = word(fp+FCB_RR); if ((track = sector/fp[DSK_ST]) >= fp[DSK_FT]) sector = _sectran(sector % fp[DSK_ST], word(fp+DSK_XL)); else sector %= fp[DSK_ST]; _settrk(track); _setsec(sector); _setdma(fp+FB_BUF); return NULL; } INT _dblin(fp) FILE *fp; { if (_dblio(fp)) return EOF; if (_sread()) { fp[FB_FLG] |= FB_EOF; return EOF; } return NULL; } INT _dblout(fp) FILE *fp; { if (_dblio(fp)) return EOF; if (_swrite(SWRITE)) { fp[FB_FLG] |= FB_EOF; return EOF; } return NULL; } INT _dseek(fp,mode,csec,cpos,ssec,spos) FILE *fp; /* to position */ int mode; /* checked to be 0,1,2,8,9,10 */ int csec,cpos; /* current position */ int ssec,spos; /* to be attained, relative for modes 2,10 */ { int *wp; /* for casting */ char *cp; /* for casting */ /* * csec/cpos is current position, * current position was flushed, * now position to end of drive */ if ((cp = _seldsk(fp[DSK_DR], SELDSK2)) == NULL) return -1; /* unknown drive */ wp = fp+FCB_RR; /* set RR */ cp = word(cp+DHD_DPB); /* point to DPB */ *wp = csec = (cp[DPB_BLM]+1) /* sectors/block */ * (word(cp+DPB_DSM)+1) /* blocks/disk */ + word(cp+DPB_OFF) /* system tracks */ * word(cp+DPB_SPT); /* sectors/track cpos = 0; wp = fp+FB_NCP; /* empty buffer */ _binit(*wp = fp+FB_BUF); switch(mode) { case 10: spos = 0; /* sector-relative */ case 2: ssec += csec; /* make absolute */ break; } /* * csec/cpos is end of file * buffer contents reflect this * now position to ssec/spos (absolute) */ if (ssec < 0 || ssec > csec || ssec == csec && spos > cpos) return -1; /* not inside file */ if (ssec != csec) /* i.e., before EOF */ { wp = fp+FCB_RR; *wp = ssec; if (_dblin(fp)) return -1; /* ouch!!! */ } wp = fp+FB_NCP; *wp = fp+FB_BUF + spos; return 0; } INT _dclose(fp) FILE *fp; { if (fp[FB_FLG] & FB_OUF && word(fp+FB_NCP) != fp+FB_BUF) return _dblout(fp); return NULL; } #endif /* ndef FTAB */ %%%%%%%%%% scc/rtl/make.sub %%%%%%%%%% ; smallC runtime library ; ; c?: source($1) object($2) ; get($3) smallC($4) ; macro-80($5) lib-80($6) ; ; ats 2/83 ; ; mkwfield needs is* ; $3 #$$a <$1:c0.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp1=$1:tmp ; ; mkwfilename needs mkwfield ; $3 #$$b <$1:c0.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp2=$1:tmp ; ; mkwfcb needs mkwfilename ; $3 #$$c <$1:c0.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp3=$1:tmp ; ; dumpbit needs putbit printf ; $3 #d <$1:c0.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp4=$1:tmp ; ; dumpdpb needs putchar printf byte ; $3 #e <$1:c0.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp5=$1:tmp $6 $2:clib=$2:tmp1,$2:tmp2,$2:tmp3,$2:tmp4,$2:tmp5/e ; ; dumpfcb needs putchar printf byte ; $3 #f <$1:c0.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp1=$1:tmp ; ; feof ; $3 #$$g <$1:c0.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp2=$1:tmp ; ; ferror ; $3 #$$h <$1:c0.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp3=$1:tmp ; ; clearerr ; $3 #$$i <$1:c0.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp4=$1:tmp ; ; fseek ; $3 #$$j <$1:c0.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp5=$1:tmp $6 $2:tmp=$2:clib,$2:tmp1,$2:tmp2,$2:tmp3,$2:tmp4,$2:tmp5/e era $2:clib.rel ren $2:clib.rel=$2:tmp.rel ; ; rewind needs fseek ; $3 #$$k <$1:c0.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp1=$1:tmp ; ; getchar needs fgetc ; $3 #$$m <$1:c0.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp3=$1:tmp ; ; fgetc needs ungetc ; $3 #$$n <$1:c0.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp4=$1:tmp ; ; ungetc ; $3 #$$o <$1:c0.get >$1:tmp.c $4 $1:tmp.c >$1:tmp.mac $5 $2:tmp5=$1:tmp $6 $2:tmp=$2:clib,$2:tmp1,$2:tmp3,$2:tmp4,$2:tmp5/e era $2:clib.rel ren $2:clib.rel=$2:tmp.rel submit 2 $1 $2 $3 $4 $5 $6 %%%%%%%%%% scc/rtl/printf.c %%%%%%%%%% /* * printf.c -- smallC runtime library for CP/M and MACRO-80 * UN*X compatible printf routines * ats 2/83, adapted from Jim Hendrix' code * rev (treat %??c like %??s) ats 3/83 */ #define NOCCARGC #include def.h /* TO BE FIXED */ /* * globally external things (in csh) */ extern char _fbin[]; /* stdin */ extern char _fbout[]; /* stdout */ extern char _fberr[]; /* stderr */ extern _narg(); /* returns # arguments */ extern abort(); /* terminate on output error */ extern fputc(), fputs(); /* output to file */ extern isdigit(); /* character class */ /* * local definitions */ #define SZ 7 /* output item size */ /* * _pfemit emit one character */ STATIC char *_pfstr; /* sprintf: -> string */ STATIC _pfemit(c, fp) char c; FILE *fp; { if (fp == &_pfstr) *_pfstr++ = c; /* sprintf */ else if (fputc(c, fp) == EOF) { fputs("output error", stderr); abort(); } } /* * _itod nbr to signed decimal string * _itou nbr to unsigned decimal string * _itox nbr to hex string * * width SZ, right adjusted, blank filled, terminated with null byte */ STATIC _itod(nbr, str) int nbr; char str[]; { char sgn; int sz; sz = SZ; if (nbr < 0) { nbr = -nbr; sgn = '-'; } else sgn = ' '; str[--sz] = NUL; while(sz) { str[--sz] = nbr % 10 + '0'; if ((nbr /= 10) == 0) break; } if (sz) str[--sz] = sgn; while (sz > 0) str[--sz] = ' '; } STATIC _itou(nbr, str) int nbr; char str[]; { int lowbit; int sz; sz = SZ; str[--sz] = NUL; while (sz) { lowbit = nbr & 1; nbr = (nbr >> 1) & 32767; /* divide by 2 */ str[--sz] = ((nbr % 5) << 1) + lowbit + '0'; if ((nbr /= 5) == 0) break; } while (sz) str[--sz] = ' '; } STATIC _itox(nbr, str) int nbr; char str[]; { int digit, offset; int sz; sz = SZ; str[--sz] = NUL; while (sz) { digit = nbr & 15; nbr = (nbr >> 4) & 4095; if (digit < 10) offset = '0'; else offset = 'A'-10; str[--sz] = digit + offset; if (nbr == 0) break; } while (sz) str[--sz] = ' '; } /* * _utoi convert unsigned decimal string to integer nbr * returns field size, else ERR on error */ STATIC INT _utoi(decstr, nbr) char *decstr; int *nbr; { int d,t; d = 0; *nbr = 0; while (isdigit(*decstr)) { t = *nbr; t = (10*t) + (*decstr++ - '0'); if (t >= 0 && *nbr < 0) return ERR; d++; *nbr = t; } return d; } /* * _printf do the actual formatting */ STATIC _printf(fp, nxtarg) FILE *fp; /* may be &_pfstr */ int *nxtarg; /* -> format */ { int i, width, prec, preclen, len; char *ctl, *cx, c, right, str[SZ], *sptr, pad; ctl = *nxtarg; while (c = *ctl++) { if (c != '%') { _pfemit(c, fp); continue; } if (*ctl == '%') { _pfemit(*ctl++, fp); continue; } cx = ctl; if (*cx == '-') { right = 0; ++cx; } else right = 1; if (*cx == '0') { pad = '0'; ++cx; } else pad = ' '; if ((i = _utoi(cx, &width)) >= 0) cx += i; else continue; if (*cx == '.') { if ((preclen = _utoi(++cx, &prec)) >= 0) cx += preclen; else continue; } else preclen = 0; sptr = str; i = *--nxtarg; switch (c = *cx++) { case 'c': str[0] = i; str[1] = NUL; break; case 'd': _itod(i, str); break; case 's': sptr = i; break; case 'u': _itou(i, str); break; case 'x': _itox(i, str); break; default: continue; } ctl=cx; /* accept conversion spec */ if (c != 's' && c != 'c') while (*sptr == ' ') ++sptr; len = -1; while (sptr[++len]) ; /* get length */ if ((c == 's' || c == 'c') && len > prec && preclen > 0) len = prec; if (right) while (width-- - len > 0) _pfemit(pad, fp); while (len) { _pfemit(*sptr++, fp); --len; --width; } while (width-- - len > 0) _pfemit(pad, fp); } } /* * printf(format [, arg, ...] ) * fprintf(fp, format [, arg, ...] ) * sprintf(string, format [, arg, ...] ) * * as described by Kernighan and Ritchie * support % [-] [0] [width] [. precision] (c|d|s|u|x) * uses _narg() feature */ printf(argc) int argc; { int i; i = _narg(); _printf(stdout, &argc + i-1); } fprintf(argc) int argc; { int i, *wp; i = _narg(); wp = &argc + i-1; _printf(*wp, wp-1); } sprintf(argc) int argc; { int i, *wp; i = _narg(); wp = &argc + i-1; _pfstr = *wp; _printf(&_pfstr, wp-1); } %%%%%%%%%% end of part 2 %%%%%%%%%%
schrein (03/14/83)
#R:uiucdcs:12600001:uiucdcs:12600003:000:56968 uiucdcs!schrein Mar 12 09:23:00 1983 (smallC V2 CP/M runtime support continued) (part 3) %%%%%%%%%% scc/scc/11.c %%%%%%%%%% /*** * fixes: * * = * not =* * lout has 2 arguments * prompt needs to return 1 for openin... (unused, anyhow) * optimizer by default turned on */ #include "smallc.h" /*** system stuff */ /* ** execution begins here */ main(argc, argv) int argc, *argv; { argcs=argc; argvs=argv; #ifdef DYNAMIC swnext=CCALLOC(SWTABSZ); swend=swnext+((SWTABSZ-SWSIZ)>>1); stage=CCALLOC(STAGESIZE); stagelast=stage+STAGELIMIT; wq=CCALLOC(WQTABSZ*BPW); litq=CCALLOC(LITABSZ); #ifdef HASH macn=CCALLOC(MACNSIZE); cptr=macn-1; while(++cptr < MACNEND) *cptr=0; #endif macq=CCALLOC(MACQSIZE); pline=CCALLOC(LINESIZE); mline=CCALLOC(LINESIZE); #else swend=(swnext=swq)+SWTABSZ-SWSIZ; stagelast=stage+STAGELIMIT; #endif swactive= /* not in switch */ stagenext= /* direct output mode */ iflevel= /* #if... nesting level = 0 */ skiplevel= /* #if... not encountered */ macptr= /* clear the macro pool */ csp = /* stack ptr (relative) */ errflag= /* not skipping errors till ";" */ eof= /* not eof yet */ ncmp= /* not in compound statement */ files= filearg= quote[1]=0; ccode=1; /* enable preprocessing */ wqptr=wq; /* clear while queue */ quote[0]='"'; /* fake a quote literal */ input=input2=EOF; ask(); /* get user options */ openin(); /* and initial input file */ preprocess(); /* fetch first line */ #ifdef DYNAMIC #ifdef HASH symtab=CCALLOC(NUMLOCS*SYMAVG + NUMGLBS*SYMMAX); #else symtab=CCALLOC(NUMLOCS*SYMAVG); /* global space is allocated with each new entry */ #endif #endif #ifdef HASH cptr=STARTGLB-1; while(++cptr < ENDGLB) *cptr=0; #endif glbptr=STARTGLB; glbflag=1; ctext=0; header(); /* intro code */ setops(); /* set values in op arrays */ parse(); /* process ALL input */ outside(); /* verify outside any function */ trailer(); /* follow-up code */ fclose(output); } /* ** process all input text ** ** At this level, only static declarations, ** defines, includes and function ** definitions are legal... */ parse() { while (eof==0) { if(amatch("extern", 6)) dodeclare(EXTERNAL); else if(dodeclare(STATIC)); else if(match("#asm")) doasm(); else if(match("#include"))doinclude(); else if(match("#define")) addmac(); else newfunc(); blanks(); /* force eof if pending */ } } /* ** dump the literal pool */ dumplits(size) int size; { int j, k; k=0; while (k<litptr) { defstorage(size); j=10; while(j--) { outdec(getint(litq+k, size)); k=k+size; if ((j==0)|(k>=litptr)) { nl(); break; } outbyte(','); } } } /* ** dump zeroes for default initial values */ dumpzero(size, count) int size, count; { int j; while (count > 0) { defstorage(size); j=30; while(j--) { outdec(0); if ((--count <= 0)|(j==0)) { nl(); break; } outbyte(','); } } } /* ** verify compile ends outside any function */ outside() { if (ncmp) error("no closing bracket"); } /* ** get run options */ ask() { int i; i=listfp=nxtlab=0; output=stdout; optimize=YES; /* default is to optimize */ alarm=monitor=pause=NO; line=mline; while(getarg(++i, line, LINESIZE, argcs, argvs)!=EOF) { if(line[0]!='-') continue; if((upper(line[1])=='L')&(numeric(line[2]))&(line[3]<=' ')) { listfp=line[2]-'0'; continue; } if(line[2]<=' ') { if(upper(line[1])=='A') { alarm=YES; continue; } if(upper(line[1])=='M') { monitor=YES; continue; } if(upper(line[1])=='O') { optimize=NO; /* switch turns optimizer off */ continue; } if(upper(line[1])=='P') { pause=YES; continue; } } sout("usage: cc [file]... [-m] [-a] [-p] [-l#] [-o]\n", stderr); abort(); } } /* ** get next input file */ openin() { input=EOF; while(getarg(++filearg, pline, LINESIZE, argcs, argvs)!=EOF) { if(pline[0]=='-') continue; if((input=fopen(pline,"r"))==NULL) { lout("open error", stderr); abort(); } files=YES; kill(); return; } if(files++) eof=YES; else input=stdin; kill(); } setops() { op2[00]= op[00]= or; /* heir5 */ op2[01]= op[01]= xor; /* heir6 */ op2[02]= op[02]= and; /* heir7 */ op2[03]= op[03]= eq; /* heir8 */ op2[04]= op[04]= ne; op2[05]=ule; op[05]= le; /* heir9 */ op2[06]=uge; op[06]= ge; op2[07]=ult; op[07]= lt; op2[08]=ugt; op[08]= gt; op2[09]= op[09]= asr; /* heir10 */ op2[10]= op[10]= asl; op2[11]= op[11]= add; /* heir11 */ op2[12]= op[12]= sub; op2[13]= op[13]=mult; /* heir12 */ op2[14]= op[14]= div; op2[15]= op[15]= mod; } %%%%%%%%%% scc/scc/12.c %%%%%%%%%% /*** * fixes: * * eliminate jump to first function * mark code/data sections */ #include "smallc.h" /* ** open an include file */ doinclude() { blanks(); /* skip over to name */ if((input2=fopen(lptr,"r"))==NULL) { input2=EOF; error("open failure on include file"); } kill(); /* clear rest of line */ /* so next read will come from */ /* new file (if open */ } /* ** test for global declarations */ dodeclare(class) int class; { if(amatch("char",4)) { declglb(CCHAR, class); ns(); return 1; } else if((amatch("int",3))|(class==EXTERNAL)) { declglb(CINT, class); ns(); return 1; } return 0; } /* ** delcare a static variable */ declglb(type, class) int type, class; { int k, j; while(1) { if(endst()) return; /* do line */ if(match("*")) { j=POINTER; k=0; } else { j=VARIABLE; k=1; } if (symname(ssname, YES)==0) illname(); if(findglb(ssname)) multidef(ssname); if(match("()")) j=FUNCTION; else if (match("[")) { k=needsub(); /* get size */ j=ARRAY; /* !0=array */ } if(class==EXTERNAL) external(ssname); else j=initials(type>>2, j, k); addsym(ssname, j, type, k, &glbptr, class); if (match(",")==0) return; /* more? */ } } /* ** declare local variables */ declloc(typ) int typ; { int k,j; #ifdef STGOTO if(noloc) error("not allowed with goto"); #endif if(declared < 0) error("must declare first in block"); while(1) { while(1) { if(endst()) return; if(match("*")) j=POINTER; else j=VARIABLE; if (symname(ssname, YES)==0) illname(); /* no multidef check, block-locals are together */ k=BPW; if (match("[")) { k=needsub(); if(k) { j=ARRAY; if(typ==CINT)k=k<<LBPW; } else j=POINTER; } else if(match("()")) j=FUNCTION; else if((typ==CCHAR)&(j==VARIABLE)) k=SBPC; declared = declared + k; addsym(ssname, j, typ, csp - declared, &locptr, AUTOMATIC); break; } if (match(",")==0) return; } } /* ** initialize global objects */ initials(size, ident, dim) int size, ident, dim; { int savedim; litptr=0; if(dim==0) dim = -1; savedim=dim; dsect(); entry(); if(match("=")) { if(match("{")) { while(dim) { init(size, ident, &dim); if(match(",")==0) break; } needtoken("}"); } else init(size, ident, &dim); } if((dim == -1)&(dim==savedim)) { stowlit(0, size=BPW); ident=POINTER; } dumplits(size); dumpzero(size, dim); return ident; } /* ** evaluate one initializer */ init(size, ident, dim) int size, ident, *dim; { int value; if(qstr(&value)) { if((ident==VARIABLE)|(size!=1)) error("must assign to char pointer or array"); *dim = *dim - (litptr - value); if(ident==POINTER) point(); } else if(constexpr(&value)) { if(ident==POINTER) error("cannot assign to pointer"); stowlit(value, size); *dim = *dim - 1; } } /* ** get required array size */ needsub() { int val; if(match("]")) return 0; /* null size */ if (constexpr(&val)==0) val=1; if (val<0) { error("negative size illegal"); val = -val; } needtoken("]"); /* force single dimension */ return val; /* and return size */ } /* ** begin a function ** ** called from "parse" and tries to make a function ** out of the following text ** ** Patched per P.L. Woods (DDJ #52) */ newfunc() { char *ptr; #ifdef STGOTO nogo = /* enable goto statements */ noloc = 0; /* enable block-local declarations */ #endif lastst= /* no statement yet */ litptr=0; /* clear lit pool */ litlab=getlabel(); /* label next lit pool */ locptr=STARTLOC; /* clear local variables */ if(monitor) lout(line, stderr); if (symname(ssname, YES)==0) { error("illegal function or declaration"); kill(); /* invalidate line */ return; } if(ptr=findglb(ssname)) { /* already in symbol table ? */ if(ptr[IDENT]!=FUNCTION) multidef(ssname); else if(ptr[OFFSET]==FUNCTION) multidef(ssname); else ptr[OFFSET]=FUNCTION; /* earlier assumed to be a function */ } else addsym(ssname, FUNCTION, CINT, FUNCTION, &glbptr, STATIC); if(match("(")==0) error("no open paren"); csect(); entry(); locptr=STARTLOC; argstk=0; /* init arg count */ while(match(")")==0) { /* then count args */ /* any legal name bumps arg count */ if(symname(ssname, YES)) { if(findloc(ssname)) multidef(ssname); else { addsym(ssname, 0, 0, argstk, &locptr, AUTOMATIC); argstk=argstk+BPW; } } else {error("illegal argument name");junk();} blanks(); /* if not closing paren, should be comma */ if(streq(lptr,")")==0) { if(match(",")==0) error("no comma"); } if(endst()) break; } csp=0; /* preset stack ptr */ argtop=argstk; while(argstk) { /* now let user declare what types of things */ /* those arguments were */ if(amatch("char",4)) {doargs(CCHAR);ns();} else if(amatch("int",3)) {doargs(CINT);ns();} else {error("wrong number of arguments");break;} } if(statement()!=STRETURN) ret(); if(litptr) { dsect(); printlabel(litlab); col(); dumplits(1); /* dump literals */ } } /* ** declare argument types ** ** called from "newfunc" this routine adds an entry in the ** local symbol table for each named argument ** ** rewritten per P.L. Woods (DDJ #52) */ doargs(t) int t; { int j, legalname; char c, *argptr; while(1) { if(argstk==0) return; /* no arguments */ if(match("*")) j=POINTER; else j=VARIABLE; if((legalname=symname(ssname, YES))==0) illname(); if(match("[")) { /* is it a pointer? */ /* yes, so skip stuff between "[...]" */ while(inbyte()!=']') if(endst()) break; j=POINTER; /* add entry as pointer */ } if(legalname) { if(argptr=findloc(ssname)) { /* add details of type and address */ argptr[IDENT]=j; argptr[TYPE]=t; putint(argtop-getint(argptr+OFFSET, OFFSIZE), argptr+OFFSET, OFFSIZE); } else error("not an argument"); } argstk=argstk-BPW; /* cnt down */ if(endst())return; if(match(",")==0) error("no comma"); } } %%%%%%%%%% scc/scc/13.c %%%%%%%%%% /*** * fixes: * * continue in switch (net.micro 1/27/83) */ #include "smallc.h" /* ** statement parser ** ** called whenever syntax requires a statement ** this routine performs that statement ** and returns a number telling which one */ statement() { if ((ch==0) & (eof)) return; else if(amatch("char",4)) {declloc(CCHAR);ns();} else if(amatch("int",3)) {declloc(CINT);ns();} else { if(declared >= 0) { #ifdef STGOTO if(ncmp > 1) nogo=declared; /* disable goto if any */ #endif csp=modstk(csp - declared, NO); declared = -1; } if(match("{")) compound(); else if(amatch("if",2)) {doif();lastst=STIF;} else if(amatch("while",5)) {dowhile();lastst=STWHILE;} #ifdef STDO else if(amatch("do",2)) {dodo();lastst=STDO;} #endif #ifdef STFOR else if(amatch("for",3)) {dofor();lastst=STFOR;} #endif #ifdef STSWITCH else if(amatch("switch",6)) {doswitch();lastst=STSWITCH;} else if(amatch("case",4)) {docase();lastst=STCASE;} else if(amatch("default",7)) {dodefault();lastst=STDEF;} #endif #ifdef STGOTO else if(amatch("goto", 4)) {dogoto(); lastst=STGOTO;} else if(dolabel()) ; #endif else if(amatch("return",6)) {doreturn();ns();lastst=STRETURN;} else if(amatch("break",5)) {dobreak();ns();lastst=STBREAK;} else if(amatch("continue",8)){docont();ns();lastst=STCONT;} else if(match(";")) errflag=0; else if(match("#asm")) {doasm();lastst=STASM;} else {doexpr();ns();lastst=STEXPR;} } return lastst; } /* ** semicolon enforcer ** ** called whenever syntax requires a semicolon */ ns() { if(match(";")==0) error("no semicolon"); else errflag=0; } compound() { int savcsp; char *savloc; savcsp=csp; savloc=locptr; declared=0; /* may now declare local variables */ ++ncmp; /* new level open */ while (match("}")==0) if(eof) { error("no final }"); break; } else statement(); /* do one */ --ncmp; /* close current level */ csp=modstk(savcsp, NO); /* delete local variable space */ #ifdef STGOTO cptr=savloc; /* retain labels */ while(cptr < locptr) { cptr2=nextsym(cptr); if(cptr[IDENT] == LABEL) { while(cptr < cptr2) *savloc++ = *cptr++; } else cptr=cptr2; } #endif locptr=savloc; /* delete local symbols */ declared = -1; /* may not declare variables */ } doif() { int flab1,flab2; flab1=getlabel(); /* get label for false branch */ test(flab1, YES); /* get expression, and branch false */ statement(); /* if true, do a statement */ if (amatch("else",4)==0) { /* if...else ? */ /* simple "if"...print false label */ postlabel(flab1); return; /* and exit */ } flab2=getlabel(); #ifdef STGOTO if((lastst != STRETURN)&(lastst != STGOTO)) jump(flab2); #else if(lastst != STRETURN) jump(flab2); #endif postlabel(flab1); /* print false label */ statement(); /* and do "else" clause */ postlabel(flab2); /* print true label */ } doexpr() { int const, val; char *before, *start; while(1) { setstage(&before, &start); expression(&const, &val); clearstage(before, start); if(ch != ',') break; bump(1); } } dowhile() { int wq[4]; /* allocate local queue */ addwhile(wq); /* add entry to queue for "break" */ postlabel(wq[WQLOOP]); /* loop label */ test(wq[WQEXIT], YES); /* see if true */ statement(); /* if so, do a statement */ jump(wq[WQLOOP]); /* loop to label */ postlabel(wq[WQEXIT]); /* exit label */ delwhile(); /* delete queue entry */ } #ifdef STDO dodo() { int wq[4], top; addwhile(wq); postlabel(top=getlabel()); statement(); needtoken("while"); postlabel(wq[WQLOOP]); test(wq[WQEXIT], YES); jump(top); postlabel(wq[WQEXIT]); delwhile(); ns(); } #endif #ifdef STFOR dofor() { int wq[4], lab1, lab2; addwhile(wq); lab1=getlabel(); lab2=getlabel(); needtoken("("); if(match(";")==0) { doexpr(); /* expr 1 */ ns(); } postlabel(lab1); if(match(";")==0) { test(wq[WQEXIT], NO); /* expr 2 */ ns(); } jump(lab2); postlabel(wq[WQLOOP]); if(match(")")==0) { doexpr(); /* expr 3 */ needtoken(")"); } jump(lab1); postlabel(lab2); statement(); jump(wq[WQLOOP]); postlabel(wq[WQEXIT]); delwhile(); } #endif #ifdef STSWITCH doswitch() { int wq[4], endlab, swact, swdef, *swnex, *swptr; swact=swactive; swdef=swdefault; swnex=swptr=swnext; addwhile(wq); *(wqptr+WQLOOP-WQSIZ) = 0; needtoken("("); doexpr(); /* evaluate switch expression */ needtoken(")"); swdefault=0; swactive=1; jump(endlab=getlabel()); statement(); /* cases, etc. */ jump(wq[WQEXIT]); postlabel(endlab); sw(); /* match cases */ while(swptr < swnext) { defstorage(CINT>>2); printlabel(*swptr++); /* case label */ outbyte(','); outdec(*swptr++); /* case value */ nl(); } defstorage(CINT>>2); outdec(0); nl(); if(swdefault) jump(swdefault); postlabel(wq[WQEXIT]); delwhile(); swnext=swnex; swdefault=swdef; swactive=swact; } docase() { if(swactive==0) error("not in switch"); if(swnext > swend) { error("too many cases"); return; } postlabel(*swnext++ = getlabel()); constexpr(swnext++); needtoken(":"); } dodefault() { if(swactive) { if(swdefault) error("multiple defaults"); } else error("not in switch"); needtoken(":"); postlabel(swdefault=getlabel()); } #endif #ifdef STGOTO dogoto() { if(nogo > 0) error("not allowed with block-locals"); else noloc = 1; if(symname(ssname, YES)) jump(addlabel()); else error("bad label"); ns(); } dolabel() { char *savelptr; blanks(); savelptr=lptr; if(symname(ssname, YES)) { if(gch()==':') { postlabel(addlabel()); return 1; } else bump(savelptr-lptr); } return 0; } addlabel() { if(cptr=findloc(ssname)) { if(cptr[IDENT]!=LABEL) error("not a label"); } else cptr=addsym(ssname, LABEL, LABEL, getlabel(), &locptr, LABEL); return (getint(cptr+OFFSET, OFFSIZE)); } #endif doreturn() { if(endst()==0) { doexpr(); modstk(0, YES); } else modstk(0, NO); ret(); } dobreak() { int *ptr; if ((ptr=readwhile(wqptr))==0) return; /* no loops open */ modstk((ptr[WQSP]), NO); /* clean up stk ptr */ jump(ptr[WQEXIT]); /* jump to exit label */ } docont() { int *ptr; ptr = wqptr; while (1) { if ((ptr = readwhile(ptr)) == 0) return; if (ptr[WQLOOP]) break; } modstk((ptr[WQSP]), NO); /* clean up stk ptr */ jump(ptr[WQLOOP]); /* jump to loop label */ } doasm() { ccode=0; /* mark mode as "asm" */ while (1) { inline(); if (match("#endasm")) break; if(eof)break; lout(line, output); } kill(); ccode=1; } %%%%%%%%%% scc/scc/21.c %%%%%%%%%% /*** * fixes: * * = * not =* * internal labels start with "." * it is needed in ask() */ #include "smallc.h" junk() { if(an(inbyte())) while(an(ch)) gch(); else while(an(ch)==0) { if(ch==0) break; gch(); } blanks(); } endst() { blanks(); return ((streq(lptr,";")|(ch==0))); } illname() { error("illegal symbol"); junk(); } multidef(sname) char *sname; { error("already defined"); } needtoken(str) char *str; { if (match(str)==0) error("missing token"); } needlval() { error("must be lvalue"); } findglb(sname) char *sname; { #ifdef HASH if(search(sname, STARTGLB, SYMMAX, ENDGLB, NUMGLBS, NAME)) return cptr; #else cptr=STARTGLB; while(cptr < glbptr) { if(astreq(sname, cptr+NAME, NAMEMAX)) return cptr; cptr=nextsym(cptr); } #endif return 0; } findloc(sname) char *sname; { cptr = locptr - 1; /* search backward for block locals */ while(cptr > STARTLOC) { cptr = cptr - *cptr; if(astreq(sname, cptr, NAMEMAX)) return (cptr - NAME); cptr = cptr - NAME - 1; } return 0; } addsym(sname, id, typ, value, lgptrptr, class) char *sname, id, typ; int value, *lgptrptr, class; { if(lgptrptr == &glbptr) { if(cptr2=findglb(sname)) return cptr2; #ifdef HASH if(cptr==0) { error("global symbol table overflow"); return 0; } #else #ifndef DYNAMIC if(glbptr >= ENDGLB) { error("global symbol table overflow"); return 0; } #endif cptr= *lgptrptr; /*** */ #endif } else { if(locptr > (ENDLOC-SYMMAX)) { error("local symbol table overflow"); abort(); } cptr= *lgptrptr; /*** */ } cptr[IDENT]=id; cptr[TYPE]=typ; cptr[CLASS]=class; putint(value, cptr+OFFSET, OFFSIZE); cptr3 = cptr2 = cptr + NAME; while(an(*sname)) *cptr2++ = *sname++; #ifdef HASH if(lgptrptr == &locptr) { *cptr2 = cptr2 - cptr3; /* set length */ *lgptrptr = ++cptr2; } #else *cptr2 = cptr2 - cptr3; /* set length */ *lgptrptr = ++cptr2; #ifdef DYNAMIC if(lgptrptr == &glbptr) CCALLOC(cptr2 - cptr); /* gets allocation error if no more memory */ #endif #endif return cptr; } #ifndef HASH nextsym(entry) char *entry; { entry = entry + NAME; while(*entry++ >= ' '); /* find length byte */ return entry; } #endif /* ** get integer of length len from address addr ** (byte sequence set by "putint") */ getint(addr, len) char *addr; int len; { int i; i = *(addr + --len); /* high order byte sign extended */ while(len--) i = (i << 8) | *(addr+len)&255; return i; } /* ** put integer i of length len into address addr ** (low byte first) */ putint(i, addr, len) char *addr; int i, len; { while(len--) { *addr++ = i; i = i>>8; } } /* ** test if next input string is legal symbol name */ symname(sname, ucase) char *sname; int ucase; { int k;char c; blanks(); if(alpha(ch)==0) return 0; k=0; while(an(ch)) { sname[k]=gch(); if(k<NAMEMAX) ++k; } sname[k]=0; return 1; } /* ** force upper case alphabetics */ upper(c) char c; { /*** */ if((c >= 'a') & (c <= 'z')) return (c - 32); else return c; } /* ** return next avail internal label number */ getlabel() { return(++nxtlab); } /* ** post a label in the program */ postlabel(label) int label; { printlabel(label); col(); nl(); } /* ** print specified number as a label */ printlabel(label) int label; { outstr("."); outdec(label); } /* ** test if given character is alphabetic */ alpha(c) char c; { return (((c>='a')&(c<='z'))|((c>='A')&(c<='Z'))|(c=='_')); } /* ** test if given character is numeric */ numeric(c) char c; { return((c>='0')&(c<='9')); } /* ** test if given character is alphanumeric */ an(c) char c; { return ((alpha(c))|(numeric(c))); } addwhile(ptr) int ptr[]; { int k; ptr[WQSP]=csp; /* and stk ptr */ ptr[WQLOOP]=getlabel(); /* and looping label */ ptr[WQEXIT]=getlabel(); /* and exit label */ if (wqptr==WQMAX) { error("too many active loops"); abort(); } k=0; while (k<WQSIZ) *wqptr++ = ptr[k++]; } delwhile() { if(wqptr > wq) wqptr=wqptr-WQSIZ; } readwhile(ptr) int *ptr; { if (ptr <= wq) { error("out of context"); return 0; } return (ptr-WQSIZ); } white() { /* test for stack/program overlap */ /* primary -> symname -> blanks -> white */ #ifdef DYNAMIC CCAVAIL(); /* abort on stack/symbol table overflow */ #endif if(*lptr==' ') return 1; if(*lptr==9) return 1; return 0; } gch() { int c; if(c=ch) bump(1); return c; } bump(n) int n; { if(n) lptr=lptr+n; else lptr=line; if(ch=nch= *lptr) nch= *(lptr+1); /*** */ } kill() { *line=0; bump(0); } inbyte() { while(ch==0) { if (eof) return 0; preprocess(); } return gch(); } inline() { int k,unit; while(1) { if (input==EOF) openin(); if(eof) return; if((unit=input2)==EOF) unit=input; if(fgets(line, LINEMAX, unit)==NULL) { fclose(unit); if(input2!=EOF) input2=EOF; else input=EOF; } else { bump(0); return; } } } %%%%%%%%%% scc/scc/22.c %%%%%%%%%% /*** * fixes: * * = * not =* */ #include "smallc.h" ifline() { while(1) { inline(); if(eof) return; if(match("#ifdef")) { ++iflevel; if(skiplevel) continue; blanks(); #ifdef HASH if(search(lptr, macn, NAMESIZE+2, MACNEND, MACNBR, 0)==0) #else if(findmac(lptr)==0) #endif skiplevel=iflevel; continue; } if(match("#ifndef")) { ++iflevel; if(skiplevel) continue; blanks(); #ifdef HASH if(search(lptr, macn, NAMESIZE+2, MACNEND, MACNBR, 0)) #else if(findmac(lptr)) #endif skiplevel=iflevel; continue; } if(match("#else")) { if(iflevel) { if(skiplevel==iflevel) skiplevel=0; else if(skiplevel==0) skiplevel=iflevel; } else noiferr(); continue; } if(match("#endif")) { if(iflevel) { if(skiplevel==iflevel) skiplevel=0; --iflevel; } else noiferr(); continue; } if(skiplevel) continue; if(listfp) { if(listfp==output) cout(';', output); lout(line, listfp); } if(ch==0) continue; break; } } keepch(c) char c; { if(pptr<LINEMAX) pline[++pptr]=c; } preprocess() { int k; char c; if(ccode) { line=mline; ifline(); if(eof) return; } else { line=pline; inline(); return; } pptr = -1; while(ch) { if(white()) { keepch(' '); while(white()) gch(); } else if(ch=='"') { keepch(ch); gch(); while((ch!='"')|((*(lptr-1)==92)&(*(lptr-2)!=92))) { if(ch==0) { error("no quote"); break; } keepch(gch()); } gch(); keepch('"'); } else if(ch==39) { keepch(39); gch(); while((ch!=39)|((*(lptr-1)==92)&(*(lptr-2)!=92))) { if(ch==0) { error("no apostrophe"); break; } keepch(gch()); } gch(); keepch(39); } else if((ch=='/')&(nch=='*')) { bump(2); while(((ch=='*')&(nch=='/'))==0) { if(ch) bump(1); else { ifline(); if(eof) break; } } bump(2); } else if(an(ch)) { k=0; while(an(ch)) { if(k<NAMEMAX) msname[k++]=ch; gch(); } msname[k]=0; #ifdef HASH if(search(msname, macn, NAMESIZE+2, MACNEND, MACNBR, 0)) { k=getint(cptr+NAMESIZE, 2); while(c=macq[k++]) keepch(c); } #else if(k=findmac(msname)) while(c=macq[k++]) keepch(c); #endif else { k=0; while(c=msname[k++]) keepch(c); } } else keepch(gch()); } if(pptr>=LINEMAX) error("line too long"); keepch(0); line=pline; bump(0); } noiferr() { error("no matching #if..."); errflag=0; } addmac() { int k; if(symname(msname, NO)==0) { illname(); kill(); return; } k=0; #ifdef HASH if(search(msname, macn, NAMESIZE+2, MACNEND, MACNBR, 0)==0) { if(cptr2=cptr) while(*cptr2++ = msname[k++]); else { error("macro name table full"); return; } } putint(macptr, cptr+NAMESIZE, 2); #else while(putmac(msname[k++])); #endif while(white()) gch(); while(putmac(gch())); if(macptr>=MACMAX) { error("macro string queue full"); abort(); } } putmac(c) char c; { macq[macptr]=c; if(macptr<MACMAX) ++macptr; return c; } #ifdef HASH /* ** search for symbol match ** on return cptr points to slot found or empty slot */ search(sname, buf, len, end, max, off) char *sname, *buf, *end; int len, max, off; { cptr=cptr2=buf+((hash(sname)%(max-1))*len); while(*cptr != 0) { if(astreq(sname, cptr+off, NAMEMAX)) return 1; if((cptr=cptr+len) >= end) cptr=buf; if(cptr == cptr2) return (cptr=0); } return 0; } hash(sname) char *sname; { int i, c; i=0; while(c= *sname++) i=(i<<1)+c; /*** */ return i; } #else findmac(sname) char *sname; { mack=0; while(mack<macptr) { if(astreq(sname,macq+mack,NAMEMAX)) { while(macq[mack++]); return mack; } while(macq[mack++]); while(macq[mack++]); } return 0; } #endif setstage(before, start) int *before, *start; { if((*before=stagenext)==0) stagenext=stage; *start=stagenext; } clearstage(before, start) char *before, *start; { *stagenext=0; if(stagenext=before) return; if(start) { peephole(start); } } outdec(number) int number; { int k,zs; char c; zs = 0; k=10000; if (number<0) { number=(-number); outbyte('-'); } while (k>=1) { c=number/k + '0'; if ((c!='0')|(k==1)|(zs)) { zs=1; outbyte(c); } number=number%k; k=k/10; } } ol(ptr) char ptr[]; { ot(ptr); nl(); } ot(ptr) char ptr[]; { tab(); outstr(ptr); } outstr(ptr) char ptr[]; { /* must work with symbol table names terminated by length */ while(*ptr >= ' ') outbyte(*ptr++); } outbyte(c) char c; { if(stagenext) { if(stagenext==stagelast) { error("staging buffer overflow"); return 0; } else *stagenext++ = c; } else cout(c,output); return c; } cout(c, fd) char c; int fd; { if(fputc(c, fd)==EOF) xout(); } sout(string, fd) char *string; int fd; { if(fputs(string, fd)==EOF) xout(); } lout(line, fd) char *line; int fd; { sout(line, fd); cout('\n', fd); } xout() { fputs("output error\n", stderr); abort(); } nl() { outbyte('\n'); } tab() { outbyte('\t'); } col() { outbyte(':'); } error(msg) char msg[]; { if(errflag) return; else errflag=1; lout(line, stderr); errout(msg, stderr); if(alarm) fputc(7, stderr); if(pause) while(fgetc(stderr)!='\n'); if(listfp>0) errout(msg, listfp); } errout(msg, fp) char msg[]; int fp; { int k; k=line+2; while(k++ <= lptr) cout(' ', fp); lout("/\\", fp); sout("**** ", fp); lout(msg, fp); } streq(str1,str2) char str1[],str2[]; { int k; k=0; while (str2[k]) { if ((str1[k])!=(str2[k])) return 0; ++k; } return k; } astreq(str1,str2,len) char str1[],str2[];int len; { int k; k=0; while (k<len) { if ((str1[k])!=(str2[k]))break; /* ** must detect end of symbol table names terminated by ** symbol length in binary */ if(str1[k] < ' ') break; if(str2[k] < ' ') break; ++k; } if (an(str1[k]))return 0; if (an(str2[k]))return 0; return k; } match(lit) char *lit; { int k; blanks(); if (k=streq(lptr,lit)) { bump(k); return 1; } return 0; } amatch(lit,len) char *lit;int len; { int k; blanks(); if (k=astreq(lptr,lit,len)) { bump(k); while(an(ch)) inbyte(); return 1; } return 0; } nextop(list) char *list; { char op[4]; opindex=0; blanks(); while(1) { opsize=0; while(*list > ' ') op[opsize++]= *list++; /*** */ op[opsize]=0; if(opsize=streq(lptr, op)) if((*(lptr+opsize) != '=')& (*(lptr+opsize) != *(lptr+opsize-1))) return 1; if(*list) { ++list; ++opindex; } else return 0; } } blanks() { while(1) { while(ch) { if(white()) gch(); else return; } if(line==mline) return; preprocess(); if(eof)break; } } %%%%%%%%%% scc/scc/31.c %%%%%%%%%% /*** * fixes: * * testfunc int (*) () not int * oper int (*) () not int * oper2 int (*) () not int * heir int (*) () not int * needs external references to heir*() * plung1 not plunge1 (M80 is stupid!!) * plung2 not plunge2 */ #include "smallc.h" /* ** lval[0] - symbol table address, else 0 for constant ** lval[1] - type of indirect obj to fetch, else 0 for static ** lval[2] - type of pointer or array, else 0 for all other ** lval[3] - true if constant expression ** lval[4] - value of constant expression ** lval[5] - true if secondary register altered ** lval[6] - function address of highest/last binary operator ** lval[7] - stage address of "oper 0" code, else 0 */ /* ** skim over terms adjoining || and && operators */ skim(opstr, testfunc, dropval, endval, heir, lval) char *opstr; int (*testfunc)(), dropval, endval, (*heir)(), lval[]; { /*** */ int k, hits, droplab, endlab; hits=0; while(1) { k=plung1(heir, lval); if(nextop(opstr)) { bump(opsize); if(hits==0) { hits=1; droplab=getlabel(); } dropout(k, testfunc, droplab, lval); } else if(hits) { dropout(k, testfunc, droplab, lval); const(endval); jump(endlab=getlabel()); postlabel(droplab); const(dropval); postlabel(endlab); lval[1]=lval[2]=lval[3]=lval[7]=0; return 0; } else return k; } } /* ** test for early dropout from || or && evaluations */ dropout(k, testfunc, exit1, lval) int k, (*testfunc)(), exit1, lval[]; { /*** */ if(k) rvalue(lval); else if(lval[3]) const(lval[4]); (*testfunc)(exit1); /* jumps on false */ /*** */ } /* ** plunge to a lower level */ plunge(opstr, opoff, heir, lval) char *opstr; int opoff, (*heir)(), lval[]; { /*** */ int k, lval2[8]; k=plung1(heir, lval); if(nextop(opstr)==0) return k; if(k) rvalue(lval); while(1) { if(nextop(opstr)) { bump(opsize); opindex=opindex+opoff; plung2(op[opindex], op2[opindex], heir, lval, lval2); } else return 0; } } /* ** unary plunge to lower level */ plung1(heir, lval) int (*heir)(), lval[]; { /*** */ char *before, *start; int k; setstage(&before, &start); k=(*heir)(lval); if(lval[3]) clearstage(before,0); /* load constant later */ return k; } /* ** binary plunge to lower level */ plung2(oper, oper2, heir, lval, lval2) int (*oper)(), (*oper2)(), (*heir)(), lval[], lval2[]; { /*** */ char *before, *start; setstage(&before, &start); lval[5]=1; /* flag secondary register used */ lval[7]=0; /* flag as not "... oper 0" syntax */ if(lval[3]) { /* constant on left side not yet loaded */ if(plung1(heir, lval2)) rvalue(lval2); if(lval[4]==0) lval[7]=stagenext; const2(lval[4]<<dbltest(lval2, lval)); } else { /* non-constant on left side */ push(); if(plung1(heir, lval2)) rvalue(lval2); if(lval2[3]) { /* constant on right side */ if(lval2[4]==0) lval[7]=start; if(oper==add) { /* may test other commutative operators */ csp=csp+2; clearstage(before, 0); const2(lval2[4]<<dbltest(lval, lval2)); /* load secondary */ } else { const(lval2[4]<<dbltest(lval, lval2)); /* load primary */ smartpop(lval2, start); } } else { /* non-constants on both sides */ smartpop(lval2, start); if((oper==add)|(oper==sub)) { if(dbltest(lval,lval2)) doublereg(); if(dbltest(lval2,lval)) { swap(); doublereg(); if(oper==sub) swap(); } } } } if(oper) { if(lval[3]=lval[3]&lval2[3]) { lval[4]=calc(lval[4], oper, lval2[4]); clearstage(before, 0); lval[5]=0; } else { if((lval[2]==0)&(lval2[2]==0)) { (*oper)(); /*** */ lval[6]=oper; /* identify the operator */ } else { (*oper2)(); /*** */ lval[6]=oper2; /* identify the operator */ } } if(oper==sub) { if((lval[2]==CINT)&(lval2[2]==CINT)) { swap(); const(1); asr(); /** div by 2 **/ } } if((oper==sub)|(oper==add)) result(lval, lval2); } } calc(left, oper, right) int left, (*oper)(), right; { /*** */ if(oper == or) return (left | right); else if(oper == xor) return (left ^ right); else if(oper == and) return (left & right); else if(oper == eq) return (left == right); else if(oper == ne) return (left != right); else if(oper == le) return (left <= right); else if(oper == ge) return (left >= right); else if(oper == lt) return (left < right); else if(oper == gt) return (left > right); else if(oper == asr) return (left >> right); else if(oper == asl) return (left << right); else if(oper == add) return (left + right); else if(oper == sub) return (left - right); else if(oper ==mult) return (left * right); else if(oper == div) return (left / right); else if(oper == mod) return (left % right); else return 0; } expression(const, val) int *const, *val; { int lval[8]; if(heir1(lval)) rvalue(lval); if(lval[3]) { *const=1; *val=lval[4]; } else *const=0; } heir1(lval) int lval[]; { int k,lval2[8], (*oper)(); /*** */ k=plung1(heir3, lval); if(lval[3]) const(lval[4]); if(match("|=")) oper=or; else if(match("^=")) oper=xor; else if(match("&=")) oper=and; else if(match("+=")) oper=add; else if(match("-=")) oper=sub; else if(match("*=")) oper=mult; else if(match("/=")) oper=div; else if(match("%=")) oper=mod; else if(match(">>=")) oper=asr; else if(match("<<=")) oper=asl; else if(match("=")) oper=0; else return k; if(k==0) { needlval(); return 0; } if(lval[1]) { if(oper) { push(); rvalue(lval); } plung2(oper, oper, heir1, lval, lval2); if(oper) pop(); } else { if(oper) { rvalue(lval); plung2(oper, oper, heir1, lval, lval2); } else { if(heir1(lval2)) rvalue(lval2); lval[5]=lval2[5]; } } store(lval); return 0; } heir3(lval) int lval[]; { return skim("||", eq0, 1, 0, heir4, lval); } heir4(lval) int lval[]; { return skim("&&", ne0, 0, 1, heir5, lval); } heir5(lval) int lval[]; { return plunge("|", 0, heir6, lval); } heir6(lval) int lval[]; { return plunge("^", 1, heir7, lval); } heir7(lval) int lval[]; { return plunge("&", 2, heir8, lval); } heir8(lval) int lval[]; { return plunge("== !=", 3, heir9, lval); } heir9(lval) int lval[]; { return plunge("<= >= < >", 5, heir10, lval); } heir10(lval) int lval[]; { return plunge(">> <<", 9, heir11, lval); } heir11(lval) int lval[]; { return plunge("+ -", 11, heir12, lval); } heir12(lval) int lval[]; { return plunge("* / %", 13, heir13, lval); } %%%%%%%%%% scc/scc/32.c %%%%%%%%%% /*** * fixes: * * plung2 not plunge2 * adapt callfunction(_narg) to MACRO-80 CP/M RTL */ #include "smallc.h" heir13(lval) int lval[]; { int k; char *ptr; if(match("++")) { /* ++lval */ if(heir13(lval)==0) { needlval(); return 0; } step(inc, lval); return 0; } else if(match("--")) { /* --lval */ if(heir13(lval)==0) { needlval(); return 0; } step(dec, lval); return 0; } else if (match("~")) { /* ~ */ if(heir13(lval)) rvalue(lval); com(); lval[4] = ~lval[4]; return 0; } else if (match("!")) { /* ! */ if(heir13(lval)) rvalue(lval); lneg(); lval[4] = !lval[4]; return 0; } else if (match("-")) { /* unary - */ if(heir13(lval)) rvalue(lval); neg(); lval[4] = -lval[4]; return 0; } else if(match("*")) { /* unary * */ if(heir13(lval)) rvalue(lval); if(ptr=lval[0])lval[1]=ptr[TYPE]; else lval[1]=CINT; lval[2]=0; /* flag as not pointer or array */ lval[3]=0; /* flag as not constant */ return 1; } else if(match("&")) { /* unary & */ if(heir13(lval)==0) { error("illegal address"); return 0; } ptr=lval[0]; lval[2]=ptr[TYPE]; if(lval[1]) return 0; /* global & non-array */ address(ptr); lval[1]=ptr[TYPE]; return 0; } else { k=heir14(lval); if(match("++")) { /* lval++ */ if(k==0) { needlval(); return 0; } step(inc, lval); dec(lval[2]>>2); return 0; } else if(match("--")) { /* lval-- */ if(k==0) { needlval(); return 0; } step(dec, lval); inc(lval[2]>>2); return 0; } else return k; } } heir14(lval) int *lval; { int k, const, val, lval2[8]; char *ptr, *before, *start; k=primary(lval); ptr=lval[0]; blanks(); if((ch=='[')|(ch=='(')) { lval[5]=1; /* secondary register will be used */ while(1) { if(match("[")) { /* [subscript] */ if(ptr==0) { error("can't subscript"); junk(); needtoken("]"); return 0; } else if(ptr[IDENT]==POINTER)rvalue(lval); else if(ptr[IDENT]!=ARRAY) { error("can't subscript"); k=0; } setstage(&before, &start); lval2[3]=0; plung2(0, 0, heir1, lval2, lval2); /* lval2 deadend */ needtoken("]"); if(lval2[3]) { clearstage(before, 0); if(lval2[4]) { if(ptr[TYPE]==CINT) const2(lval2[4]<<LBPW); else const2(lval2[4]); add(); } } else { if(ptr[TYPE]==CINT) doublereg(); add(); } lval[0]=lval[2]=0; lval[1]=ptr[TYPE]; k=1; } else if(match("(")) { /* function(...) */ if (ptr==0) callfunction(0); else if (ptr[IDENT]!=FUNCTION) { rvalue(lval); callfunction(0); } else callfunction(ptr); k=lval[0]=lval[3]=0; } else return k; } } if(ptr==0) return k; if(ptr[IDENT]==FUNCTION) { address(ptr); return 0; } return k; } primary(lval) int *lval; { char *ptr; int k; if(match("(")) { /* (expression) */ k=heir1(lval); needtoken(")"); return k; } putint(0, lval, 8<<LBPW); /* clear lval array */ if(symname(ssname, YES)) { if(ptr=findloc(ssname)) { #ifdef STGOTO if(ptr[IDENT]==LABEL) { experr(); return 0; } #endif getloc(ptr); lval[0]=ptr; lval[1]=ptr[TYPE]; if(ptr[IDENT]==POINTER) { lval[1]=CINT; lval[2]=ptr[TYPE]; } if(ptr[IDENT]==ARRAY) { lval[2]=ptr[TYPE]; return 0; } else return 1; } if(ptr=findglb(ssname)) if(ptr[IDENT]!=FUNCTION) { lval[0]=ptr; lval[1]=0; if(ptr[IDENT]!=ARRAY) { if(ptr[IDENT]==POINTER) lval[2]=ptr[TYPE]; return 1; } address(ptr); lval[1]=lval[2]=ptr[TYPE]; return 0; } ptr=addsym(ssname, FUNCTION, CINT, 0, &glbptr, STATIC); lval[0]=ptr; lval[1]=0; return 0; } if(constant(lval)==0) experr(); return 0; } experr() { error("invalid expression"); const(0); junk(); } callfunction(ptr) char *ptr; { /* symbol table entry or 0 */ int nargs, const, val; nargs=0; blanks(); /* already saw open paren */ if(ptr==0) push(); /* calling HL */ while(streq(lptr,")")==0) { if(endst()) break; expression(&const, &val); if(ptr==0) swapstk(); /* don't push addr */ push(); /* push argument */ nargs=nargs+BPW; /* count args*BPW */ if (match(",")==0) break; } needtoken(")"); if (! streq(ptr+NAME, "_narg")) loadargc(nargs >> LBPW); if (ptr) call(ptr+NAME); else callstk(); csp=modstk(csp+nargs, YES); } %%%%%%%%%% scc/scc/33.c %%%%%%%%%% /*** * fixes: * * oper int (*) () not int * correct escape sequences in strings */ #include "smallc.h" /* ** true if val1 -> int pointer or int array and val2 not ptr or array */ dbltest(val1,val2) int val1[], val2[]; { if(val1[2]!=CINT) return 0; if(val2[2]) return 0; return 1; } /* ** determine type of binary operation */ result(lval, lval2) int lval[], lval2[]; { if((lval[2]!=0)&(lval2[2]!=0)) { lval[2]=0; } else if(lval2[2]) { lval[0]=lval2[0]; lval[1]=lval2[1]; lval[2]=lval2[2]; } } step(oper, lval) int (*oper)(), lval[]; { /*** */ if(lval[1]) { if(lval[5]) { push(); rvalue(lval); (*oper)(lval[2]>>2); /*** */ pop(); store(lval); return; } else { move(); lval[5]=1; } } rvalue(lval); (*oper)(lval[2]>>2); /*** */ store(lval); } store(lval) int lval[]; { if(lval[1]) putstk(lval); else putmem(lval); } rvalue(lval) int lval[]; { if ((lval[0]!=0)&(lval[1]==0)) getmem(lval); else indirect(lval); } test(label, parens) int label, parens; { int lval[8]; char *before, *start; if(parens) needtoken("("); while(1) { setstage(&before, &start); if(heir1(lval)) rvalue(lval); if(match(",")) clearstage(before, start); else break; } if(parens) needtoken(")"); if(lval[3]) { /* constant expression */ clearstage(before, 0); if(lval[4]) return; jump(label); return; } if(lval[7]) { /* stage address of "oper 0" code */ oper=lval[6];/* operator function address */ if((oper==eq)| (oper==ule)) zerojump(eq0, label, lval); else if((oper==ne)| (oper==ugt)) zerojump(ne0, label, lval); else if (oper==gt) zerojump(gt0, label, lval); else if (oper==ge) zerojump(ge0, label, lval); else if (oper==uge) clearstage(lval[7],0); else if (oper==lt) zerojump(lt0, label, lval); else if (oper==ult) zerojump(ult0, label, lval); else if (oper==le) zerojump(le0, label, lval); else testjump(label); } else testjump(label); clearstage(before, start); } constexpr(val) int *val; { int const; char *before, *start; setstage(&before, &start); expression(&const, val); clearstage(before, 0); /* scratch generated code */ if(const==0) error("must be constant expression"); return const; } const(val) int val; { immed(); outdec(val); nl(); } const2(val) int val; { immed2(); outdec(val); nl(); } constant(lval) int lval[]; { lval=lval+3; *lval=1; /* assume it will be a constant */ if (number(++lval)) immed(); else if (pstr(lval)) immed(); else if (qstr(lval)) { *(lval-1)=0; /* nope, it's a string address */ immed(); printlabel(litlab); outbyte('+'); } else return 0; outdec(*lval); nl(); return 1; } number(val) int val[]; { int k, minus; k=minus=0; while(1) { if(match("+")) ; else if(match("-")) minus=1; else break; } if(numeric(ch)==0)return 0; while (numeric(ch)) k=k*10+(inbyte()-'0'); if (minus) k=(-k); val[0]=k; return 1; } address(ptr) char *ptr; { immed(); outstr(ptr+NAME); nl(); } pstr(val) int val[]; { int k; k=0; if (match("'")==0) return 0; while(ch!=39) k=(k&255)*256 + (litchar()&255); ++lptr; val[0]=k; return 1; } qstr(val) int val[]; { char c; if (match(quote)==0) return 0; val[0]=litptr; while (ch!='"') { if(ch==0) break; stowlit(litchar(), 1); } gch(); litq[litptr++]=0; return 1; } stowlit(value, size) int value, size; { if((litptr+size) >= LITMAX) { error("literal queue overflow"); abort(); } putint(value, litq+litptr, size); litptr=litptr+size; } /* ** return current literal char & bump lptr */ litchar() { int i, oct; if (ch != '\\' || nch == 0) return gch(); gch(); switch(ch) { case 'b': gch(); return 8; /* BS */ case 'f': gch(); return 12; /* FF */ case 'n': gch(); return 10; /* LF */ case 'r': gch(); return 13; /* CR */ case 't': gch(); return 9; /* HT */ } i = 3; oct = 0; while (i-- > 0 && ch >= '0' && ch <= '7') oct = (oct << 3) + gch() - '0'; if (i == 2) return gch(); /* \x is just x */ return oct; } %%%%%%%%%% scc/scc/41.c %%%%%%%%%% /*** * fixes: * * = * not =* * oper int (*) () not int * overhauled for MACRO-80 and CP/M */ #include "smallc.h" header() /* incantations at begin of module */ { ol("EXTRN ?smallC ; smallC for MACRO-80 CP/M"); ol("EXTRN ?30217 ; ats 02/17/83"); /* * linkage boot strap: * * ?smallC is EXTRN in all modules compiled by this compiler * is ENTRY in the outermost runtime routine * which is entered from CP/M * * ?ymmdd is EXTRN in all modules compiled by this compiler * is ENTRY in ?smallC module and controls version dates * * _shell is EXTRN in ?smallC module * is the outermost runtime routine written in smallC * * main is extern in _shell() * and must be supplied by the user, * to be called UN*X-style * * _end is EXTRN in ?smallC module * marks the first byte available to a heap * by being linked absolutely last */ } csect() /* incantations at begin of code */ { ol("CSEG"); } dsect() /* incantations at begin of data */ { ol("DSEG"); } trailer() /* incantations at end of module */ { ol("END"); } loadargc(val) /* the great #arguments trick */ int val; { #ifdef HASH if (search("NOCCARGC", macn, NAMESIZE+2, MACNEND, MACNBR, 0) == 0) #else if (findmac("NOCCARGC") == 0) #endif { ot("MVI A,"); outdec(val); nl(); } } entry() /* define entry point */ { outstr(ssname); outstr("::"); nl(); } external(name) /* declare external reference */ char *name; { ot("EXTRN"); ol(name); } indirect(lval) /* PR = *(PR) */ int lval[]; { if(lval[1] == CCHAR) call("?GCHAR##"); else call("?GINT##"); } getmem(lval) /* PR = memory */ int lval[]; { char *sym; sym = lval[0]; if (sym[IDENT] != POINTER && sym[TYPE] == CCHAR) { ot("LDA "); outstr(sym+NAME); nl(); call("?SXT##"); } else { ot("LHLD "); outstr(sym+NAME); nl(); } } getloc(sym) /* PR = &symbol */ char *sym; { const(getint(sym+OFFSET, OFFSIZE) - csp); ol("DAD SP"); } putmem(lval) /* memory = PR */ int lval[]; { char *sym; sym = lval[0]; if (sym[IDENT] != POINTER && sym[TYPE] == CCHAR) { ol("MOV A,L"); ot("STA "); } else ot("SHLD "); outstr(sym+NAME); nl(); } putstk(lval) /* push = PR */ int lval[]; { if (lval[1] == CCHAR) { ol("MOV A,L"); ol("STAX D"); } else call("?PINT##"); } move() /* SE = PR */ { ol("MOV D,H"); ol("MOV E,L"); } swap() /* SE = PR and PR = SE */ { ol("XCHG;;"); /* peephole() uses trailing ";;" */ } immed() /* PR = value (partial!) */ { ot("LXI H,"); } immed2() /* SE = value (partial!) */ { ot("LXI D,"); } push() /* push = PR */ { ol("PUSH H"); csp -= BPW; } smartpop(lval, start) /* unpush or pop as required */ int lval[]; char *start; { if (lval[5]) pop(); /* secondary was used */ else unpush(start); } unpush(dest) /* replace push by swap */ char *dest; { int i; char *sour; sour = "\tXCHG;;"; /* peephole() uses trailing ";;" */ while (*sour) *dest++ = *sour++; sour = stagenext; while (--sour > dest) /* adjust stack references */ if (streq(sour,"\tDAD SP")) { --sour; i = BPW; while (numeric(*--sour)) if ((*sour -= i) < '0') { *sour += 10; i = 1; } else i = 0; } csp += BPW; } pop() /* SE = pop */ { ol("POP D"); csp += BPW; } swapstk() /* stack = PR and PR = stack */ { ol("XTHL"); } sw() /* switch statement */ { call("?SWITCH##"); } call(sname) /* subroutine call */ char *sname; { ot("CALL "); outstr(sname); nl(); } ret() /* subroutine return */ { ol("RET"); } callstk() /* call subroutine address on stack */ { immed(); outstr("$+5"); nl(); swapstk(); ol("PCHL"); csp += BPW; } jump(label) /* jump to internal label */ int label; { outjmp("JMP",label); } testjump(label) /* test PR, jump if false */ int label; { ol("MOV A,H"); ol("ORA L"); outjmp("JZ",label); } zerojump(oper, label, lval) /* test PR 0, jump of false */ int (*oper)(), label, lval[]; { clearstage(lval[7], 0); /* purge conventional code */ (*oper)(label); } defstorage(size) /* define storage */ int size; { if (size == 1) ot("DB "); else ot("DW "); } point() /* point to following objects */ { ol("DW $+2"); } modstk(newsp, save) /* mod stack pointer to value */ int newsp, save; { int k; if ((k = newsp-csp) == 0) return newsp; if (k >= 0) { if (k < 7) { if (k & 1) { ol("INX SP"); k--; } while (k) { ol("POP B"); k -= BPW; } return newsp; } } if (k < 0) { if (k > -7) { if (k & 1) { ol("DCX SP"); k++; } while (k) { ol("PUSH B"); k += BPW; } return newsp; } } if (save) swap(); const(k); ol("DAD SP"); ol("SPHL"); if (save) swap(); return newsp; } doublereg() /* PR += PR */ { ol("DAD H"); } %%%%%%%%%% scc/scc/42.c %%%%%%%%%% /*** * fixes: * * pp int (*)() not int * overhauled for MACRO-80 CP/M * optimizer corrected (was very wrong) */ #include "smallc.h" add() /* PR += SE */ { ol("DAD D"); } sub() /* PR = SE-PR */ { call("?SUB##"); } mult() /* PR *= SE */ { call("?MULT##"); } div() /* SE %= PR and PR = SE/PR */ { call("?DIV##"); } mod() /* SE /= PR and PR = SE%PR */ { div(); swap(); } or() /* PR |= SE */ { call("?OR##"); } xor() /* PR ^= SE */ { call("?XOR##"); } and() /* PR &= SE */ { call("?AND##"); } lneg() /* PR = !PR */ { call("?LNEG##"); } asr() /* PR = SE >> PR */ { call("?ASR##"); } asl() /* PR = SE << PR */ { call("?ASL##"); } neg() /* PR = -PR */ { call("?NEG##"); } com() /* PR ~PR */ { call("?COM##"); } inc(n) /* PR += n */ int n; { while(1) { ol("INX H"); if (--n < 1) break; } } dec(n) /* PR -= n */ int n; { while(1) { ol("DCX H"); if (--n < 1) break; } } eq() /* == */ { call("?EQ##"); } eq0(label) /* == 0 */ int label; { ol("MOV A,H"); ol("ORA L"); outjmp("JNZ", label); } ne() /* != */ { call("?NE##"); } ne0(label) /* != 0 */ int label; { ol("MOV A,H"); ol("ORA L"); outjmp("JZ", label); } lt() /* (int) < */ { call("?LT##"); } lt0(label) /* (int) < 0 */ int label; { ol("XRA A"); ol("ORA H"); outjmp("JP", label); } le() /* (int) <= */ { call("?LE##"); } le0(label) /* (int) <= 0 */ int label; { ol("MOV A,H"); ol("ORA L"); ol("JZ $+8"); ol("XRA A"); ol("ORA H"); outjmp("JP", label); } gt() /* (int) > */ { call("?GT##"); } gt0(label) /* (int) > 0 */ int label; { ol("XRA A"); ol("ORA H"); outjmp("JM", label); ol("ORA L"); outjmp("JZ", label); } ge() /* (int) >= */ { call("?GE##"); } ge0(label) /* (int) >= 0 */ int label; { ol("XRA A"); ol("ORA H"); outjmp("JM", label); } ult() /* (unsigned) < */ { call("?ULT##"); } ult0(label) /* (unsigned) < 0 */ int label; { outjmp("JMP", label); } ule() /* (unsigned) <= */ { call("?ULE##"); } ugt() /* (unsigned) > */ { call("?UGT##"); } uge() /* (unsigned) >= */ { call("?UGE##"); } outjmp(j, l) /* \t j sp l \n */ char *j; int l; { ot(j); outbyte(' '); printlabel(l); nl(); } /* * pattern compare: * * '*' is a match-all, * first such character matched is returned in 'drop'. * * return value is non-matched pattern position * or end of pattern. * * non-matched string position is also dropped. */ p_eq(str,nstr,pat,drop) char *str; /* to search */ int *nstr; /* really char **, return */ char *pat; /* pattern to search */ char *drop; /* return */ { for (*drop = '\0'; *pat; str++,pat++) if (*str == *pat) continue; else if (*pat == '*') { if (*drop == '\0') *drop = *str; continue; } else break; *nstr = str; return pat; } char p_1[] = "XCHG;;\n\tLXI H,*\n\tDAD SP\n\tCALL ?GINT##\n\tXCHG;;\n"; /* 1 2 3 */ char p_2[] = "DAD SP\n\tMOV D,H\n\tMOV E,L\n\t"; /* 1 2 */ char p_3[] = "CALL ?GINT##\n\t**X H\n\tCALL ?PINT##\n"; /* 1 2 3 */ char p_4[] = "CALL ?GCHAR##\n\t**X H\n\tMOV A,L\n\tSTAX D\n"; /* 1 2 3 */ char p_5[] = "DAD D\n\tPOP D\n\t"; /* 1 2 */ #define p_1_1 (p_1+8) #define p_1_2 (p_1+38) #define p_1_3 (p_1+46) #define p_2_1 (p_2+8) #define p_2_2 (p_2+26) #define _p_3_1 13 #define p_3_1 (p_3+_p_3_1) #define p_3_2 (p_3+21) #define p_3_3 (p_3+34) #define _p_4_1 14 #define p_4_1 (p_4+_p_4_1) #define p_4_2 (p_4+22) #define p_4_3 (p_4+38) #define p_5_1 (p_5+7) #define p_5_2 (p_5+14) peephole(ptr) /* emit stage buffer, replacing some text */ char *ptr; { char ch, *pp, *nptr, *nnptr; while (ch = *ptr++) { if (! optimize /* can turn it totally off */ || ch != '\t') /* \t before ANY mnemonic */ { cout(ch, output); continue; } pp = p_eq(ptr, &nptr, p_1, &ch); if (ch == '0' || ch == '2') { if (pp == p_1_3) { if (ch == '0') pp2(); else pp3(pp2); ptr = nptr; continue; } if (pp >= p_1_2) { ol("XCHG"); if (ch == '0') pp1(); else pp3(pp1); ptr += p_1_2-p_1; continue; } } pp = p_eq(ptr, &nptr, p_1_1, &ch); if (ch == '0' || ch == '2') { if (pp == p_1_3) { ol("XCHG"); if (ch == '0') pp2(); else pp3(pp2); ptr = nptr; continue; } if (pp >= p_1_2) { if (ch == '0') pp1(); else pp3(pp1); ptr += p_1_2-p_1_1; continue; } } if ((pp = p_eq(ptr, &nptr, p_2, &ch)) == p_2_2) { pp = p_eq(nptr, &nnptr, p_3, &ch); if (ch == 'I' || ch == 'D') if (pp == p_3_3) { if (ch == 'D') call("?DECI##"); else call("?INCI##"); ptr = nnptr; continue; } pp = p_eq(nptr, &nnptr, p_4, &ch); if (ch == 'I' || ch == 'D') if (pp == p_4_3) { if (ch == 'D') call("?DECC##"); else call("?INCC##"); ptr = nnptr; continue; } } else if (pp == p_2_1) { if (p_eq(nptr, &nnptr, p_3, &ch) >= p_3_1) { call("?DSGI##"); ptr = nptr + _p_3_1; continue; } if (p_eq(nptr, &nnptr, p_4, &ch) >= p_4_1) { call("?DSGC##"); ptr = nptr + _p_4_1; continue; } } if ((pp = p_eq(ptr, &nptr, p_5, &ch)) == p_5_2) { if (p_eq(nptr, &nnptr, p_3_2, &ch) == p_3_3) { call("?DDPPI##"); ptr = nnptr; continue; } if (p_eq(nptr, &nnptr, p_4_2, &ch) == p_4_3) { call("?DDPPC##"); ptr = nnptr; continue; } } else if (pp == p_5_1) { if (p_eq(nptr, &nnptr, p_3, &ch) >= p_3_1) { call("?DDGI##"); ptr = nptr + _p_3_1; continue; } if (p_eq(nptr, &nnptr, p_4, &ch) >= p_4_1) { call("?DDGC##"); ptr = nptr + _p_4_1; continue; } } if ((pp == p_eq(ptr, &nptr, p_5_1, &ch)) == p_5_2) { if (p_eq(nptr, &nnptr, p_3_2, &ch) == p_3_3) { call("?PDPI##"); ptr = nnptr; continue; } if (p_eq(nptr, &nnptr, p_4_2, &ch) == p_4_3) { call("?PDPC##"); ptr = nnptr; continue; } } cout('\t', output); } } pp1() /* PR = top() */ { ol("POP H"); ol("PUSH H"); } pp2() /* SE = top() */ { ol("POP D"); ol("PUSH D"); } pp3(pp) /* PR or SE = belowtop() */ int (*pp)(); { ol("POP B"); (*pp)(); ol("PUSH B"); } %%%%%%%%%% end of part 3 %%%%%%%%%%
schrein (03/14/83)
#R:uiucdcs:12600001:uiucdcs:12600004:000:44609 uiucdcs!schrein Mar 12 09:23:00 1983 (smallC V2 CP/M runtime support continued) (part 4) %%%%%%%%%% scc/scc/READ_ME %%%%%%%%%% This directory contains a slightly modified version of the original smallC V2 compiler obtained from 'net.sources'. Changes are generally noted; the header file 'smallc.h' is arranged so as to allow separate compilation of each source file. [1234][123].c the smallc V2 compiler misc.c a small amount of fudging the runtime routines smallc.c static (!!) allocation of global variables smallc.h header file, to allow separate compilation c.h header file, to be used with C/80 Now for the bad news: this has not compiled itself -- but that has not even been tried. Nor has it compiled on a UN*X system. It has been compiled using Software Toolwork's C/80 system and Microsoft's MACRO-80. The result was used to compile utilities and runtime support. Major bugs (as far as they have been noted) are listed elsewhere. A major fix is contained in 42.c -- the optimizer has been cleaned up. Since 'calloc' is now part of the runtime support, work could start on making it compile itself, while allocating tables dynamically. The 'wc' utility noted the following: 0xD9E1 4735 572 222 11.c 0x7E6A 6309 780 272 12.c 0x500B 6855 765 314 13.c 0x5A14 5159 729 293 21.c 0x0B7A 7051 782 413 22.c 0x1D8C 6730 882 280 31.c 0x7B5F 4613 505 230 32.c 0x6363 4249 540 224 33.c 0xC33F 4710 806 322 41.c 0x81F7 6150 1037 430 42.c 0x2E43 1073 192 53 c.h 0x169C 1041 191 68 misc.c 0x982B 1429 249 72 smallc.c 0x84D0 10594 1702 530 smallc.h %%%%%%%%%% scc/scc/c.h %%%%%%%%%% /* * c.h -- CP/M C/80 M80 header file * ats 1/83 */ #ifndef cpm #define cpm /* signal CP/M system */ /* * coding standards */ #define HALT exit() /* bad end */ #define EXIT exit() /* good end */ /* * important constants */ #define TRUE 1 /* active truth values */ #define FALSE 0 #define EOF (-1) /* end of file getchar() */ #define NIL (-1) /* null pointer from alloc() */ #define NULL 0 /* no file from fopen() */ /* * bug fixes and kludges */ #define AUTO auto /* locals under recursion */ #define FILE int /* fopen et alia */ #define getc getch /* re-route getc to work right */ #define getchar _getch /* re-route getchar to work right */ #define putc putch /* re-route putc to work right */ /* * standard i/o support */ extern FILE * fin, * fout; #define stdin fin /* standard input */ #define stdout fout /* standard output */ extern FILE * stderr; /* diagnostic output */ /* * printf support */ #define printf prnt_1(),prnt_2 #define fprintf prnt_1(),prnt_3 #define sprintf prnt_1(),prnt_4 #endif /* will be included once */ %%%%%%%%%% scc/scc/misc.c %%%%%%%%%% /* * smallC C/80 runtime routines * ats 1/83 */ /* * getarg * as described by Hendrix * * fgetc * alias for getch -- getchar() or getc() * * fgets * fetch a string using getch() * * fputc * alias for putch -- putchar() or putc() */ #include <c.h> /* C/80 system stuff */ getarg(n, str, maxsz, argc, argv) int n; /* argument index */ char *str; /* argument text */ int maxsz; /* max length */ int argc,*argv; /* from main() */ { register char *dptr, *sptr; register int cnt; if ((n > argc-1) | (n<0)) { str[0] = NULL; return EOF; } cnt=0; dptr=str; sptr=argv[n]; while (*dptr++ = *sptr++) if (++cnt >= maxsz-1) { *dptr = NULL; break; } return cnt; } fgetc(fd) FILE *fd; { #asm JMP getch## fputc:: JMP putch## #endasm } fgets(string, size, fd) char *string; int size; int fd; { register int ch; register char * cp; cp = string; while(--size && (ch = fgetc(fd)) != '\n' && ch != EOF) *cp++ = ch; *cp = '\0'; if (size && ch == EOF && cp == string) return NULL; return string; } %%%%%%%%%% scc/scc/smallc.c %%%%%%%%%% /* * Small-C Compiler Version 2.0 * * Copyright 1982 J. E. Hendrix * rev (adaption to cp/m, macro-80) ats 1/83 */ /* * major changes: * * SEPARATE * eliminated; all parts compile separately * all functions are declared in header file * * LINK * PDS * CMD_LINE * TAB * PHASE2 * OPTIMIZE * COL * UPPER * SMALL_VM * POLL * eliminated; environment is MACRO-80, CP/M * * EXTERN * define it once to allocate global variables * * C80 to enable C/80 specific code: * abort alias for exit * added relevant part of stdio.h here * * CCDDPDP[CI] are too long for preprocessor * rename plunge[12] to plung[12] for MACRO-80 */ /* * major bugs: * * HASH can't define -- eliminates nextsym needed by STGOTO * * must `extern' external functions for MACRO-80 * * very permissive about syntax like `int f*;' * * generates char [10] for char *[10] w/out warning * * doesn't notice lots of duplicate definitions * * very ungraceful about overrunning tables * like switch table or literal pool * * complains about multiple externs to same name * * should not allow MACRO-80 reserved names as global */ /* * major fixes: * * CCDDPDP[CI] are too long for preprocessor * rename plunge[12] to plung[12] for MACRO-80 * * maps \-escapes correctly now * * no longer creates undefined first label * on pure data file */ #define EXTERN /* define globale variables */ #include "smallc.h" %%%%%%%%%% scc/scc/smallc.h %%%%%%%%%% /* * smallc.h -- header file Small-C Compiler Version 2.0 */ #define C80 /* Software Toolworks C/80 V2.0 */ #ifdef C80 #include <c.h> /* C/80 system stuff */ #define abort exit #define ERR (-2) /* extra smallC stdio.h stuff */ #define YES 1 #define NO 0 #endif C80 #ifndef EXTERN #define EXTERN extern /* globals allocated elsewhere */ #else #undef EXTERN #define EXTERN /* globals allocated here */ #endif EXTERN /* * remaining compile options */ #define NOCCARGC /* no calls to CCARGC */ /* #define HASH /* use hash search for macros */ /* #define DYNAMIC /* allocate memory dynamically */ /* * machine dependent parameters */ #define BPW 2 /* bytes per word */ #define LBPW 1 /* log2(BPW) */ #define SBPC 1 /* stack bytes per character */ /* * symbol table format */ #define IDENT 0 #define TYPE 1 #define CLASS 2 #define OFFSET 3 #define NAME 5 #define OFFSIZE (NAME - OFFSET) #define SYMAVG 10 #define SYMMAX 14 /* * symbol table parameters */ #define NUMLOCS 25 #define STARTLOC symtab #define ENDLOC (symtab + NUMLOCS*SYMAVG) #define NUMGLBS 180 #define STARTGLB ENDLOC #define ENDGLB (ENDLOC + (NUMGLBS-1)*SYMMAX) #define SYMTBSZ (NUMLOCS*SYMAVG + NUMGLBS*SYMMAX) /* * System wide name size (for symbols) */ #define NAMESIZE 9 #define NAMEMAX 8 /* * possible entries for "IDENT" */ #define LABEL 0 #define VARIABLE 1 #define ARRAY 2 #define POINTER 3 #define FUNCTION 4 /* * possible entries for "TYPE" * low order 2 bits make type unique within length * high order bits give length of object */ /* LABEL 0 */ #define CCHAR (1 << 2) #define CINT (BPW << 2) /* * possible entries for "CLASS" */ /* LABEL 0 */ #define STATIC 1 #define AUTOMATIC 2 #define EXTERNAL 3 /* * "switch" table */ #define SWSIZ (2*BPW) #define SWTABSZ (25*SWSIZ) /* * "while" statement queue */ #define WQTABSZ 30 #define WQSIZ 3 #define WQMAX (wq + WQTABSZ-WQSIZ) /* * entry offsets in while queue */ #define WQSP 0 #define WQLOOP 1 #define WQEXIT 2 /* * literal pool */ #define LITABSZ 700 #define LITMAX (LITABSZ-1) /* * input line */ #define LINEMAX 100 #define LINESIZE (LINEMAX+1) /* * output staging buffer size */ #define STAGESIZE 800 #define STAGELIMIT (STAGESIZE-1) /* * macro (define) pool */ #ifdef HASH #define MACNBR 90 #define MACNSIZE (90 * (NAMESIZE+2)) #define MACNEND (macn + MACNSIZE) #define MACQSIZE (90 * 5) #else #define MACQSIZE 950 #endif #define MACMAX (MACQSIZE-1) /* * statement types */ #define STIF 1 #define STWHILE 2 #define STRETURN 3 #define STBREAK 4 #define STCONT 5 #define STASM 6 #define STEXPR 7 #define STDO 8 /* compile "do" logic */ #define STFOR 9 /* compile "for" logic */ #define STSWITCH 10 /* compile "switch/case/default" logic */ #define STCASE 11 #define STDEF 12 #define STGOTO 13 /* compile "goto" logic */ /* * miscellaneous storage * to be allocate once by defining EXTERN */ EXTERN char optimize, /* optimize output of staging buffer */ alarm, /* audible alarm on errors? */ monitor, /* monitor function headers? */ pause, /* pause for operator on errors? */ #ifdef DYNAMIC *stage, /* output staging buffer */ *symtab, /* symbol table */ *litq, /* literal pool */ #ifdef HASH *macn, /* macro name buffer */ #endif *macq, /* macro string buffer */ *pline, /* parsing buffer */ *mline, /* macro buffer */ #else stage[STAGESIZE], symtab[SYMTBSZ], litq[LITABSZ], #ifdef HASH macn[MACNSIZE], #endif macq[MACQSIZE], pline[LINESIZE], mline[LINESIZE], swq[SWTABSZ], #endif *line, /* points to pline or mline */ *lptr, /* ptr to either */ *glbptr, /* ptrs to next entries */ *locptr, /* ptr to next local symbol */ *stagenext, /* next addr in stage */ *stagelast, /* last addr in stage */ quote[2], /* literal string for '"' */ *cptr, /* work ptrs to any char buffer */ *cptr2, *cptr3, msname[NAMESIZE], /* macro symbol name array */ ssname[NAMESIZE]; /* static symbol name array */ EXTERN int #ifdef STGOTO nogo, /* > 0 disables goto statements */ noloc, /* > 0 disables block locals */ #endif op[16], /* function addresses of binary operators */ op2[16], /* same for unsigned operators */ opindex, /* index to matched operator */ opsize, /* size of operator in bytes */ swactive, /* true inside a switch */ swdefault, /* default label #, else 0 */ *swnext, /* address of next entry */ *swend, /* address of last table entry */ #ifdef DYNAMIC *wq, /* while queue */ #else wq[WQTABSZ], #endif argcs, /* static argc */ *argvs, /* static argv */ *wqptr, /* ptr to next entry */ litptr, /* ptr to next entry */ macptr, /* macro buffer index */ #ifndef HASH mack, /* variable k for findmac routine */ #endif pptr, /* ptr to parsing buffer */ oper, /* address of binary operator function */ ch, /* current character of line being scanned */ nch, /* next character of line being scanned */ declared, /* # of local bytes declared, else -1 when done */ iflevel, /* #if... nest level */ skiplevel, /* level at which #if... skipping started */ nxtlab, /* next avail label # */ litlab, /* label # assigned to literal pool */ csp, /* compiler relative stk ptr */ argstk, /* function arg sp */ argtop, ncmp, /* # open compound statements */ errflag, /* non-zero after 1st error in statement */ eof, /* set non-zero on final input eof */ input, /* fd # for input file */ input2, /* fd # for "include" file */ output, /* fd # for output file */ files, /* non-zero if file list specified on cmd line */ filearg, /* cur file arg index */ glbflag, /* non-zero if internal globals */ ctext, /* non-zero to intermix c-source */ ccode, /* non-zero while parsing c-code */ /* zero when passing assembly code */ listfp, /* file pointer to list device */ lastst, /* last executed statement type */ *iptr; /* work ptr to any int buffer */ /* * global declarations for all functions */ /* * 11.c */ int main(), parse(), /* process all input text */ dumplits(), /* dump literal pool *l dumpzero(), /* dump zeros for default initial values */ outside(), /* verify compile ends outside any function */ ask(), /* get runtime options */ openin(), /* open next input file */ setops(), /* initialize op arrays */ /* * 12.c */ doinclude(), /* open include file */ dodeclare(), /* test for global declarations */ declglb(), /* declare a static variable */ declloc(), /* declare local variables */ initials(), /* initialize global objects */ init(), /* evaluate one initializer */ needsub(), /* get required array size */ newfunc(), /* begin a function */ doargs(), /* declare argument types */ /* * 13.c */ statement(), /* statement parser */ ns(), /* semicolon enforcer */ compound(), doif(), doexpr(), dowhile(), #ifdef STDO dodo(), #endif #ifdef STFOR dofor(), #endif #ifdef STSWITCH doswitch(), docase(), dodefault(), #endif #ifdef STGOTO dogoto(), dolabel(), addlabel(), #endif doreturn(), dobreak(), docont(), doasm(), /* * 21.c */ junk(), endst(), illname(), multidef(), needtoken(), needlval(), findglb(), findloc(), addsym(), #ifndef HASH nextsym(), #endif getint(), /* get int from addr */ putint(), /* put int to addr */ symname(), /* test if next input legal symbol name */ upper(), /* force alpha upper case */ getlabel(), /* next avail internal label */ postlabel(), /* post a label in the program */ printlabel(), /* print number as a label */ alpha(), /* test if char is alpha */ numeric(), /* test if char is numeric */ an(), /* test if character is alphanumeric */ addwhile(), delwhile(), readwhile(), white(), /* test for stack/program overlap */ gch(), bump(), kill(), inbyte(), inline(), /* * 22.c */ ifline(), keepch(), preprocess(), noiferr(), addmac(), putmac(), #ifdef HASH search(), hash(), #else findmac(), #endif setstage(), clearstage(), outdec(), ol(), ot(), outstr(), outbyte(), cout(), sout(), lout(), xout(), nl(), tab(), col(), error(), errout(), streq(), astreq(), match(), amatch(), nextop(), blanks(), /* * 31.c */ skim(), /* skim over terms adjoining || and && */ dropout(), /* early dropout from || && */ plunge(), /* plunge to a lower level */ plung1(), /* unary plunge to lower level */ plung2(), /* binary plunge to lower level */ calc(), expression(), heir1(), heir3(), heir4(), heir5(), heir6(), heir7(), heir8(), heir9(), heir10(), heir11(), heir12(), /* * 32.c */ heir13(), heir14(), primary(), experr(), callfunction(), /* * 33.c */ dbltest(), /* true if val1->int ptr or int[], val2 not ptr [] */ result(), /* determine type of binary op */ step(), store(), rvalue(), test(), constexpr(), const(), const2(), constant(), number(), address(), pstr(), qstr(), stowlit(), litchar(), /* return current literal, bump lit ptr */ /* * 41.c */ header(), /* print all assembler info first */ csect(), /* code segment */ dsect(), /* data segment */ trailer(), /* assembler stuff at end */ loadargc(), /* load # args before fct call */ entry(), /* decl entry */ external(), /* decl external reference */ indirect(), /* fetch obj indirect to primary reg */ getmem(), /* static mem to primary */ getloc(), /* symbol addr to primary */ putmem(), /* primary to static */ putstk(), /* put on stack type obj in primary */ move(), /* primary to secondary */ swap(), /* swap primary and secondary */ immed(), /* partial instr. to get immediate val to primary */ immed2(), /* partial instr to get immediate to secondary */ push(), /* primary to stack */ smartpop(), /* unpush or pop as required */ unpush(), /* replace push by swap */ pop(), /* pop stack to secondary */ swapstk(), /* swap primary and stack */ sw(), /* process switch */ call(), /* call subroutine */ ret(), /* return from subroutine */ callstk(), /* subroutine call to val on stack */ jump(), /* jump to internal label */ testjump(), /* test primary, jump if false */ zerojump(), /* test primary against zero, jump if false */ defstorage(), /* define storage */ point(), /* point to following object */ modstk(), /* modify staack pointer to value */ doublereg(), /* double primary reg */ /* * 42.c */ /* operators */ add(), sub(), mult(), div(), mod(), or(), xor(), and(), lneg(), asr(), asl(), neg(), com(), inc(), dec(), eq(), eq0(), ne(), ne0(), lt(), lt0(), le(), le0(), gt(), gt0(), ge(), ge0(), ult(), ult0(), ule(), ugt(), uge(), outjmp(), /* emit jump to internal label */ peephole(), pp1(), pp2(), pp3(); %%%%%%%%%% scc/status %%%%%%%%%% 3-04-83 Bugs in code generation for pointers. 1) int *p; p = p | 1; This should actually be illegal (you cannot use OR on a pointer), but it is accepted, and the OR is with 2 (two) not 1 (one)!! Due, of course, to the fact that arithmetic with pointers is meant to be scaled... 2) int *p, *q; p-q The value 'p-q', assuming that p points to a higher address than q, cannot be negative. But since it is computed by first subtracting and then arithmetically shifting, it is, sometimes... This is a problem, if you try to compute free space between the top of the program and the stack. 2-25-83 Bug in function calls. int i, v[5]; f() { (i)(); LHLD H,i call address in HL (v[5])(); LXI H,v LXI D,10 DAD D call address in HL (v+5)(); LXI H,v LXI D,10 CALL CCDDGI call address in HL } Code in the first case is expected (abuse of "int" as "int (*)()"), code in the second and third case is reversed. In effect, function pointers can only be used from int variables, not from array elements. 2-21-83 Status of smallC under CP/M. I now have a runtime support to run smallC programs under CP/M. This includes interfaces to all BDOS calls, and a very UNIX-compatible I/O library (FILE * is with us...). Missing at this point is dynamic memory allocation and seeking in files, both yet to be done. I have not yet let the compiler compile itself, but I did note the bugs (and some fixes) as indicated in the following list. I do, therefore, not share Cain's enthusiasm in the February issue of DDJ. --- BUG list --- BUG: Compiler complains about multiple 'extern' definitions of the same name. IMPACT: Cosmetic only. BUG: Compiler calls external() routine when 'extern' is seen. IMPACT: Depends on the assembler used. If it does not like global symbols to be defined in a file where they are also made external, there will be problems. BUG: Compiler transmits global names from source to assembler file. IMPACT: Depends on assembler. If it has names (e.g., for registers) predefined, or if it silently uses shorter names, there are problems. BUG: Switch table and literal pool overruns cause compiler to crash very ungracefully. IMPACT: Error message (missing token) is quite misleading. BUG: Maps escape sequences '\r' silently to 'r', and '\n' to 13, i.e., does not know RETURN and maps NEWLINE as RETURN. IMPACT: Incompatible with C definition, surprising in the case of '\n'. FIX: Obvious in litchar(). BUG: If source file does not contain a function, a jump to an undefined label is generated. This jump is in any case not necessary. IMPACT: Largely cosmetic, wastes space, however. FIX: Eliminate global variables beglab and func1, eliminate jump generation in header(), and label generation in newfunc(). BUG: An array of pointers to character is silently turned into an array of character, initialization is 'adjusted' accordingly. I.e., char *arr[] ={ "abc", "def", "ghi" }; will become an array of 12 characters. IMPACT: Major, since completely wrong code is generated. BUG: Function name cannot be initializer. I.e., extern f(); int arr[] ={ f }; is flagged as not containing a constant. IMPACT: Minor - was probably a desing choice. BUG: Cannot take address of array name. I.e., int arr[10]; ... &arr is flagged. IMPACT: Minor - the address operator in this case is wrong, but cc and pcc were kind enough to forgive. BUG: Cannot define HASH feature - eliminates nextsym() routine. BUG: Very permissive (without reports) about syntax errors in declarations, e.g., int f*; IMPACT: Not minor - code stability becomes a problem! BUG: Very permissive about duplicate and undefined names. IMPACT: Major - possibly compounded by the assembler. E.g., MACRO-80 has an (unadvertised) feature to turn NUL and NULL into -1. Multiply defined names are usually caught by the assembler. BUG: The peephole() optimizer demolishes fetches from the stack, as indicated by the code sequences below. It only works correctly, if a fetch is not followed by a swap (XCHG;;) but there are trivial examples, where this is not the case. IMPACT: Major - invalidates code generation if OPTIMIZE is included. (Note: not specifying the -o switch to smallC will not make the problem go away, since this optimization is always performed.) FIX: Involved. Basically, all 8 possible patterns from [XCHG] LOAD [XCHG] can be replaced by PUSH/POP and XCHG sequences individually. I revised the optimizer for the case TAB (can only be 9, anyhow), using a tree-structured pattern selection path and a simple routine to compare pattern and staging buffer. BAD PATTERNS: HL DE -------------------------------- original x y -------------------------------- after LXI H,# DAD SP CALL CCGINT (sp+#) y XCHG y (sp+#) -------------------------------- after POP D PUSH D x (sp+0) -------------------------------- after POP B POP D PUSH D PUSH B x (sp+2) -------------------------------- after POP H PUSH H (sp+0) y -------------------------------- after POP B POP H PUSH H PUSH B (sp+2) y -------------------------------- %%%%%%%%%% scc/uty/READ_ME %%%%%%%%%% This directory holds some utilities and exercising programs to be compiled by smallC V2 and run under CP/M with the 'csh' environment. bdos exercise BDOS calls from command line bios exercise BIOS calls from command line cat like UN*X cat, '-h' inserts file names prior to each file cmp like UN*X cmp; conditionalized to also produce 'cp' entab insert \t for multiple spaces get unarchive the runtime library hex dump anything -- including naked disk wc like UN*X wc, '-v' computes sum of non-white-space See and understand the sources for more information. Verify numbers produced by 'wc' are as follows: 0xE460 7124 806 378 bdos.c 0x932E 2639 294 148 bios.c 0x45F0 1221 185 73 cat.c 0xF233 2853 435 172 cmp.c 0x7F2B 2493 403 139 entab.c 0x5ED5 1297 224 72 get.c 0x2D37 3016 516 167 hex.c 0x8A51 1534 255 95 wc.c %%%%%%%%%% scc/uty/bdos.c %%%%%%%%%% /* * bdos.c -- exercise smallC CP/M BDOS calls * ats 2/83 */ extern printf(), atoi(), isascii(), isupper(), islower(), isdigit(), isspace(), toupper(), mkdrive(), mkfilename(), mkfcb(), mkwfcb(), dumpbit(), dumpdpb(), dumpfcb(), byte(), puthex(), _exit(), _end, abort(), _getchar(), _putchar(), _rgetchar(), _pputchar(), _lputchar(), _dirio(), _giob(), _siob(), _puts(), _gets(), _cstat(), _vers(), _reset(), _mount(), _open(), _close(), _glob(), _nglob(), _delete(), _read(), _write(), _create(), _rename(), _login(), _drive(), _setbuf(), _bitmap(), _protect(), _romap(), _chmod(), _diskmap(), _uid(), _rread(), _rwrite(), _stat(), _record(), _umount(), _rzwrite(); extern char _fbout[]; #define stdout (_fbout) /* standard output */ #define LEN 128 /* buffer size */ #define NUL 0 /* null character */ #define ERR (-2) /* error return */ char *f1 = "\n", *f2 = " = %x\n", *f3 = "\7syntax: %s\n", *f4 = " = %x\t"; main(argc,argv) int argc; int *argv; /* char ** */ { char *cp; int *ip; int i; char buf[LEN]; char fcb[36]; while (--argc) { i = atoi(*++argv); if (0 <= i && i < 20) switch (i) { /* split switch */ case 0: abort(); case 1: printf("_getchar() "); printf("%c\n", _getchar()); break; case 2: if (!--argc) _exit(); cp = *++argv; printf("_putchar(%c)\n", *cp); _putchar(*cp); printf(f1); break; case 3: printf("_rgetchar() "); printf("%c\n", _rgetchar()); break; case 4: if (!--argc) _exit(); cp = *++argv; printf("_pputchar(%c)\n", *cp); _pputchar(*cp); printf(f1); break; case 5: if (!--argc) _exit(); cp = *++argv; printf("_lputchar(%c)\n", *cp); _lputchar(*cp); printf(f1); break; case 6: if (!--argc) _exit(); i = atoi(*++argv); printf("_dirio(%d) ", i); printf(f2, _dirio(i)); break; case 7: printf("_giob()"); printf(f2, _giob()); break; case 8: if (!--argc) _exit(); i = atoi(*++argv); printf("_siob(%x)", i); _siob(i); printf(f1); break; case 9: if (!--argc) _exit(); cp = *++argv; printf("_puts(%s)\n", cp); _puts(cp); printf(f1); break; case 10: printf("_gets() "); buf[0] = LEN-3; _gets(buf); buf[2+buf[1]] = NUL; printf("\n%d %d %s\n", buf[0], buf[1], buf+2); break; case 11: printf("_cstat()"); printf(f2, _cstat()); break; case 12: printf("_vers()"); printf(f2, _vers()); break; case 13: printf("_reset()"); _reset(); printf(f1); break; case 14: if (!--argc) _exit(); i = mkdrive(*++argv); if (i < 0 || i > 1) printf(f3,*argv); else { printf("_mount(%d)", i); printf(f2, _mount(i)); } break; case 15: if (!--argc) _exit(); if (mkfcb(fcb,*++argv) == ERR) printf(f3, *argv); else { printf("_open(FCB)"); printf(f2, i = _open(fcb)); dumpfcb(fcb); } break; case 16: printf("_close(FCB)"); printf(f2, i = _close(fcb)); break; case 17: newbuf(buf,0); if (!--argc) _exit(); if (mkwfcb(fcb,*++argv) == ERR) printf(f3, *argv); else { printf("_glob(FCB)"); printf(f2, i = _glob(fcb)); dircode(i,buf); } break; case 18: _setbuf(buf); printf("_nglob()"); printf(f2, i = _nglob()); dircode(i,buf); break; case 19: if (!--argc) _exit(); if (mkwfcb(fcb,*++argv) == ERR) printf(f3, *argv); else { printf("_delete(FCB)"); printf(f2, i = _delete(fcb)); } break; } else if (20 <= i && i < 38 || i == 40) switch(i) { case 20: if (!--argc) _exit(); for (i = atoi(*++argv); i>0; i--) { newbuf(buf,0); printf("_read(FCB)"); printf(f4, _read(fcb)); puthex(buf,buf,LEN,stdout); } dumpfcb(fcb); break; case 21: if (!--argc) _exit(); for (i = atoi(*++argv); i>0; i--) { newbuf(buf, fcb[32]); printf("_write(FCB)"); printf(f4, _write(fcb)); puthex(buf,buf,LEN,stdout); } dumpfcb(fcb); break; case 22: if (!--argc) _exit(); if (mkfcb(fcb,*++argv) == ERR) printf(f3, *argv); else { printf("_create(FCB)"); printf(f2, i = _create(fcb)); } break; case 23: if (!--argc) _exit(); if (mkfcb(fcb,*++argv) == ERR) printf(f3, *argv); else if (!--argc) _exit(); else if (mkfilename(fcb+16,*++argv) == ERR) printf(f3, *argv); else { printf("_rename(FCB)"); printf(f2, i = _rename(fcb)); } break; case 24: printf("_login()"); printf(f2, _login()); break; case 25: printf("_drive()"); printf(f2, _drive()); break; case 26: if (!--argc) _exit(); if ((cp = atoi(*++argv)) < &_end) printf("\7overlaps program\n"); else { printf("_setbuf(%x)", cp); _setbuf(cp); printf(f1); } break; case 27: printf("_bitmap()"); printf(f2, cp = _bitmap()); dumpbit(cp); break; case 28: printf("_protect()"); _protect(); printf(f1); break; case 29: printf("_romap()"); printf(f2, _romap()); break; case 30: if (!--argc) _exit(); if (mkfcb(fcb,*++argv) == ERR) printf(f3, *argv); else if (!--argc) _exit(); else { i = atoi(*++argv); printf("_chmod(%d)",i); if (i&1) fcb[9] |= 128; else fcb[9] &= ~128; if (i&2) fcb[10] |= 128; else fcb[10] &= ~128; printf(f2, i = _chmod(fcb)); dumpfcb(fcb); } break; case 31: printf("_diskmap()"); printf(f2, cp = _diskmap()); dumpdpb(cp); break; case 32: if (!--argc) _exit(); i = atoi(*++argv); printf("_uid(%x)", i); printf(f2, _uid(i)); break; case 33: if (!--argc) _exit(); ip = fcb+33; /* FCB_RR */ *ip = atoi(*++argv); fcb[35] = 0; /* FCB_OV */ newbuf(buf,0); printf("_rread(FCB)"); printf(f4, _rread(fcb)); puthex(buf,buf,LEN,stdout); dumpfcb(fcb); break; case 34: if (!--argc) _exit(); ip = fcb+33; *ip = atoi(*++argv); fcb[35] = 0; newbuf(buf, *ip); printf("_rwrite(FCB)"); printf(f4, _rwrite(fcb)); puthex(buf,buf,LEN,stdout); dumpfcb(fcb); break; case 35: if (!--argc) _exit(); if (mkfcb(fcb,*++argv) == ERR) printf(f3, *argv); else { printf("_stat(FCB)"); _stat(fcb); printf(f1); dumpfcb(fcb); } break; case 36: printf("_record(FCB)"); _record(fcb); printf(f1); dumpfcb(fcb); break; case 37: if (!--argc) _exit(); i = atoi(*++argv); printf("_umount(%x)", i); printf(f2, _umount(i)); break; case 40: if (!--argc) _exit(); ip = fcb+33; *ip = atoi(*++argv); fcb[35] = 0; newbuf(buf, *ip); printf("_rzwrite(FCB)"); printf(f4, _rzwrite(fcb)); puthex(buf,buf,LEN,stdout); dumpfcb(fcb); break; } else printf("\7%d??\n",i); } } newbuf(buf,v) /* clear and set buffer for DMA */ char buf[LEN]; /* buffer */ int v; /* value to initial */ { int i; for (i=0; i<LEN; i++) buf[i] = v; _setbuf(buf); } dircode(i,buf) /* display directory code fcb */ int i; char *buf; { if (0 <= i && i < 4) dumpfcb(buf+32*i); } %%%%%%%%%% scc/uty/bios.c %%%%%%%%%% /* * bios.c -- exercise smallC CP/M BIOS calls * ats 2/83 */ extern atoi(), printf(), _exit(), _end, dumpbit(), dumpdpb(), dumpdhd(), puthex(), _wboot(), _const(), _conin(), _conout(), _lstout(), _punout(), _rdrin(), _home(), _seldsk(), _settrk(), _setsec(), _setdma(), _sread(), _swrite(), _lstst(), _sectran(); extern char _fbout[]; #define stdout (_fbout) /* standard output */ #define LEN 128 /* buffer size */ char *f1 = "[done]\n", *f2 = " = %x\n"; main(argc,argv) int argc; int *argv; /* char ** */ { char *cp; int i,j; char buf[LEN]; while (--argc) { switch(i = atoi(*++argv)) { default: printf("%d??\n", i); break; case 3: printf("_wboot()"); _wboot(); printf(f1); break; case 6: printf("_const()"); printf(f2, _const()); break; case 9: printf("_conin() "); printf("%c\n", _conin()); break; case 12: if (! --argc) _exit(); cp = *++argv; printf("_conout(%c)\n", *cp); _conout(*cp); printf(f1); break; case 15: if (! --argc) _exit(); cp = *++argv; printf("_lstout(%c)\n", *cp); _lstout(*cp); printf(f1); break; case 18: if (! --argc) _exit(); cp = *++argv; printf("_punout(%c)\n", *cp); _punout(*cp); printf(f1); break; case 21: printf("_rdrin() "); printf("%c\n", _rdrin()); break; case 24: printf("_home()"); _home(); printf(f1); break; case 27: if (! --argc) _exit(); i = atoi(*++argv); if (! --argc) _exit(); j = atoi(*++argv); printf("_seldsk(%d,%d)",i,j); printf(f2, cp = _seldsk(i,j)); if (cp) dumpdhd(cp); break; case 30: if (! --argc) _exit(); i = atoi(*++argv); printf("_settrk(%d)", i); _settrk(i); printf(f1); break; case 33: if (! --argc) _exit(); i = atoi(*++argv); printf("_setsec(%d)", i); _setsec(i); printf(f1); break; case 36: if (!--argc) _exit(); if ((cp = atoi(*++argv)) < &_end) printf("%04x overlaps program\n", cp); else { printf("_setdma(%x)", cp); _setdma(cp); printf(f1); } break; case 39: _setdma(buf); printf("_sread()"); printf(f2, _sread()); puthex(buf,buf,LEN,stdout); break; case 42: if (! --argc) _exit(); i = atoi(*++argv); _setdma(buf); printf("_swrite(%d)",i); printf(f2, _swrite(i)); break; case 45: printf("_lstst()"); printf(f2,_lstst()); break; case 48: if (! --argc) _exit(); i = atoi(*++argv); if (! --argc) _exit(); j = atoi(*++argv); printf("_sectran(%d,%04x)", i,j); printf(" = %d\n", _sectran(i,j)); break; } } } %%%%%%%%%% scc/uty/cat.c %%%%%%%%%% /* * cat.c - file concatenation * ats 3/83 */ #define FILE char #define NULL 0 #define NUL 0 #define EOF (-1) #define stdin (_fbin) #define stdout (_fbout) #define stderr (_fberr) extern char _fbin[], _fbout[], _fberr[]; #define HALT exit() #define EXIT exit() extern exit(); extern fputs(), fopen(), fclose(), strcmp(), fgetc(), putchar(); char usage[] = "cat [-h] [from]..."; char hflag = 0; main(argc,argv) int argc; int *argv; /* really char ** */ { char *cp; /* for casting */ FILE *in; while (--argc) { cp = *++argv; if (*cp != '-' || *++cp == NUL) break; switch(*cp) { case 'h': ++hflag; break; default: fputs(usage, stderr); HALT; } } if (argc == 0) docat(stdin, stdout, "stdin"); else do { if (strcmp(*argv, "-") == 0) docat(stdin, stdout, *argv); else if ((in = fopen(*argv, "r")) == NULL) { fputs("cannot read ", stderr); fputs(*argv, stderr); } else { docat(in, stdout, *argv); fclose(in); } ++argv; } while (--argc); } docat(in, out, inn) FILE *in, *out; char * inn; { int ch; if (hflag) { fputs("%%%%% ", stdout); fputs(inn, stdout); fputs(" %%%%%\n", stdout); } while ((ch = fgetc(in)) != EOF) putchar(ch); } %%%%%%%%%% scc/uty/cmp.c %%%%%%%%%% /* * cmp.c - file copy and comparison * rev (smallC) ats 3/83 */ /* * define... * * CP to make cp [-v] from to */ #define FILE char #define NULL 0 #define stdin (_fbin) #define stdout (_fbout) #define stderr (_fberr) extern char _fbin[], _fbout[], _fberr[]; #define HALT exit() extern exit(); extern fputs(), freopen(), getw(), feof(), ferror(), fprintf(); #ifdef CP char usage[] = "cp [-v] from to"; extern putw(); #else char usage[] = "cmp file1 file2"; #endif main(argc,argv) int argc; int *argv; /* really char ** */ { char *cp; /* for casting */ #ifdef CP int vflag; vflag = 0; #endif while (--argc) { cp = *++argv; if (*cp != '-') break; switch(*++cp) { #ifdef CP case 'v': ++vflag; break; #endif default: fputs(usage, stderr); HALT; } } if (argc != 2) { fputs(usage, stderr); HALT; } #ifdef CP if (freopen(argv[0], "r", stdin) == NULL) { fputs("cannot read ", stderr); fputs(argv[0], stderr); HALT; } else if (freopen(argv[1], "w", stdout) == NULL) { fputs("cannot write ", stderr); fputs(argv[1], stderr); HALT; } else docopy(stdin, stdout, argv[0], argv[1]); if (vflag) #endif if (freopen(argv[0], "r", stdin) == NULL) { fputs("cannot read ", stderr); fputs(argv[0], stderr); HALT; } else if (freopen(argv[1], "r", stdout) == NULL) { fputs("cannot read ", stderr); fputs(argv[1], stderr); HALT; } else docmp(stdin, stdout, argv[0], argv[1]); } #ifdef CP docopy(in, out, inn, outn) FILE *in, *out; char * inn, *outn; { int word; int kb, b; for (kb = b = 0; ; ) { word = getw(in); if (feof(in)) { fprintf(stderr, "%d KB", kb); if (b) fprintf(stderr, " %d bytes", b); fputs(" copied\n", stderr); return; } if (ferror(in)) { fputs("error reading ", stderr); fputs(inn, stderr); HALT; } putw(word, out); if (feof(out) || ferror(out)) { fputs("error writing ", stderr); fputs(outn, stderr); HALT; } if ((b += 2) >= 1024) { ++kb; b = 0; } } } #endif docmp(fa,fb,fna,fnb) FILE *fa, *fb; char *fna, *fnb; { int wa, wb; int kb, b; for(kb = b = 0; ; ) { wa = getw(fa); wb = getw(fb); if (feof(fa)) if (feof(fb)) { fprintf(stderr, "%d KB", kb); if (b) fprintf(stderr, " %d bytes", b); fputs(" verified\n", stderr); return; } else { fputs(fna, stderr); fputs(" is short", stderr); HALT; } else if (feof(fb)) { fputs(fnb, stderr); fputs(" is short", stderr); HALT; } if (ferror(fa)) { fputs("error reading ", stderr); fputs(fna, stderr); HALT; } if (ferror(fb)) { fputs("error reading ", stderr); fputs(fnb, stderr); HALT; } if (wa != wb) { fprintf(stderr, "verify error at %d KB", kb); if (b) fprintf(stderr, " %d bytes", b); HALT; } if ((b += 2) >= 1024) { ++kb; b = 0; } } } %%%%%%%%%% scc/uty/entab.c %%%%%%%%%% /* * entab - turn blank series into tabs * eliminate trailing white space * * will handle blank/tab mixtures * will not turn single blank into tabs (intentionally) * will not handle backspaces * ats 9/82 * cpm ats 1/83 * cpm smallC ats 3/83 */ #define FILE char #define stdin (_fbin) #define stdout (_fbout) #define stderr (_fberr) #define NULL 0 #define EOF (-1) extern char _fbin[], _fbout[], _fberr[]; #define HALT exit() #define EXIT exit() extern exit(); extern fputs(), freopen(), getchar(), putchar(); #define TAB 8 /* columns per tab */ char usage[] = "entab [-b] [from [to]]"; main(argc, argv) int argc; int *argv; /* really char ** */ { int tab; /* stored tabs */ int blank; /* additionally stored blanks */ int delay; /* ==1 if one blank caused tab stop */ int col; /* column modulo 8 */ int ch; int bflag; /* if set: ^\t only */ int begin; /* if set: not yet non-white */ char *cp; /* for casting */ tab = blank = delay = col = bflag = 0; while (--argc) { cp = *++argv; if (*cp != '-') break; switch(*++cp) { case 'b': bflag++; break; default: fputs(usage, stderr); HALT; } } switch (argc) { case 0: break; /* standard i/o */ case 1: if (freopen(argv[0], "r", stdin) == NULL) { fputs("cannot read ", stderr); fputs(argv[0], stderr); HALT; } break; case 2: if (freopen(argv[0], "r", stdin) == NULL) { fputs("cannot read ", stderr); fputs(argv[0], stderr); HALT; } if (freopen(argv[1], "w", stdout) == NULL) { fputs("cannot write ", stderr); fputs(argv[1], stderr); HALT; } break; default: fputs(usage, stderr); HALT; } for (begin = 1;;) switch(ch = getchar()) { case EOF: EXIT; case '\n': putchar('\n'); col = blank = delay = tab = 0; begin = 1; continue; case '\t': if (! begin) goto nope; tab++; if (delay) tab++; col = blank = delay = 0; continue; case ' ': if (! begin) goto nope; if (delay) { delay = 0; tab++; blank++; col++; } else if (blank == 0 && col+1 >= TAB) { delay++; col = 0; } else { blank++; if (++col >= TAB) { tab++; col = blank = 0; } } continue; default: if (begin && bflag) begin = 0; nope: if (delay) putchar(' '); else { while (tab--) putchar('\t'); while (blank--) putchar(' '); } tab = delay = blank = 0; putchar(ch); if (++col >= TAB) col = 0; continue; } } %%%%%%%%%% scc/uty/get.c %%%%%%%%%% /* * get.c -- extract archived text * ats 2/83 * * used to extract from the libraries: * * 'flags' are one or more characters. * Lines are copied from stdin to stdout, * provided they start with a 'flags' character. * The 'flags' character is not copied. */ #define FILE char #define stdout _fbout #define stderr _fberr #define NULL 0 #define EOF (-1) extern char _fbout[], _fberr[]; extern fputs(), abort(), getchar(), fputc(), exit(); char *usage = "usage: get flags"; #define OOPS fputs(usage, stderr), abort() char flags['~'-' '+1]; isflag(ch) /* return TRUE if... */ int ch; /* ...this is a flag */ { return ch >= ' ' && ch <= '~'; } toflag(ch) /* return position if... */ char ch; /* ...this is a flag */ { return ch - ' '; } main(argc,argv) int argc; int *argv; /* really char ** */ { char *cp; int ch; while (--argc) for (cp = *++argv; ch = *cp; cp++) if (isflag(ch)) flags[toflag(ch)]++; else OOPS; for (;;) if ((ch = getchar()) == EOF) return; else if (isflag(ch) && flags[toflag(ch)]) doline(stdout); else if (ch != '\n') doline(NULL); } doline(out) FILE *out; { int ch, eof; do { if ((eof = ch = getchar()) == EOF) ch = '\n'; if (out != NULL) fputc(ch, out); } while (ch != '\n'); if (eof == EOF) exit(); } %%%%%%%%%% scc/uty/hex.c %%%%%%%%%% /* * hex.c -- CP/M file dump program * ats 3/83 */ /* * BUGS: offsets and addresses are handled in 16 bits, * the displayed address thus will wrap around. * Things are pretty much locked into * CP/M sectors, tracks, and blocks as on the Osborne... */ extern _dopen(); /* enable raw disk i/o */ char usage[] = "hex [-b[+][w|s|k|b|t]#] [-l[+][w|s|k|b|t]#]"; #define stdin (_fbin) #define stdout (_fbout) #define stderr (_fberr) extern char _fbin[], _fbout[], _fberr[]; #define HALT exit() extern exit(); extern atoi(), fputs(), feof(), printf(), puthex(), getw(), fseek(); /* * if the following defines are changed, * 'getarg' should be reviewed for scale and meaning */ #define SMODE 8 /* fseek measured in sectors */ #define SLEN 128 /* sector length */ #define LSLEN 7 /* log2 of SLEN */ #define CPW 2 /* sizeof(int), really */ #define SPT 20 /* sectors/track (Osborne) */ main(argc,argv) int argc; int *argv; { char *cp; /* for casting */ int mode, first, offset; int lflag, sectors, bytes; mode = first = offset = lflag = sectors = bytes = 0; while (--argc) { cp = *++argv; if (*cp != '-') { fputs(usage, stderr); HALT; } switch (*++cp) { default: fputs(usage, stderr); HALT; case 'b': getarg(cp, &mode, &first, &offset); continue; case 'l': getarg(cp, &lflag, §ors, &bytes); lflag = 1; continue; } } doseek(mode, first, &offset); dohex(first, offset, lflag, sectors, bytes); } doseek(mode,first,offset) int mode, first, *offset; { if (mode == 0) first = first << LSLEN | *offset; else *offset = 0; if (first && fseek(stdin, first, mode) == -1) { fputs("unable to position", stderr); HALT; } } dohex(first, offset, lflag, sectors, bytes) int first; /* # first sector */ int offset; /* offset in sector */ int lflag; /* 0: to EOF */ int sectors; /* sectors to show */ int bytes; /* plus bytes to show */ { char buf[SLEN]; int *wp; int len; for ( ; !lflag || sectors; --sectors) { wp = buf; for (len = 0; len<SLEN; len += CPW) { *wp++ = getw(stdin); if (feof(stdin)) break; } if (len) puthex(first<<LSLEN | offset, buf, len, stdout); if (feof(stdin)) return; ++first; } if (bytes) { wp = buf; for (len = 0; len < bytes; len += CPW) { *wp++ = getw(stdin); if (feof(stdin)) break; } if (len) puthex(first<<7 | offset, buf, len, stdout); } } getarg(cp, mode, sec, off) char *cp; int *mode, *sec, *off; { int m,s,o,plus; if (*++cp == '+') { plus = 1; ++cp; } else plus = 0; m = s = o = 0; switch (*cp) { default: o = atoi(cp); break; case 'w': o = atoi(++cp) << 1; break; case 's': m = SMODE; s = atoi(++cp); break; case 'k': m = SMODE; s = atoi(++cp) << 3; break; case 'b': m = SMODE; s = atoi(++cp) << 4; break; case 't': m = SMODE; s = atoi(++cp) * SPT; } if (plus) { *off += o; *sec += s + (*off >> LSLEN); *off &= SLEN-1; } else { *mode = m; *sec = s + (o >> LSLEN); *off = o & SLEN-1; } } %%%%%%%%%% scc/uty/wc.c %%%%%%%%%% /* * wc.c -- words, characters, lines in files * ats 3/83 */ #define FILE char #define NULL 0 #define NUL 0 #define EOF (-1) #define stdin (_fbin) #define stdout (_fbout) #define stderr (_fberr) extern char _fbin[], _fbout[], _fberr[]; #define HALT exit() #define EXIT exit() extern exit(); extern fputs(), fopen(), fclose(), strcmp(), fgetc(), printf(); char usage[] = "wc [-v] [from]..."; char vflag = 0; int cc = 0, wc = 0, lc = 0; /* grand total */ main(argc,argv) int argc; int *argv; /* really char ** */ { char *cp; /* for casting */ FILE *in; while (--argc) { cp = *++argv; if (*cp != '-' || *++cp == NUL) break; switch(*cp) { case 'v': ++vflag; break; default: fputs(usage, stderr); HALT; } } if (argc == 0) dowc(stdin, "stdin"); else { do { if (strcmp(*argv, "-") == 0) dowc(stdin, "stdin"); else if ((in = fopen(*argv, "r")) == NULL) { fputs("cannot read ", stderr); fputs(*argv, stderr); } else { dowc(in, *argv); fclose(in); } ++argv; } while (--argc); printf("\t%6d\t%6d\t%6d\ttotal", cc, wc, lc); } } dowc(in, inn) FILE *in; char * inn; { int ch; int c, w, l, sum, inword; c = w = l = sum = inword = 0; while ((ch = fgetc(in)) != EOF) { ++c; switch(ch) { case '\n': ++l; case ' ': case '\t': if (inword) inword = 0; continue; } if (! inword) { ++inword; ++w; } sum += ch; } if (vflag) printf("0x%4x", sum); printf("\t%6d\t%6d\t%6d\t%s\n", c, w, l, inn); cc += c; wc += w; lc += l; } %%%%%%%%%% end of part 4 and of smallC V2 CP/M runtime support %%%%%%%%%%