From a3c7602dac1719f6857fc72661217dbba9ed349b Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 22 Jun 2016 20:34:02 +0100 Subject: [PATCH] Small C 3.0 with some cleanups and ANSI processing I've attached the 6809 code generator for the older compiler version as well. We should be able to get a real C compiler in the space we have (CP/M manages it for a passable ANSI C) but this will be fun for now and for debugging work. --- Applications/SmallC/8080/Makefile | 8 + Applications/SmallC/8080/arglist.c | 34 ++ Applications/SmallC/8080/bdos.c | 18 + Applications/SmallC/8080/bdos1.c | 5 + Applications/SmallC/8080/chio8080.c | 12 + Applications/SmallC/8080/cret.asm | 27 + Applications/SmallC/8080/crun.asm | 352 ++++++++++++ Applications/SmallC/8080/exit.c | 6 + Applications/SmallC/8080/inout.c | 28 + Applications/SmallC/8080/io8080.c | 305 ++++++++++ Applications/SmallC/M_README | 14 + Applications/SmallC/Makefile | 27 + Applications/SmallC/README | 89 +++ Applications/SmallC/README.2 | 63 +++ Applications/SmallC/code6809.c | 803 +++++++++++++++++++++++++++ Applications/SmallC/code8080.c | 798 ++++++++++++++++++++++++++ Applications/SmallC/data.c | 65 +++ Applications/SmallC/data.h | 57 ++ Applications/SmallC/defs.h | 225 ++++++++ Applications/SmallC/error.c | 45 ++ Applications/SmallC/expr.c | 787 ++++++++++++++++++++++++++ Applications/SmallC/foo.c | 2 + Applications/SmallC/function.c | 196 +++++++ Applications/SmallC/gen.c | 188 +++++++ Applications/SmallC/includes/ctype.h | 1 + Applications/SmallC/includes/stdio.h | 6 + Applications/SmallC/initials.c | 141 +++++ Applications/SmallC/io.c | 199 +++++++ Applications/SmallC/lex.c | 228 ++++++++ Applications/SmallC/lib/abs.c | 5 + Applications/SmallC/lib/atoi.c | 21 + Applications/SmallC/lib/binary.c | 22 + Applications/SmallC/lib/charclass.c | 33 ++ Applications/SmallC/lib/fgets.c | 27 + Applications/SmallC/lib/fputs.c | 7 + Applications/SmallC/lib/getchar.c | 5 + Applications/SmallC/lib/gets.c | 28 + Applications/SmallC/lib/index.c | 18 + Applications/SmallC/lib/itoa.c | 14 + Applications/SmallC/lib/printn.c | 16 + Applications/SmallC/lib/putchar.c | 5 + Applications/SmallC/lib/puts.c | 6 + Applications/SmallC/lib/rand.c | 20 + Applications/SmallC/lib/reverse.c | 17 + Applications/SmallC/lib/sbrk.c | 17 + Applications/SmallC/lib/shell.c | 21 + Applications/SmallC/lib/strcat.c | 20 + Applications/SmallC/lib/strcmp.c | 13 + Applications/SmallC/lib/strcpy.c | 18 + Applications/SmallC/lib/strlen.c | 8 + Applications/SmallC/lib/strncat.c | 25 + Applications/SmallC/lib/strncmp.c | 16 + Applications/SmallC/lib/strncpy.c | 23 + Applications/SmallC/main.c | 363 ++++++++++++ Applications/SmallC/preproc.c | 364 ++++++++++++ Applications/SmallC/primary.c | 316 +++++++++++ Applications/SmallC/prototype.h | 219 ++++++++ Applications/SmallC/readme.txt.old | 7 + Applications/SmallC/stmt.c | 416 ++++++++++++++ Applications/SmallC/struct.c | 95 ++++ Applications/SmallC/sym.c | 418 ++++++++++++++ Applications/SmallC/while.c | 86 +++ 62 files changed, 7418 insertions(+) create mode 100644 Applications/SmallC/8080/Makefile create mode 100644 Applications/SmallC/8080/arglist.c create mode 100644 Applications/SmallC/8080/bdos.c create mode 100644 Applications/SmallC/8080/bdos1.c create mode 100644 Applications/SmallC/8080/chio8080.c create mode 100644 Applications/SmallC/8080/cret.asm create mode 100644 Applications/SmallC/8080/crun.asm create mode 100644 Applications/SmallC/8080/exit.c create mode 100644 Applications/SmallC/8080/inout.c create mode 100644 Applications/SmallC/8080/io8080.c create mode 100644 Applications/SmallC/M_README create mode 100644 Applications/SmallC/Makefile create mode 100644 Applications/SmallC/README create mode 100644 Applications/SmallC/README.2 create mode 100644 Applications/SmallC/code6809.c create mode 100644 Applications/SmallC/code8080.c create mode 100644 Applications/SmallC/data.c create mode 100644 Applications/SmallC/data.h create mode 100644 Applications/SmallC/defs.h create mode 100644 Applications/SmallC/error.c create mode 100644 Applications/SmallC/expr.c create mode 100644 Applications/SmallC/foo.c create mode 100644 Applications/SmallC/function.c create mode 100644 Applications/SmallC/gen.c create mode 100644 Applications/SmallC/includes/ctype.h create mode 100644 Applications/SmallC/includes/stdio.h create mode 100644 Applications/SmallC/initials.c create mode 100644 Applications/SmallC/io.c create mode 100644 Applications/SmallC/lex.c create mode 100644 Applications/SmallC/lib/abs.c create mode 100644 Applications/SmallC/lib/atoi.c create mode 100644 Applications/SmallC/lib/binary.c create mode 100644 Applications/SmallC/lib/charclass.c create mode 100644 Applications/SmallC/lib/fgets.c create mode 100644 Applications/SmallC/lib/fputs.c create mode 100644 Applications/SmallC/lib/getchar.c create mode 100644 Applications/SmallC/lib/gets.c create mode 100644 Applications/SmallC/lib/index.c create mode 100644 Applications/SmallC/lib/itoa.c create mode 100644 Applications/SmallC/lib/printn.c create mode 100644 Applications/SmallC/lib/putchar.c create mode 100644 Applications/SmallC/lib/puts.c create mode 100644 Applications/SmallC/lib/rand.c create mode 100644 Applications/SmallC/lib/reverse.c create mode 100644 Applications/SmallC/lib/sbrk.c create mode 100644 Applications/SmallC/lib/shell.c create mode 100644 Applications/SmallC/lib/strcat.c create mode 100644 Applications/SmallC/lib/strcmp.c create mode 100644 Applications/SmallC/lib/strcpy.c create mode 100644 Applications/SmallC/lib/strlen.c create mode 100644 Applications/SmallC/lib/strncat.c create mode 100644 Applications/SmallC/lib/strncmp.c create mode 100644 Applications/SmallC/lib/strncpy.c create mode 100644 Applications/SmallC/main.c create mode 100644 Applications/SmallC/preproc.c create mode 100644 Applications/SmallC/primary.c create mode 100644 Applications/SmallC/prototype.h create mode 100644 Applications/SmallC/readme.txt.old create mode 100644 Applications/SmallC/stmt.c create mode 100644 Applications/SmallC/struct.c create mode 100644 Applications/SmallC/sym.c create mode 100644 Applications/SmallC/while.c diff --git a/Applications/SmallC/8080/Makefile b/Applications/SmallC/8080/Makefile new file mode 100644 index 00000000..f2560815 --- /dev/null +++ b/Applications/SmallC/8080/Makefile @@ -0,0 +1,8 @@ +.SUFFIXES: .o .c .asm + +ASSEMS = bdos.asm bdos1.asm chio8080.asm exit.asm io8080.asm sbrk.asm + +.c.asm: + tscc $*.c + +all: $(ASSEMS) diff --git a/Applications/SmallC/8080/arglist.c b/Applications/SmallC/8080/arglist.c new file mode 100644 index 00000000..f747b465 --- /dev/null +++ b/Applications/SmallC/8080/arglist.c @@ -0,0 +1,34 @@ +/* Interpret CPM argument list to produce C style + argc/argv + default dma buffer has it, form: + --------------------------------- + |count|characters ... | + --------------------------------- +*/ +int Xargc; +int Xargv[30]; +Xarglist(ap) char *ap; { + char qc; + Xargc = 0; + ap[(*ap)+1 ] = '\0'; + ap++; + while (isspace(*ap)) ap++; + Xargv[Xargc++] = "arg0"; + if (*ap) + do { + if (*ap == '\'' || *ap == '\"') { + qc = *ap; + Xargv[Xargc++] = ++ap; + while (*ap&&*ap != qc) ap++; + } else { + Xargv[Xargc++] = ap; + while (*ap&&!isspace(*ap)) ap++; + } + if (!*ap) break; + *ap++='\0'; + while (isspace(*ap)) ap++; + } while(*ap); + Xargv[Xargc] = 0; + +} + diff --git a/Applications/SmallC/8080/bdos.c b/Applications/SmallC/8080/bdos.c new file mode 100644 index 00000000..b475f181 --- /dev/null +++ b/Applications/SmallC/8080/bdos.c @@ -0,0 +1,18 @@ +bdos (c, de) int c, de; { +#asm +; CP/M support routine +; bdos(C,DE); +; char *DE; int C; +; returns H=B,L=A per CPM standard + pop h ; hold return address + pop d ; get bdos function number + pop b ; get DE register argument + push d + push b + push h + call 5 + mov h,b + mov l,a +#endasm +} + diff --git a/Applications/SmallC/8080/bdos1.c b/Applications/SmallC/8080/bdos1.c new file mode 100644 index 00000000..aa00c931 --- /dev/null +++ b/Applications/SmallC/8080/bdos1.c @@ -0,0 +1,5 @@ +bdos1(c, de) int c, de; { + /* returns only single byte (top half is 0) */ + return (255 & bdos(c, de)); +} + diff --git a/Applications/SmallC/8080/chio8080.c b/Applications/SmallC/8080/chio8080.c new file mode 100644 index 00000000..4cdd2e29 --- /dev/null +++ b/Applications/SmallC/8080/chio8080.c @@ -0,0 +1,12 @@ +#define EOL 10 +getchar() { + return (bdos(1,1)); + +} + +putchar (c) char c; { + if (c == EOL) bdos(2,13); + bdos(2,c); + return c; +} + diff --git a/Applications/SmallC/8080/cret.asm b/Applications/SmallC/8080/cret.asm new file mode 100644 index 00000000..ea3d06c5 --- /dev/null +++ b/Applications/SmallC/8080/cret.asm @@ -0,0 +1,27 @@ +; Run time start off for Small C. + cseg + sphl ; save the stack pointer + shld ?stksav + lhld 6 ; pick up core top + lxi d,-10 ; decrease by 10 for safety + dad d + sphl ; set stack pointer + call stdioinit ; initialize stdio + call Xarglist + lhld Xargc + push h + lxi h,Xargv + push h + call main ; call main program + pop d + pop d + lhld ?stksav ; restore stack pointer + ret ; go back to CCP + dseg +?stksav ds 2 + extrn stdioinit + extrn Xarglist + extrn Xargc + extrn Xargv + extrn main + end diff --git a/Applications/SmallC/8080/crun.asm b/Applications/SmallC/8080/crun.asm new file mode 100644 index 00000000..d60070ab --- /dev/null +++ b/Applications/SmallC/8080/crun.asm @@ -0,0 +1,352 @@ +; +;***************************************************** +; * +; runtime library for small C compiler * +; * +; c.s - runtime routine for basic C code * +; * +; Ron Cain * +; * +;***************************************************** +; + cseg +; + public ?gchar,?gint,?pchar,?pint + public ?sxt + public ?or,?and,?xor + public ?eq,?ne,?gt,?le,?ge,?lt,?uge,?ult,?ugt,?ule + public ?asr,?asl + public ?sub,?neg,?com,?lneg,?bool,?mul,?div + public ?case,brkend,Xstktop + public etext + public edata +; +; fetch char from (HL) and sign extend into HL +?gchar: mov a,m +?sxt: mov l,a + rlc + sbb a + mov h,a + ret +; fetch int from (HL) +?gint: mov a,m + inx h + mov h,m + mov l,a + ret +; store char from HL into (DE) +?pchar: mov a,l + stax d + ret +; store int from HL into (DE) +?pint: mov a,l + stax d + inx d + mov a,h + stax d + ret +; "or" HL and DE into HL +?or: mov a,l + ora e + mov l,a + mov a,h + ora d + mov h,a + ret +; "xor" HL and DE into HL +?xor: mov a,l + xra e + mov l,a + mov a,h + xra d + mov h,a + ret +; "and" HL and DE into HL +?and: mov a,l + ana e + mov l,a + mov a,h + ana d + mov h,a + ret +; +;......logical operations: HL set to 0 (false) or 1 (true) +; +; DE == HL +?eq: call ?cmp + rz + dcx h + ret +; DE != HL +?ne: call ?cmp + rnz + dcx h + ret +; DE > HL [signed] +?gt: xchg + call ?cmp + rc + dcx h + ret +; DE <= HL [signed] +?le: call ?cmp + rz + rc + dcx h + ret +; DE >= HL [signed] +?ge: call ?cmp + rnc + dcx h + ret +; DE < HL [signed] +?lt: call ?cmp + rc + dcx h + ret +; DE >= HL [unsigned] +?uge: call ?ucmp + rnc + dcx h + ret +; DE < HL [unsigned] +?ult: call ?ucmp + rc + dcx h + ret +; DE > HL [unsigned] +?ugt: xchg + call ?ucmp + rc + dcx h + ret +; DE <= HL [unsigned] +?ule: call ?ucmp + rz + rc + dcx h + ret +; signed compare of DE and HL +; carry is sign of difference [set => DE < HL] +; zero is zero/non-zero +?cmp: mov a,e + sub l + mov e,a + mov a,d + sbb h + lxi h,1 ;preset true + jm ?cmp1 + ora e ;resets carry + ret +?cmp1: ora e + stc + ret +; unsigned compare of DE and HL +; carry is sign of difference [set => DE < HL] +; zero is zero/non-zero +?ucmp: mov a,d + cmp h + jnz ?ucmp1 + mov a,e + cmp l +?ucmp1: lxi h,1 ;preset true + ret +; shift DE right arithmetically by HL, move to HL +?asr: xchg +?asr1: dcr e + rm + mov a,h + ral + mov a,h + rar + mov h,a + mov a,l + rar + mov l,a + jmp ?asr1 +; shift DE left arithmetically by HL, move to HL +?asl: xchg +?asl1: dcr e + rm + dad h + jmp ?asl1 +; HL = DE - HL +?sub: mov a,e + sub l + mov l,a + mov a,d + sbb h + mov h,a + ret +; HL = -HL +?neg: call ?com + inx h + ret +; HL = ~HL +?com: mov a,h + cma + mov h,a + mov a,l + cma + mov l,a + ret +; HL = !HL +?lneg: mov a,h + ora l + jz ?lneg1 + lxi h,0 + ret +?lneg1: inx h + ret +; HL = !!HL +?bool: call ?lneg + jmp ?lneg +; +; HL = DE * HL [signed] +?mul: mov b,h + mov c,l + lxi h,0 +?mul1: mov a,c + rrc + jnc ?mul2 + dad d +?mul2: 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 ?mul1 +; HL = DE / HL, DE = DE % HL +?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 ?cmpbd + 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 +; {DE = -DE} +?deneg: mov a,d + cma + mov d,a + mov a,e + cma + mov e,a + inx d + ret +; {BC = -BC} +?bcneg: mov a,b + cma + mov b,a + mov a,c + cma + mov c,a + inx b + ret +; {DE +ininst in 0 ; self modifying code... + mov l,a + xra a + mov h,a + ret +#endasm + +} + +outp(pno, val) char pno, val; { + pno; +#asm + mov a,l + sta outinst+1 +#endasm + val; +#asm + mov a,l +outinst out 0 + ret +#endasm +} + diff --git a/Applications/SmallC/8080/io8080.c b/Applications/SmallC/8080/io8080.c new file mode 100644 index 00000000..f6c457f7 --- /dev/null +++ b/Applications/SmallC/8080/io8080.c @@ -0,0 +1,305 @@ +/* Basic CP/M file I/O: +fopen,fclose,fgetc,fputc,feof + +Original: Paul Tarvydas +Fixed by: Chris Lewis +*/ +#include + +#define EOL 10 +#define EOL2 13 +#define CPMEOF 26 +#define CPMERR 255 +#define UNIT_OFFSET 3 +#define CPMCIN 1 +#define CPMCOUT 2 +#define READ_EOF 3 +#define SETDMA 26 +#define DEFAULT_DMA 128 +#define CPMREAD 20 +#define CPMWR 21 +#define WRITE 2 +#define READ 1 +#define FREE 0 +#define NBUFFS 4 +#define BUFSIZ 512 +#define FCBSIZ 33 +#define ALLBUFFS 2048 +#define ALLFCBS 132 +#define CPMERA 19 +#define CPMCREAT 22 +#define CPMOPEN 15 +#define NBLOCKS 4 +#define BLKSIZ 128 +#define BKSP 8 +#define CTRLU 21 +#define FWSP ' ' +#define CPMCLOSE 16 + +char buffs[ALLBUFFS], /* disk buffers */ +fcbs[ALLFCBS]; /* fcbs for buffers */ +int bptr[NBUFFS]; /* ptrs into buffers */ +int modes[NBUFFS]; /* mode for each open file */ +int eptr[NBUFFS]; /* buffers' ends */ +char eofstdin; /* flag end of file on stdin */ + +fgetc(unit) int unit; +{ + int c; + while ((c = Xfgetc(unit)) == EOL2); + return c; + +} + +Xfgetc(unit) int unit; +{ + int i; + int c; + char *buff; + char *fcba; + if ((unit == stdin) & !eofstdin) { + c = bdos1(CPMCIN, 0); + if (c == 4) { + eofstdin = 1; + return (EOF); + } + else if (c == 3) + exit (1); + else { + if (c == EOL2) { + c = EOL; + bdos (CPMCOUT, EOL); + } + return (c); + } + } + if (modes[unit = unit - UNIT_OFFSET] == READ) { + if (bptr[unit] >= eptr[unit]) { + fcba = fcbaddr(unit); + /* fill da buffer again */ + i = 0; /* block counter */ + buff = buffaddr(unit); /* dma ptr */ + /* if buffer wasn't totally + filled last time, we already + eof */ + if (eptr[unit] == buffaddr(unit + 1)) + do { + bdos(SETDMA, buff); + if (0!=bdos1(CPMREAD, fcba)) + break; + buff = buff + BLKSIZ; + } + while (++ieof*/ + if (i==0) { + modes[unit] = READ_EOF; + return EOF; + } + /* o.k. set start & end ptrs */ + eptr[unit] = + (bptr[unit]=buffaddr(unit)) + + (i * BLKSIZ); + } + c = (*(bptr[unit]++)) & 0xff; + if (c == CPMEOF) { + c = EOF; + modes[unit] = READ_EOF; + } + return c; + } + return EOF; + +} + +fclose(unit) int unit; +{ + int i; + if ((unit==stdin)|(unit==stdout)|(unit==stderr)) + return NULL; + if (modes[unit = unit - UNIT_OFFSET] != FREE) { + if (modes[unit] == WRITE) + fflush(unit + UNIT_OFFSET); + modes[unit] = FREE; + return bdos1(CPMCLOSE, fcbaddr(unit)); + } + return EOF; + +} + +fflush(unit) int unit; +{ + char *buffa; + char *fcba; + if ((unit!=stdin)|(unit!=stdout)|(unit!=stderr)) { + /* put an eof at end of file */ + fputc(CPMEOF, unit); + if (bptr[unit = unit - UNIT_OFFSET] != + (buffa = buffaddr(unit))) { + /* some chars in buffer - flush them */ + fcba = fcbaddr(unit); + do { + bdos(SETDMA, buffa); + if (0 != bdos1(CPMWR, fcba)) + return (EOF); + } + while (bptr[unit] > + (buffa=buffa+BLKSIZ)); + bdos(SETDMA, DEFAULT_DMA); + } + } + return NULL; + +} + +fputc(c, unit) char c; +int unit; +{ + char *buffa; + char *fcba; + if (c == EOL) fputc(EOL2, unit); + if ((unit == stdout) | (unit == stderr)) { + bdos(CPMCOUT, c); + return c; + } + if (WRITE == modes[unit = unit - UNIT_OFFSET]) { + if (bptr[unit] >= eptr[unit]) { + /* no room - dump buffer */ + fcba = fcbaddr(unit); + buffa=buffaddr(unit); + while (buffa < eptr[unit]) { + bdos(SETDMA, buffa); + if (0 != bdos1(CPMWR, fcba)) break; + buffa = buffa + BLKSIZ; + } + bdos(SETDMA, DEFAULT_DMA); + bptr[unit] = buffaddr(unit); + if (buffa < eptr[unit]) return EOF; + } + *(bptr[unit]++) = c; + return c; + } + return EOF; + +} + +allocunitno() { + int i; + /* returns # of first free buffer, EOF if none */ + /* buffer is not reserved (ie. mode remains FREE) */ + for (i = 0; i < NBUFFS; ++i) + if (modes[i] == FREE) break; + if (i >= NBUFFS) return EOF; + else return (i + UNIT_OFFSET); + +} + +fopen(name, mode) char *name, *mode; +{ + int fileno, fno2; + if (EOF != (fileno = allocunitno())) { + /* internal file # excludes units 0,1 & 2 + since there's no buffers associated with + these units */ + movname(clearfcb(fcbaddr(fno2 = fileno + - UNIT_OFFSET)), name); + if ('r' == *mode) { + if (bdos1(CPMOPEN, fcbaddr(fno2)) != CPMERR) + { + modes[fno2] = READ; + /* ptr>bufsiz => buffer empty*/ + eptr[fno2] = + bptr[fno2] = buffaddr(fno2+1 ); + return fileno; + } + } + else if ('w' == *mode) { + bdos(CPMERA, fcbaddr(fno2)); + if (bdos1(CPMCREAT, fcbaddr(fno2)) != CPMERR){ + modes[fno2] = WRITE; + bptr[fno2] = buffaddr(fno2); + eptr[fno2] = buffaddr(fno2+1 ); + return fileno; + } + } + } + return NULL; + +} + +clearfcb(fcb) char fcb[]; +{ + int i; + for (i=0; i= c)) { + *fcb = (c - 'A' + 1); + str++; + str++; + } + } + while ((NULL != *str) & (i<9)) { + /* up to 8 chars into file name field */ + if ('.' == *str) break; + fcb[i++] = toupper(*str++); + } + /* strip off excess chars - up to '.' (beginning of + extension name ) */ + while ((NULL != *str) & ((*str) != '.')) ++str; + if (*str) + /* '.' is first char of *str now */ + /* copy 3 chars of ext. if there */ + for ( /* first char of ext @ pos 9 (8+1 )*/ +i = 8; +/* '.' is stripped by ++ 1st time */ +/* around */ +(NULL != *++str) & (12 > ++i); +fcb[i] = toupper(*str) +); + return fcb; + +} + +stdioinit() { + int i; + eofstdin = 0; + for (i=0; i filename + +There are other options available - see main.c for details. + +The code generated by these compilers need a run-time support library +for two things: operations that are "hard" on a particular processor +(eg: 16 bit multiply on an 8080), or O/S interface (vax is BSD 4.1, +6809 is FLEX, 8080 is CPM, never had one for M68k). + +Status: the 6809, VAX and 8080 versions work last I checked - a problem or +two may have crept in during the implementation of the compile/assemble/and +link code for machines that support it. The M68k version has never been +tested. I don't have a Pyramid version because Pyrcorp seems reluctant +to publish instruction set information. + +So you want to write a new coder do you? Well, it's easy - read the +comments in one of the coders. You should not have to modify *any* of +the existing files, just write a new codexxx.c file. Please contact +me if you run into trouble. I would be greatly interested in any new +coders or bug reports in the compilers. As far as I am aware, the +major restriction on porting this thing for different targets is that +pointers and integers *must* be the same length, alignment, and be +interchangeable. diff --git a/Applications/SmallC/README.2 b/Applications/SmallC/README.2 new file mode 100644 index 00000000..28d50e29 --- /dev/null +++ b/Applications/SmallC/README.2 @@ -0,0 +1,63 @@ + Small C version C3.0R1.1 + (SCC3) + + Chris Lewis + +This directory contains the source for a version of Ron Cain's Small C +compiler that I have heavily modified - beyond the Small-C V2.0 later +published in Dr. Dobbs. This compiler generates assembler source code that +needs to be assembled and linked to make a running program. + +Small C is a public domain compiler for a subset of C. The main things +lacking are "#if", structs/unions, doubles/floats/longs and more than +one level of indirection. Even so, it's powerful enough to be able to +compile itself. It's also lots of fun to play around with. It could +use lots of more work (eg: a real scanner), but what the heck... +Retargetting the compiler requires only relinking the frontend with a new +code generator. + +Code generators for 6809 (MIT UNIX-like assembler), M68K (Motorola V/68 +UNIX +assembler), VAX (BSD 4.1 assembler), and 8080 (RMAC assembler) are +provided. + +Users having access to System V make should be able to use the Makefile +without any modification except for INCDIR and LIBDIR (where you'd like +to put the compiler itself). + +Users not having access to System V will probably have to rewrite the +Makefile. +[ I have provided a Makefile that seems to work with bsd systems - mod] + +WARNING: you will probably see a great deal of compilation warnings when +you compile this compiler with a "real" UNIX C. Don't worry - this is +*perfectly* normal - Small C is a subset of real C, and in order to +keep the compiler in this subset you have to bend the rules somewhat. +The only time where this might cause a problem is where pointers are +"different" from ints (ie: different length or on non-byte-addressible +machines). Small C assumes that ints are the same as pointers. + +Invocation: + scc<6809|vax|m68k|8080> filename + +There are other options available - see main.c for details. + +The code generated by these compilers need a run-time support library +for two things: operations that are "hard" on a particular processor +(eg: 16 bit multiply on an 8080), or O/S interface (vax is BSD 4.1, +6809 is FLEX, 8080 is CPM, never had one for M68k). + +Status: the 6809, VAX and 8080 versions work last I checked - a problem or +two may have crept in during the implementation of the compile/assemble/and +link code for machines that support it. The M68k version has never been +tested. I don't have a Pyramid version because Pyrcorp seems reluctant +to publish instruction set information. + +So you want to write a new coder do you? Well, it's easy - read the +comments in one of the coders. You should not have to modify *any* of +the existing files, just write a new codexxx.c file. Please contact +me if you run into trouble. I would be greatly interested in any new +coders or bug reports in the compilers. As far as I am aware, the +major restriction on porting this thing for different targets is that +pointers and integers *must* be the same length, alignment, and be +interchangeable. diff --git a/Applications/SmallC/code6809.c b/Applications/SmallC/code6809.c new file mode 100644 index 00000000..b4762f70 --- /dev/null +++ b/Applications/SmallC/code6809.c @@ -0,0 +1,803 @@ +/* File codeas09.c: 2.2 (84/08/31,10:05:13) */ +/*% cc -O -c % + * + * THIS IS FROM AN OLDER VERSION OF THE COMPILER: WILL NEED PORTING + */ + +#include +#include "defs.h" +#include "data.h" + +#ifdef M6809 + +/* Define ASNM and LDNM to the names of the assembler and linker + respectively */ + +/* + * Some predefinitions: + * + * INTSIZE is the size of an integer in the target machine + * BYTEOFF is the offset of an byte within an integer on the + * target machine. (ie: 8080,pdp11 = 0, 6809 = 1, + * 360 = 3) + * This compiler assumes that an integer is the SAME length as + * a pointer - in fact, the compiler uses INTSIZE for both. + */ +#define INTSIZE 2 +#define BYTEOFF 1 + +void tab(void) +{ + output_byte('\t'); +} + +void ot(char ptr[]) +{ + tab (); + output_string (ptr); + +} + +void ol(char ptr[]) +{ + ot (ptr); + newline(); +} + + + +/* + * print all assembler info before any code is generated + * + */ +void header(void) +{ + output_string("|\tSmall C MC6809\n|\tCoder (2.4,84/11/27)\n|"); + frontend_version(); + newline(); + ol (".globl\tsmul,sdiv,smod,asr,asl,neg,lneg,case"); + ol (".globl\teq,ne,lt,le,gt,ge,ult,ule,ugt,uge,bool"); + +} + + +void initmac(void) { + defmac("mc6809\t1"); + defmac("mitas09\t1"); + defmac("smallc\t1"); + +} + +int galign(int t) +{ + return (t); + +} + +/* + * return size of an integer + */ +int intsize(void) { + return(INTSIZE); + +} + +/* + * return offset of ls byte within word + * (ie: 8080 & pdp11 is 0, 6809 is 1, 360 is 3) + */ +int byteoff(void) { + return(BYTEOFF); +} + +/* + * Output internal generated label prefix + */ +void olprfix(void) { + output_string("LL"); + +} + +/* + * Output a label definition terminator + */ +void col(void) +{ + output_string ("=.\n"); + +} + +/* + * begin a comment line for the assembler + * + */ +void comment(void) +{ + output_byte ('|'); + +} + +/* + * Output a prefix in front of user labels + */ +void prefix(void) { + output_byte('_'); + +} + +/* + * print any assembler stuff needed after all code + * + */ +void trailer(void) +{ + ol (".end"); + +} + +/* + * function prologue + */ +void prologue(void) +{ + +} + +/* + * text (code) segment + */ + +void gtext(void) +{ + ol (".text"); + +} + +/* + * data segment + */ +void gdata(void) +{ + ol (".data"); + +} + +/* + * Output the variable symbol at scptr as an extrn or a public + */ +void ppubext(char *scptr) +{ + if (scptr[STORAGE] == STATIC) + return; + ot (".globl\t"); + prefix (); + output_string (scptr); + nl(); + +} + +/* + * Output the function symbol at scptr as an extrn or a public + */ +void fpubext(char *scptr) { + ppubext(scptr); + +} + +/* + * Output a decimal number to the assembler file + */ +void onum(int num) { + output_decimal(num); /* pdp11 needs a "." here */ + output_byte('.'); +} + +/* + * fetch a static memory cell into the primary register + */ + +void getmem(char *sym) +{ + if ((sym[IDENT] != POINTER) & (sym[TYPE] == CCHAR)) { + ot ("ldb\t"); + prefix (); + output_string (sym + NAME); + newline(); + ot ("sex"); + newline(); + } else { + ot ("ldd\t"); + prefix (); + output_string (sym + NAME); + newline(); + } +} + +/* + * fetch the address of the specified symbol into the primary register + * + */ +void getloc(char *sym) +{ + if (sym[STORAGE] == LSTATIC) { + immed(); + printlabel(glint(sym)); + nl(); + } else { + ot ("leay\t"); + onum (glint(sym) - stkp); + output_string ("(s)\n\ttfr\ty,d\n"); + } + +} + +/* + * store the primary register into the specified static memory cell + * + */ +void putmem (char *sym) +{ + if ((sym[IDENT] != POINTER) & (sym[TYPE] == CCHAR)) { + ot ("stb\t"); + } else + ot ("std\t"); + prefix (); + output_string (sym + NAME); + newline(); + +} + +/* + * store the specified object type in the primary register + * at the address on the top of the stack + * + */ +void putstk(char typeobj) +{ + if (typeobj == CCHAR) + ol ("stb\t@(s)++"); + else + ol ("std\t@(s)++"); + stkp = stkp + INTSIZE; + +} + +/* + * fetch the specified object type indirect through the primary + * register into the primary register + * + */ +void indirect (char typeobj) +{ + ol("tfr\td,y"); + if (typeobj == CCHAR) + ol ("ldb\t(y)\n\tsex"); + else + ol ("ldd\t(y)"); + +} + +/* + * swap the primary and secondary registers + * + */ +void swap(void) +{ + ol ("exg\td,x"); + +} + +/* + * print partial instruction to get an immediate value into + * the primary register + * + */ +void immed(void) +{ + ot ("ldd\t#"); + +} + +/* + * push the primary register onto the stack + * + */ +void gpush(void) +{ + ol ("pshs\td"); + stkp = stkp - INTSIZE; + +} + +/* + * pop the top of the stack into the secondary register + * + */ +void gpop(void) +{ + ol ("puls\td"); + stkp = stkp + INTSIZE; + +} + +/* + * swap the primary register and the top of the stack + * + */ +void swapstk(void) +{ + ol ("ldy\t(s)\nstd\t(s)\n\ttfr\ty,d"); + +} + +/* + * call the specified subroutine name + * + */ +void gcall(char *sname) +{ + ot ("jsr\t"); + if (*sname == '^') + output_string (++sname); + else { + prefix (); + output_string (sname); + } + newline(); + +} + +/* + * return from subroutine + * + */ +void gret(void) +{ + ol ("rts"); + +} + +/* + * perform subroutine call to value on top of stack + * + */ +void callstk(void) +{ + gpop(); + ol("jsr\t(x)"); + +} + +/* + * jump to specified internal label number + * + */ +void jump(int label) +{ + ot ("lbra\t"); + printlabel(label); + nl(); + +} + +/* + * test the primary register and jump if false to label + * + */ +void testjump (int label, int ft) +{ + ol ("cmpd\t#0"); + if (ft) + ot ("lbne\t"); + else + ot ("lbeq\t"); + printlabel (label); + newline(); + +} + +/* + * print pseudo-op to define a byte + * + */ +void defbyte(void) +{ + ot (".byte\t"); + +} + +/* + * print pseudo-op to define storage + * + */ +void defstorage(void) +{ + ot (".blkb\t"); + +} + +/* + * print pseudo-op to define a word + * + */ + +void defword(void) +{ + ot (".word\t"); + +} + +/* + * modify the stack pointer to the new value indicated + * + */ +void modstk(int newstkp) +{ + int k; + + k = galign(newstkp - stkp); + if (k == 0) + return (newstkp); + ot ("leas\t"); + onum (k); + output_string ("(s)\n"); + return (newstkp); + +} + +/* + * multiply the primary register by INTSIZE + */ +void gaslint(void) +{ + ol ("aslb\n\trola"); + +} + +/* + * divide the primary register by INTSIZE + */ +void gasrint(void) +{ + ol ("asra\n\trorb"); + +} + +/* + * Case jump instruction + */ +void gjcase(void) { + ot ("jmp\tcase"); + newline(); + +} + +/* + * add the primary and secondary registers + * if lval2 is int pointer and lval is int, scale lval + */ +void gadd (LVALUE *lval, LVALUE *lval2) +{ + if (dbltest (lval2, lval)) { + ol ("asl\t1(s)\n\trol\t(s)"); + } + ol ("addd\t(s)++"); + stkp = stkp + INTSIZE; + +} + +/* + * subtract the primary register from the secondary + * + */ +void gsub(void) +{ + ol ("subd\t(s)++\n\tcoma\n\tcomb\n\taddd\t#1"); + stkp = stkp + INTSIZE; + +} + +/* + * multiply the primary and secondary registers + * (result in primary) + * + */ +void gmult(void) +{ + gcall ("^smul"); + stkp = stkp + INTSIZE; + +} + +/* + * divide the secondary register by the primary + * (quotient in primary, remainder in secondary) + * + */ +void gdiv(void) +{ + gcall ("^sdiv"); + stkp = stkp + INTSIZE; + +} + +/* + * compute the remainder (mod) of the secondary register + * divided by the primary register + * (remainder in primary, quotient in secondary) + * + */ +void gmod(void) +{ + gcall ("^smod"); + stkp = stkp + INTSIZE; + +} + +/* + * inclusive 'or' the primary and secondary registers + * + */ +void gor(void) +{ + ol ("ora\t(s)+\n\torb\t(s)+"); + stkp = stkp + INTSIZE; + +} + +/* + * exclusive 'or' the primary and secondary registers + * + */ +void gxor(void) +{ + ol ("eora\t(s)+\n\teorb\t(s)+"); + stkp = stkp + INTSIZE; + +} + +/* + * 'and' the primary and secondary registers + * + */ +void gand(void) +{ + ol ("anda\t(s)+\n\tandb\t(s)+"); + stkp = stkp + INTSIZE; + +} + +/* + * arithmetic shift right the secondary register the number of + * times in the primary register + * (results in primary register) + * + */ +void gasr(void) +{ + gcall ("^asr"); + stkp = stkp + INTSIZE; + +} + +/* + * arithmetic shift left the secondary register the number of + * times in the primary register + * (results in primary register) + * + */ +void gasl(void) +{ + gcall ("^asl"); + stkp = stkp + INTSIZE; + +} + +/* + * two's complement of primary register + * + */ +void gneg(void) +{ + gcall ("^neg"); + +} + +/* + * logical complement of primary register + * + */ +void glneg(void) +{ + gcall ("^lneg"); + +} + +/* + * one's complement of primary register + * + */ +void gcom(void) +{ + ol ("coma\n\tcomb"); + +} + +/* + * convert primary register into logical value + * + */ +void gbool(void) +{ + gcall ("^bool"); +} + +/* + * increment the primary register by 1 if char, INTSIZE if + * int + */ +void ginc (int lval[]) +{ + if (lval[2] == CINT) + ol ("addd\t#2"); + else + ol ("addd\t#1"); + +} + +/* + * decrement the primary register by one if char, INTSIZE if + * int + */ +void gdec(int lval[]) +{ + if (lval[2] == CINT) + ol ("subd\t#2"); + else + ol ("subd\t#1"); + +} + +/* + * following are the conditional operators. + * they compare the secondary register against the primary register + * and put a literl 1 in the primary if the condition is true, + * otherwise they clear the primary register + * + */ + +/* + * equal + * + */ +void geq(void) +{ + gcall ("^eq"); + stkp = stkp + INTSIZE; + +} + +/* + * not equal + * + */ +void gne(void) +{ + gcall ("^ne"); + stkp = stkp + INTSIZE; + +} + +/* + * less than (signed) + * + */ +void glt(void) +{ + gcall ("^lt"); + stkp = stkp + INTSIZE; +} + +/* + * less than or equal (signed) + * + */ +void gle(void) +{ + gcall ("^le"); + stkp = stkp + INTSIZE; + +} + +/* + * greater than (signed) + * + */ +void ggt(void) +{ + gcall ("^gt"); + stkp = stkp + INTSIZE; + +} + +/* + * greater than or equal (signed) + * + */ +void gge(void) +{ + gcall ("^ge"); + stkp = stkp + INTSIZE; + +} + +/* + * less than (unsigned) + * + */ +void gult(void) +{ + gcall ("^ult"); + stkp = stkp + INTSIZE; + +} + +/* + * less than or equal (unsigned) + * + */ +void gule(void) +{ + gcall ("^ule"); + stkp = stkp + INTSIZE; + +} + +/* + * greater than (unsigned) + * + */ +void gugt(void) +{ + gcall ("^ugt"); + stkp = stkp + INTSIZE; + +} + +/* + * greater than or equal (unsigned) + * + */ +void guge(void) +{ + gcall ("^uge"); + stkp = stkp + INTSIZE; + +} + +char *inclib(void) { +#ifdef flex + return("B."); +#endif +#ifdef unix + return(INCDIR); +#endif +#ifdef cpm + return("B:"); +#endif + +} + +/* Squirrel away argument count in a register that modstk/getloc/stloc + doesn't touch. +*/ + +void gnargs(int d) +{ + ot ("ldu\t#"); + onum(d); + newline(); + +} + +#endif diff --git a/Applications/SmallC/code8080.c b/Applications/SmallC/code8080.c new file mode 100644 index 00000000..847ff5cd --- /dev/null +++ b/Applications/SmallC/code8080.c @@ -0,0 +1,798 @@ +/* File code8080.c: 2.2 (84/08/31,10:05:09) */ +/*% cc -O -c % + * + */ + +#include +#include "defs.h" +#include "data.h" + +#ifdef M8080 + +/* Define ASNM and LDNM to the names of the assembler and linker + respectively */ + +/* + * Some predefinitions: + * + * INTSIZE is the size of an integer in the target machine + * BYTEOFF is the offset of an byte within an integer on the + * target machine. (ie: 8080,pdp11 = 0, 6809 = 1, + * 360 = 3) + * This compiler assumes that an integer is the SAME length as + * a pointer - in fact, the compiler uses INTSIZE for both. + */ + +/** + * print all assembler info before any code is generated + */ +void header (void) { + output_string ("; Small C 8080\n;\tCoder (2.4,84/11/27)\n;"); + frontend_version(); + newline (); + output_line ("\t;program area SMALLC_GENERATED is RELOCATABLE"); + output_line ("\t.module SMALLC_GENERATED"); + output_line ("\t.list (err, loc, bin, eqt, cyc, lin, src, lst, md)"); + output_line ("\t.nlist (pag)"); +} + +/** + * prints new line + * @return + */ +void newline (void) { +#if __CYGWIN__ == 1 + output_byte (CR); +#endif + output_byte (LF); +} + +void initmac(void) { + defmac("cpm\t1"); + defmac("I8080\t1"); + defmac("RMAC\t1"); + defmac("smallc\t1"); +} + +/** + * Output internal generated label prefix + */ +void output_label_prefix(void) { + output_byte('$'); +} + +/** + * Output a label definition terminator + */ +void output_label_terminator (void) { + output_byte (':'); +} + +/** + * begin a comment line for the assembler + */ +void gen_comment(void) { + output_byte (';'); +} + +/** + * print any assembler stuff needed after all code + */ +void trailer(void) { + output_line (";\t.end"); +} + +/** + * text (code) segment + */ +void code_segment_gtext(void) { + output_line ("\t.area SMALLC_GENERATED (REL,CON,CSEG)"); +} + +/** + * data segment + */ +void data_segment_gdata(void) { + output_line ("\t.area SMALLC_GENERATED_DATA (REL,CON,DSEG)"); +} + +/** + * Output the variable symbol at scptr as an extrn or a public + * @param scptr + */ +void ppubext(SYMBOL *scptr) { + if (symbol_table[current_symbol_table_idx].storage == STATIC) return; + output_with_tab (scptr->storage == EXTERN ? ";extrn\t" : ".globl\t"); + output_string (scptr->name); + newline(); +} + +/** + * Output the function symbol at scptr as an extrn or a public + * @param scptr + */ +void fpubext(SYMBOL *scptr) { + if (scptr->storage == STATIC) return; + output_with_tab (scptr->offset == FUNCTION ? ".globl\t" : ";extrn\t"); + output_string (scptr->name); + newline (); +} + +/** + * Output a decimal number to the assembler file, with # prefix + * @param num + */ +void output_number(int num) { + output_byte('#'); + output_decimal(num); +} + +/** + * fetch a static memory cell into the primary register + * @param sym + */ +void gen_get_memory(SYMBOL *sym) { + if ((sym->identity != POINTER) && (sym->type == CCHAR)) { + output_with_tab ("lda\t"); + output_string (sym->name); + newline (); + gen_call ("ccsxt"); + } else if ((sym->identity != POINTER) && (sym->type == UCHAR)) { + output_with_tab("lda\t"); + output_string(sym->name); + newline(); + output_line("mov \tl,a"); + output_line("mvi \th,#0"); + } else { + output_with_tab ("lhld\t"); + output_string (sym->name); + newline (); + } +} + +/** + * asm - fetch the address of the specified symbol into the primary register + * @param sym the symbol name + * @return which register pair contains result + */ +int gen_get_locale(SYMBOL *sym) { + if (sym->storage == LSTATIC) { + gen_immediate(); + print_label(sym->offset); + newline(); + return HL_REG; + } else { + if (uflag && !(sym->identity == ARRAY)) {// || + //(sym->identity == VARIABLE && sym->type == STRUCT))) { + output_with_tab("ldsi\t"); + output_number(sym->offset - stkp); + newline (); + return DE_REG; + } else { + gen_immediate(); + output_number(sym->offset - stkp); + newline (); + output_line ("dad \tsp"); + return HL_REG; + } + } +} + +/** + * asm - store the primary register into the specified static memory cell + * @param sym + */ +void gen_put_memory(SYMBOL *sym) { + if ((sym->identity != POINTER) && (sym->type & CCHAR)) { + output_line ("mov \ta,l"); + output_with_tab ("sta \t"); + } else { + output_with_tab ("shld\t"); + } + output_string (sym->name); + newline (); +} + +/** + * store the specified object type in the primary register + * at the address in secondary register (on the top of the stack) + * @param typeobj + */ +void gen_put_indirect(char typeobj) { + gen_pop (); + if (typeobj & CCHAR) { + //gen_call("ccpchar"); + output_line("mov \ta,l"); + output_line("stax\td"); + } else { + if (uflag) { + output_line("shlx"); + } else { + gen_call("ccpint"); + } + } +} + +/** + * fetch the specified object type indirect through the primary + * register into the primary register + * @param typeobj object type + */ +void gen_get_indirect(char typeobj, int reg) { + if (typeobj == CCHAR) { + if (reg & DE_REG) { + gen_swap(); + } + gen_call("ccgchar"); + } else if (typeobj == UCHAR) { + if (reg & DE_REG) { + gen_swap(); + } + //gen_call("cguchar"); + output_line("mov \tl,m"); + output_line("mvi \th,0"); + } else { // int + if (uflag) { + if (reg & HL_REG) { + gen_swap(); + } + output_line("lhlx"); + } else { + gen_call("ccgint"); + } + } +} + +/** + * swap the primary and secondary registers + */ +void gen_swap(void) { + output_line("xchg"); +} + +/** + * print partial instruction to get an immediate value into + * the primary register + */ +void gen_immediate(void) { + output_with_tab ("lxi \th,"); +} + +/** + * push the primary register onto the stack + */ +void gen_push(int reg) { + if (reg & DE_REG) { + output_line ("push\td"); + stkp = stkp - INTSIZE; + } else { + output_line ("push\th"); + stkp = stkp - INTSIZE; + } +} + +/** + * pop the top of the stack into the secondary register + */ +void gen_pop(void) { + output_line ("pop \td"); + stkp = stkp + INTSIZE; +} + +/** + * swap the primary register and the top of the stack + */ +void gen_swap_stack(void) { + output_line ("xthl"); +} + +/** + * call the specified subroutine name + * @param sname subroutine name + */ +void gen_call(char *sname) { + output_with_tab ("call\t"); + output_string (sname); + newline (); +} + +/** + * declare entry point + */ +void declare_entry_point(char *symbol_name) { + output_string(symbol_name); + output_label_terminator(); + //newline(); +} + +/** + * return from subroutine + */ +void gen_ret(void) { + output_line ("ret"); +} + +/** + * perform subroutine call to value on top of stack + */ +void callstk(void) { + gen_immediate (); + output_string ("#.+5"); + newline (); + gen_swap_stack (); + output_line ("pchl"); + stkp = stkp + INTSIZE; +} + +/** + * jump to specified internal label number + * @param label the label + */ +void gen_jump(int label) +{ + output_with_tab ("jmp \t"); + print_label (label); + newline (); +} + +/** + * test the primary register and jump if false to label + * @param label the label + * @param ft if true jnz is generated, jz otherwise + */ +void gen_test_jump(int label, int ft) +{ + output_line ("mov \ta,h"); + output_line ("ora \tl"); + if (ft) + output_with_tab ("jnz \t"); + else + output_with_tab ("jz \t"); + print_label (label); + newline (); +} + +/** + * print pseudo-op to define a byte + */ +void gen_def_byte(void) { + output_with_tab (".db\t"); +} + +/** + * print pseudo-op to define storage + */ +void gen_def_storage(void) { + output_with_tab (".ds\t"); +} + +/** + * print pseudo-op to define a word + */ +void gen_def_word(void) { + output_with_tab (".dw\t"); +} + +/** + * modify the stack pointer to the new value indicated + * @param newstkp new value + */ +int gen_modify_stack(int newstkp) { + int k; + + k = newstkp - stkp; + if (k == 0) + return (newstkp); + if (k > 0) { + if (k < 7) { + if (k & 1) { + output_line ("inx \tsp"); + k--; + } + while (k) { + output_line ("pop \tb"); + k = k - INTSIZE; + } + return (newstkp); + } + } else { + if (k > -7) { + if (k & 1) { + output_line ("dcx \tsp"); + k++; + } + while (k) { + output_line ("push\tb"); + k = k + INTSIZE; + } + return (newstkp); + } + } + gen_swap (); + gen_immediate (); + output_number (k); + newline (); + output_line ("dad \tsp"); + output_line ("sphl"); + gen_swap (); + return (newstkp); +} + +/** + * multiply the primary register by INTSIZE + */ +void gen_multiply_by_two(void) { + output_line ("dad \th"); +} + +/** + * divide the primary register by INTSIZE, never used + */ +void gen_divide_by_two(void) { + gen_push(HL_REG); /* push primary in prep for gasr */ + gen_immediate (); + output_number (1); + newline (); + gen_arithm_shift_right (); /* divide by two */ +} + +/** + * Case jump instruction + */ +void gen_jump_case(void) { + output_with_tab ("jmp \tcccase"); + newline (); +} + +/** + * add the primary and secondary registers + * if lval2 is int pointer and lval is not, scale lval + * @param lval + * @param lval2 + */ +void gen_add(LVALUE *lval, LVALUE *lval2) { + gen_pop (); + if (dbltest (lval2, lval)) { + gen_swap (); + gen_multiply_by_two (); + gen_swap (); + } + output_line ("dad \td"); +} + +/** + * subtract the primary register from the secondary + */ +void gen_sub(void) { + gen_pop (); + gen_call ("ccsub"); +} + +/** + * multiply the primary and secondary registers (result in primary) + */ +void gen_mult(void) { + gen_pop(); + gen_call ("ccmul"); +} + +/** + * divide the secondary register by the primary + * (quotient in primary, remainder in secondary) + */ +void gen_div(void) { + gen_pop(); + gen_call ("ccdiv"); +} + +/** + * unsigned divide the secondary register by the primary + * (quotient in primary, remainder in secondary) + */ +void gen_udiv(void) { + gen_pop(); + gen_call ("ccudiv"); +} + +/** + * compute the remainder (mod) of the secondary register + * divided by the primary register + * (remainder in primary, quotient in secondary) + */ +void gen_mod(void) { + gen_div (); + gen_swap (); +} + +/** + * compute the remainder (mod) of the secondary register + * divided by the primary register + * (remainder in primary, quotient in secondary) + */ +void gen_umod(void) { + gen_udiv (); + gen_swap (); +} + +/** + * inclusive 'or' the primary and secondary registers + */ +void gen_or(void) { + gen_pop(); + gen_call ("ccor"); +} + +/** + * exclusive 'or' the primary and secondary registers + */ +void gen_xor(void) { + gen_pop(); + gen_call ("ccxor"); +} + +/** + * 'and' the primary and secondary registers + */ +void gen_and(void) { + gen_pop(); + gen_call ("ccand"); +} + +/** + * arithmetic shift right the secondary register the number of + * times in the primary register (results in primary register) + */ +void gen_arithm_shift_right(void) { + gen_pop(); + gen_call ("ccasr"); +} + +/** + * logically shift right the secondary register the number of + * times in the primary register (results in primary register) + */ +void gen_logical_shift_right(void) { + gen_pop(); + gen_call ("cclsr"); +} + +/** + * arithmetic shift left the secondary register the number of + * times in the primary register (results in primary register) + */ +void gen_arithm_shift_left(void) { + gen_pop (); + gen_call ("ccasl"); +} + +/** + * two's complement of primary register + */ +void gen_twos_complement(void) { + gen_call ("ccneg"); +} + +/** + * logical complement of primary register + */ +void gen_logical_negation(void) { + gen_call ("cclneg"); +} + +/** + * one's complement of primary register + */ +void gen_complement(void) { + gen_call ("cccom"); +} + +/** + * Convert primary value into logical value (0 if 0, 1 otherwise) + */ +void gen_convert_primary_reg_value_to_bool(void) { + gen_call ("ccbool"); +} + +/** + * increment the primary register by 1 if char, INTSIZE if int + */ +void gen_increment_primary_reg(LVALUE *lval) { + switch (lval->ptr_type) { + case STRUCT: + gen_immediate2(); + output_number(lval->tagsym->size); + newline(); + output_line("dad \td"); + break ; + case CINT: + case UINT: + output_line("inx \th"); + default: + output_line("inx \th"); + break; + } +} + +/** + * decrement the primary register by one if char, INTSIZE if int + */ +void gen_decrement_primary_reg(LVALUE *lval) { + output_line("dcx \th"); + switch (lval->ptr_type) { + case CINT: + case UINT: + output_line("dcx \th"); + break; + case STRUCT: + gen_immediate2(); + output_number(lval->tagsym->size - 1); + newline(); + // two's complement + output_line("mov \ta,d"); + output_line("cma"); + output_line("mov \td,a"); + output_line("mov \ta,e"); + output_line("cma"); + output_line("mov \te,a"); + output_line("inx \td"); + // substract + output_line("dad \td"); + break ; + default: + break; + } +} + +/** + * following are the conditional operators. + * they compare the secondary register against the primary register + * and put a literal 1 in the primary if the condition is true, + * otherwise they clear the primary register + */ + +/** + * equal + */ +void gen_equal(void) { + gen_pop(); + gen_call ("cceq"); +} + +/** + * not equal + */ +void gen_not_equal(void) { + gen_pop(); + gen_call ("ccne"); +} + +/** + * less than (signed) + */ +void gen_less_than(void) { + gen_pop(); + gen_call ("cclt"); +} + +/** + * less than or equal (signed) + */ +void gen_less_or_equal(void) { + gen_pop(); + gen_call ("ccle"); +} + +/** + * greater than (signed) + */ +void gen_greater_than(void) { + gen_pop(); + gen_call ("ccgt"); +} + +/** + * greater than or equal (signed) + */ +void gen_greater_or_equal(void) { + gen_pop(); + gen_call ("ccge"); +} + +/** + * less than (unsigned) + */ +void gen_unsigned_less_than(void) { + gen_pop(); + gen_call ("ccult"); +} + +/** + * less than or equal (unsigned) + */ +void gen_unsigned_less_or_equal(void) { + gen_pop(); + gen_call ("ccule"); +} + +/** + * greater than (unsigned) + */ +void gen_usigned_greater_than(void) { + gen_pop(); + gen_call ("ccugt"); +} + +/** + * greater than or equal (unsigned) + */ +void gen_unsigned_greater_or_equal(void) { + gen_pop(); + gen_call ("ccuge"); +} + +char *inclib(void) { +#ifdef cpm + return("B:"); +#endif +#ifdef unix +#ifdef INCDIR + return(INCDIR); +#else + return ""; +#endif +#endif +} + +/** + * Squirrel away argument count in a register that modstk doesn't touch. + * @param d + */ +void gnargs(int d) +{ + output_with_tab ("mvi \ta,"); + output_number(d); + newline (); +} + +/** + * print partial instruction to get an immediate value into + * the secondary register + */ +void gen_immediate2(void) { + output_with_tab ("lxi \td,"); +} + +/** + * add offset to primary register + * @param val the value + */ +void add_offset(int val) { + gen_immediate2(); + output_number(val); + newline(); + output_line ("dad \td"); +} + +/** + * multiply the primary register by the length of some variable + * @param type + * @param size + */ +void gen_multiply(int type, int size) { + switch (type) { + case CINT: + case UINT: + gen_multiply_by_two(); + break; + case STRUCT: + gen_immediate2(); + output_number(size); + newline(); + gen_call("ccmul"); + break ; + default: + break; + } +} + +#endif diff --git a/Applications/SmallC/data.c b/Applications/SmallC/data.c new file mode 100644 index 00000000..d6c97401 --- /dev/null +++ b/Applications/SmallC/data.c @@ -0,0 +1,65 @@ +/* File data.c: 2.2 (84/11/27,16:26:13) */ +/*% cc -O -c % + * + */ + +#include +#include "defs.h" + +/* storage words */ +SYMBOL symbol_table[NUMBER_OF_GLOBALS + NUMBER_OF_LOCALS]; +int global_table_index, rglobal_table_index; +int local_table_index; + +WHILE ws[WSTABSZ]; +int while_table_index; + +int swstcase[SWSTSZ]; +int swstlab[SWSTSZ]; +int swstp; +char litq[LITABSZ]; +int litptr; +char macq[MACQSIZE]; +int macptr; +char line[LINESIZE]; +char mline[LINESIZE]; +int lptr, mptr; + +TAG_SYMBOL tag_table[NUMTAG]; // start of structure tag table +int tag_table_index; // ptr to next entry + +SYMBOL member_table[NUMMEMB]; // structure member table +int member_table_index; // ptr to next member + +/* miscellaneous storage */ +int nxtlab, + litlab, + stkp, + argstk, + ncmp, + errcnt, + glbflag, + ctext, + cmode, + lastst; + +int input, input2, output; +int inclstk[INCLSIZ] = {-1, -1, -1 }; +int inclsp; +char fname[20]; +char input_eof; + +//char quote[2]; +int current_symbol_table_idx; //char *cptr; +int *iptr; +int fexitlab; +int iflevel, skiplevel; +int errfile; +int cflag; +int errs; +int aflag; +int uflag; // undocumented 8085 instructions + +INITIALS initials_table[NUMBER_OF_GLOBALS]; +char initials_data_table[INITIALS_SIZE]; // 5kB space for initialisation data +int initials_idx = 0, initials_data_idx = 0; diff --git a/Applications/SmallC/data.h b/Applications/SmallC/data.h new file mode 100644 index 00000000..2ca78fcf --- /dev/null +++ b/Applications/SmallC/data.h @@ -0,0 +1,57 @@ +/* File data.h: 2.2 (84/11/27,16:26:11) */ + +/* storage words */ +extern SYMBOL symbol_table[NUMBER_OF_GLOBALS + NUMBER_OF_LOCALS]; +extern int global_table_index, rglobal_table_index; +extern int local_table_index; +extern WHILE ws[]; +extern int while_table_index; +extern int swstcase[]; +extern int swstlab[]; +extern int swstp; +extern char litq[]; +extern int litptr; +extern char macq[]; +extern int macptr; +extern char line[]; +extern char mline[]; +extern int lptr, mptr; + +extern TAG_SYMBOL tag_table[NUMTAG]; // start of structure tag table +extern int tag_table_index; // ptr to next entry + +extern SYMBOL member_table[NUMMEMB]; // structure member table +extern int member_table_index; // ptr to next member< + +/* miscellaneous storage */ +extern int nxtlab, + litlab, + stkp, + argstk, + ncmp, + errcnt, + glbflag, + ctext, + cmode, + lastst; + +extern int input, input2, output; +extern int inclstk[]; +extern int inclsp; +extern char fname[]; +extern char input_eof; + +extern char quote[]; +extern int current_symbol_table_idx; //extern char *cptr; +extern int *iptr; +extern int fexitlab; +extern int iflevel, skiplevel; +extern int errfile; +extern int cflag; +extern int errs; +extern int aflag; +extern int uflag; // undocumented 8085 instructions + +extern INITIALS initials_table[NUMBER_OF_GLOBALS]; +extern char initials_data_table[INITIALS_SIZE]; // 5kB space for initialisation data +extern int initials_idx, initials_data_idx; diff --git a/Applications/SmallC/defs.h b/Applications/SmallC/defs.h new file mode 100644 index 00000000..c6fbc22e --- /dev/null +++ b/Applications/SmallC/defs.h @@ -0,0 +1,225 @@ +/* + * File defs.h: 2.1 (83/03/21,02:07:20) + */ + +// Intel 8080 architecture defs +#if defined(M6809) || defined(M8080) +#define INTSIZE 2 +#endif + +// miscellaneous +#define FOREVER for(;;) +#define FALSE 0 +#define TRUE 1 +#define NO 0 +#define YES 1 + +#define EOS 0 +#define LF 10 +#define BKSP 8 +#define CR 13 +#define FFEED 12 +#define TAB 9 + +#ifdef TINY +#define NAMESIZE 17 +#define NAMEMAX 16 +#else +// system-wide name size (for symbols) +#define NAMESIZE 33 +#define NAMEMAX 32 +#endif + +struct symbol { + char name[NAMESIZE]; // symbol name + unsigned char identity; // variable, array, pointer, function + unsigned char storage; // public, auto, extern, static, lstatic, defauto + int type; // char, int, uchar, unit + int offset; // offset + int tagidx; // index of struct in tag table +}; +#define SYMBOL struct symbol + +#define NUMBER_OF_GLOBALS 100 +#define NUMBER_OF_LOCALS 20 + +// Define the structure tag table parameters +#define NUMTAG 10 + +struct tag_symbol { + char name[NAMESIZE]; // structure tag name + int size; // size of struct in bytes + int member_idx; // index of first member + int number_of_members; // number of tag members +}; +#define TAG_SYMBOL struct tag_symbol + +#ifdef SMALL_C +#define NULL_TAG 0 +#else +#define NULL_TAG (TAG_SYMBOL *)0 +#endif + +// Define the structure member table parameters +#define NUMMEMB 30 + +// possible entries for "ident" +#define VARIABLE 1 +#define ARRAY 2 +#define POINTER 3 +#define FUNCTION 4 + +/** + * possible entries for "type" + * high order 14 bits give length of object + * low order 2 bits make type unique within length + */ +#define UNSIGNED 1 +#define STRUCT 2 +#define CCHAR (1 << 2) +#define UCHAR ((1 << 2) + 1) +#define CINT (2 << 2) +#define UINT ((2 << 2) + 1) + +// possible entries for storage +#define PUBLIC 1 +#define AUTO 2 +#define EXTERN 3 + +#define STATIC 4 +#define LSTATIC 5 +#define DEFAUTO 6 + +// "do"/"for"/"while"/"switch" statement stack +#define WSTABSZ 20 + +struct while_rec { + int symbol_idx; // symbol table address + int stack_pointer; // stack pointer + int type; // type + int case_test; // case or test + int incr_def; // continue label ? + int body_tab; // body of loop, switch ? + int while_exit; // exit label +}; +#define WHILE struct while_rec + +/* possible entries for "wstyp" */ +#define WSWHILE 0 +#define WSFOR 1 +#define WSDO 2 +#define WSSWITCH 3 + +/* "switch" label stack */ +#define SWSTSZ 100 + +/* literal pool */ +#ifdef TINY +#define LITABSZ 2500 +#else +#define LITABSZ 5000 +#endif +#define LITMAX LITABSZ-1 + +/* input line */ +#define LINESIZE 150 +#define LINEMAX (LINESIZE-1) +#define MPMAX LINEMAX + +#ifdef TINY +#define MACQSIZE 500 +#define MACMAX (MACQSIZE-1) +#else +/* macro (define) pool */ +#define MACQSIZE 1500 +#define MACMAX (MACQSIZE-1) +#endif + +/* "include" stack */ +#define INCLSIZ 3 + +/* statement types (tokens) */ +#define STIF 1 +#define STWHILE 2 +#define STRETURN 3 +#define STBREAK 4 +#define STCONT 5 +#define STASM 6 +#define STEXP 7 +#define STDO 8 +#define STFOR 9 +#define STSWITCH 10 + +#define DEFLIB inclib() + +#define FETCH 1 +#define HL_REG 1<<1 +#define DE_REG 1<<2 + +struct lvalue { + SYMBOL *symbol; // symbol table address, or 0 for constant + int indirect; // type of indirect object, 0 for static object + int ptr_type; // type of pointer or array, 0 for other idents + TAG_SYMBOL *tagsym; // tag symbol address, 0 if not struct +}; +#define LVALUE struct lvalue + +/** + * path to include directories. set at compile time on host machine + * @return + */ +char *inclib(void); + +/** + * Output the variable symbol at scptr as an extrn or a public + * @param scptr + */ +void ppubext(SYMBOL *scptr); + +/** + * Output the function symbol at scptr as an extrn or a public + * @param scptr + */ +void fpubext(SYMBOL *scptr); + +/** + * fetch a static memory cell into the primary register + * @param sym + */ +void gen_get_memory(SYMBOL *sym); + +/** + * fetch the specified object type indirect through the primary + * register into the primary register + * @param typeobj object type + */ +void gen_get_indirect(char typeobj, int reg); + +/** + * asm - store the primary register into the specified static memory cell + * @param sym + */ +void gen_put_memory(SYMBOL *sym); + +// initialisation of global variables +#define INIT_TYPE NAMESIZE +#define INIT_LENGTH NAMESIZE+1 +#define INITIALS_SIZE 5*1024 + +struct initials_table { + char name[NAMESIZE]; // symbol name + int type; // type + int dim; // length of data (possibly an array) + int data_len; // index of tag or zero +}; +#define INITIALS struct initials_table + +/** + * determine if 'sname' is a member of the struct with tag 'tag' + * @param tag + * @param sname + * @return pointer to member symbol if it is, else 0 + */ +SYMBOL *find_member(TAG_SYMBOL *tag, char *sname); + +#include "prototype.h" diff --git a/Applications/SmallC/error.c b/Applications/SmallC/error.c new file mode 100644 index 00000000..4de46c39 --- /dev/null +++ b/Applications/SmallC/error.c @@ -0,0 +1,45 @@ +/* File error.c: 2.1 (83/03/20,16:02:00) */ +/*% cc -O -c % + * + */ + +#include +#include "defs.h" +#include "data.h" + +void error (char *ptr) +{ + int tempfile; + + tempfile = output; + output = 1; + doerror(ptr); + output = tempfile; + doerror(ptr); + errcnt++; +} + +void doerror(char *ptr) +{ + int k; + gen_comment (); + output_string (line); + newline (); + gen_comment (); + k = 0; + while (k < lptr) { + if (line[k] == 9) + print_tab (); + else + output_byte (' '); + k++; + } + output_byte ('^'); + newline (); + gen_comment (); + output_string ("****** "); + output_string (ptr); + output_string (" ******"); + newline (); +} + diff --git a/Applications/SmallC/expr.c b/Applications/SmallC/expr.c new file mode 100644 index 00000000..f502393b --- /dev/null +++ b/Applications/SmallC/expr.c @@ -0,0 +1,787 @@ +/* + * File expr.c: 2.2 (83/06/21,11:24:26) + */ + +#include +#include "defs.h" +#include "data.h" + +/** + * unsigned operand ? + */ +int nosign(LVALUE *is) { + SYMBOL *ptr; + + if((is->ptr_type) || + ((ptr = is->symbol) && (ptr->type & UNSIGNED))) { + return 1; + } + return 0; +} + +/** + * lval.symbol - symbol table address, else 0 for constant + * lval.indirect - type indirect object to fetch, else 0 for static object + * lval.ptr_type - type pointer or array, else 0 + * @param comma + * @return + */ +void expression(int comma) { + LVALUE lval; + int k; + + do { + k = hier1 (&lval); + if (k & FETCH) + rvalue(&lval, k); + if (!comma) + return; + } while (match (",")); +} + +/** + * assignment operators + * @param lval + * @return + */ +int hier1 (LVALUE *lval) { + int k; + LVALUE lval2[1]; + char fc; + + k = hier1a (lval); + if (match ("=")) { + if ((k & FETCH) == 0) { + needlval (); + return (0); + } + if (lval->indirect) + gen_push(k); + k = hier1 (lval2); + if (k & FETCH) + k = rvalue(lval2, k); + store (lval); + return (0); + } else { + fc = ch(); + if (match ("-=") || + match ("+=") || + match ("*=") || + match ("/=") || + match ("%=") || + match (">>=") || + match ("<<=") || + match ("&=") || + match ("^=") || + match ("|=")) { + if ((k & FETCH) == 0) { + needlval (); + return (0); + } + if (lval->indirect) + gen_push(k); + k = rvalue(lval, k); + gen_push(k); + k = hier1 (lval2); + if (k & FETCH) + k = rvalue(lval2, k); + switch (fc) { + case '-': { + if (dbltest(lval,lval2)) { + gen_multiply(lval->ptr_type, lval->tagsym ? lval->tagsym->size : INTSIZE); + } + gen_sub(); + result (lval, lval2); + break; + } + case '+': { + if (dbltest(lval,lval2)) { + gen_multiply(lval->ptr_type, lval->tagsym ? lval->tagsym->size : INTSIZE); + } + gen_add (lval,lval2); + result(lval,lval2); + break; + } + case '*': gen_mult (); break; + case '/': + if(nosign(lval) || nosign(lval2)) { + gen_udiv(); + } else { + gen_div(); + } + break; + case '%': + if(nosign(lval) || nosign(lval2)) { + gen_umod(); + } else { + gen_mod(); + } + break; + case '>': + if (nosign(lval)) { + gen_logical_shift_right(); + } else { + gen_arithm_shift_right(); + } + break; + case '<': gen_arithm_shift_left(); break; + case '&': gen_and (); break; + case '^': gen_xor (); break; + case '|': gen_or (); break; + } + store (lval); + return (0); + } else + return (k); + } +} + +/** + * processes ? : expression + * @param lval + * @return 0 or 1, fetch or no fetch + */ +int hier1a (LVALUE *lval) { + int k, lab1, lab2; + LVALUE lval2[1]; + + k = hier1b (lval); + blanks (); + if (ch () != '?') + return (k); + if (k & FETCH) + k = rvalue(lval, k); + FOREVER + if (match ("?")) { + gen_test_jump (lab1 = getlabel (), FALSE); + k = hier1b (lval2); + if (k & FETCH) + k = rvalue(lval2, k); + gen_jump (lab2 = getlabel ()); + print_label (lab1); + output_label_terminator (); + newline (); + blanks (); + if (!match (":")) { + error ("missing colon"); + return (0); + } + k = hier1b (lval2); + if (k & FETCH) + k = rvalue(lval2, k); + print_label (lab2); + output_label_terminator (); + newline (); + } else + return (0); +} + +/** + * processes logical or || + * @param lval + * @return 0 or 1, fetch or no fetch + */ +int hier1b (LVALUE *lval) { + int k, lab; + LVALUE lval2[1]; + + k = hier1c (lval); + blanks (); + if (!sstreq ("||")) + return (k); + if (k & FETCH) + k = rvalue(lval, k); + FOREVER + if (match ("||")) { + gen_test_jump (lab = getlabel (), TRUE); + k = hier1c (lval2); + if (k & FETCH) + k = rvalue(lval2, k); + print_label (lab); + output_label_terminator (); + newline (); + gen_convert_primary_reg_value_to_bool(); + } else + return (0); +} + +/** + * processes logical and && + * @param lval + * @return 0 or 1, fetch or no fetch + */ +int hier1c (LVALUE *lval) { + int k, lab; + LVALUE lval2[1]; + + k = hier2 (lval); + blanks (); + if (!sstreq ("&&")) + return (k); + if (k & FETCH) + k = rvalue(lval, k); + FOREVER + if (match ("&&")) { + gen_test_jump (lab = getlabel (), FALSE); + k = hier2 (lval2); + if (k & FETCH) + k = rvalue(lval2, k); + print_label (lab); + output_label_terminator (); + newline (); + gen_convert_primary_reg_value_to_bool(); + } else + return (0); +} + +/** + * processes bitwise or | + * @param lval + * @return 0 or 1, fetch or no fetch + */ +int hier2 (LVALUE *lval) { + int k; + LVALUE lval2[1]; + + k = hier3 (lval); + blanks (); + if ((ch() != '|') | (nch() == '|') | (nch() == '=')) + return (k); + if (k & FETCH) + k = rvalue(lval, k); + FOREVER { + if ((ch() == '|') & (nch() != '|') & (nch() != '=')) { + inbyte (); + gen_push(k); + k = hier3 (lval2); + if (k & FETCH) + k = rvalue(lval2, k); + gen_or (); + blanks(); + } else + return (0); + } +} + +/** + * processes bitwise exclusive or + * @param lval + * @return 0 or 1, fetch or no fetch + */ +int hier3 (LVALUE *lval) { + int k; + LVALUE lval2[1]; + + k = hier4 (lval); + blanks (); + if ((ch () != '^') | (nch() == '=')) + return (k); + if (k & FETCH) + k = rvalue(lval, k); + FOREVER { + if ((ch() == '^') & (nch() != '=')){ + inbyte (); + gen_push(k); + k = hier4 (lval2); + if (k & FETCH) + k = rvalue(lval2, k); + gen_xor (); + blanks(); + } else + return (0); + } +} + +/** + * processes bitwise and & + * @param lval + * @return 0 or 1, fetch or no fetch + */ +int hier4 (LVALUE *lval) { + int k; + LVALUE lval2[1]; + + k = hier5 (lval); + blanks (); + if ((ch() != '&') | (nch() == '|') | (nch() == '=')) + return (k); + if (k & FETCH) + k = rvalue(lval, k); + FOREVER { + if ((ch() == '&') & (nch() != '&') & (nch() != '=')) { + inbyte (); + gen_push(k); + k = hier5 (lval2); + if (k & FETCH) + k = rvalue(lval2, k); + gen_and (); + blanks(); + } else + return (0); + } + +} + +/** + * processes equal and not equal operators + * @param lval + * @return 0 or 1, fetch or no fetch + */ +int hier5 (LVALUE *lval) { + int k; + LVALUE lval2[1]; + + k = hier6 (lval); + blanks (); + if (!sstreq ("==") & + !sstreq ("!=")) + return (k); + if (k & FETCH) + k = rvalue(lval, k); + FOREVER { + if (match ("==")) { + gen_push(k); + k = hier6 (lval2); + if (k & FETCH) + k = rvalue(lval2, k); + gen_equal (); + } else if (match ("!=")) { + gen_push(k); + k = hier6 (lval2); + if (k & FETCH) + k = rvalue(lval2, k); + gen_not_equal (); + } else + return (0); + } + +} + +/** + * comparison operators + * @param lval + * @return 0 or 1, fetch or no fetch + */ +int hier6 (LVALUE *lval) { + int k; + LVALUE lval2[1]; + + k = hier7 (lval); + blanks (); + if (!sstreq ("<") && + !sstreq ("<=") && + !sstreq (">=") && + !sstreq (">")) + return (k); + if (sstreq ("<<") || sstreq (">>")) + return (k); + if (k & FETCH) + k = rvalue(lval, k); + FOREVER { + if (match ("<=")) { + gen_push(k); + k = hier7 (lval2); + if (k & FETCH) + k = rvalue(lval2, k); + if (nosign(lval) || nosign(lval2)) { + gen_unsigned_less_or_equal (); + continue; + } + gen_less_or_equal (); + } else if (match (">=")) { + gen_push(k); + k = hier7 (lval2); + if (k & FETCH) + k = rvalue(lval2, k); + if (nosign(lval) || nosign(lval2)) { + gen_unsigned_greater_or_equal (); + continue; + } + gen_greater_or_equal(); + } else if ((sstreq ("<")) && + !sstreq ("<<")) { + inbyte (); + gen_push(k); + k = hier7 (lval2); + if (k & FETCH) + k = rvalue(lval2, k); + if (nosign(lval) || nosign(lval2)) { + gen_unsigned_less_than (); + continue; + } + gen_less_than (); + } else if ((sstreq (">")) && + !sstreq (">>")) { + inbyte (); + gen_push(k); + k = hier7 (lval2); + if (k & FETCH) + k = rvalue(lval2, k); + if (nosign(lval) || nosign(lval2)) { + gen_usigned_greater_than (); + continue; + } + gen_greater_than(); + } else + return (0); + blanks (); + } + +} + +/** + * bitwise left, right shift + * @param lval + * @return 0 or 1, fetch or no fetch + */ +int hier7 (LVALUE *lval) { + int k; + LVALUE lval2[1]; + + k = hier8(lval); + blanks(); + if ((!sstreq (">>") && + !sstreq ("<<")) || sstreq(">>=") || sstreq("<<=")) + return (k); + if (k & FETCH) + k = rvalue(lval, k); + FOREVER { + if (sstreq(">>") && ! sstreq(">>=")) { + inbyte(); inbyte(); + gen_push(k); + k = hier8 (lval2); + if (k & FETCH) + k = rvalue(lval2, k); + if (nosign(lval)) { + gen_logical_shift_right(); + } else { + gen_arithm_shift_right(); + } + } else if (sstreq("<<") && ! sstreq("<<=")) { + inbyte(); inbyte(); + gen_push(k); + k = hier8 (lval2); + if (k & FETCH) + k = rvalue(lval2, k); + gen_arithm_shift_left(); + } else + return (0); + blanks(); + } + +} + +/** + * addition, subtraction + * @param lval + * @return 0 or 1, fetch or no fetch + */ +int hier8 (LVALUE *lval) { + int k; + LVALUE lval2[1]; + + k = hier9 (lval); + blanks (); + if ((ch () != '+') & (ch () != '-') | nch() == '=') + return (k); + if (k & FETCH) + k = rvalue(lval, k); + FOREVER { + if (match ("+")) { + gen_push(k); + k = hier9 (lval2); + if (k & FETCH) + k = rvalue(lval2, k); + // if left is pointer and right is int, scale right + if (dbltest(lval,lval2)) { + gen_multiply(lval->ptr_type, lval->tagsym ? lval->tagsym->size : INTSIZE); + } + // will scale left if right int pointer and left int + gen_add (lval,lval2); + result (lval, lval2); + } else if (match ("-")) { + gen_push(k); + k = hier9 (lval2); + if (k & FETCH) + k = rvalue(lval2, k); + /* if dbl, can only be: pointer - int, or + pointer - pointer, thus, + in first case, int is scaled up, + in second, result is scaled down. */ + if (dbltest(lval,lval2)) { + gen_multiply(lval->ptr_type, lval->tagsym ? lval->tagsym->size : INTSIZE); + } + gen_sub (); + /* if both pointers, scale result */ + if ((lval->ptr_type & CINT) && (lval2->ptr_type & CINT)) { + gen_divide_by_two(); /* divide by intsize */ + } + result (lval, lval2); + } else + return (0); + } +} + +/** + * multiplication, division, modulus + * @param lval + * @return 0 or 1, fetch or no fetch + */ +int hier9 (LVALUE *lval) { + int k; + LVALUE lval2[1]; + + k = hier10 (lval); + blanks (); + if (((ch () != '*') && (ch () != '/') && + (ch () != '%')) || (nch() == '=')) + return (k); + if (k & FETCH) + k = rvalue(lval, k); + FOREVER { + if (match ("*")) { + gen_push(k); + k = hier10 (lval2); + if (k & FETCH) + k = rvalue(lval2, k); + gen_mult (); + } else if (match ("/")) { + gen_push(k); + k = hier10 (lval2); + if (k & FETCH) + k = rvalue(lval2, k); + if(nosign(lval) || nosign(lval2)) { + gen_udiv(); + } else { + gen_div (); + } + } else if (match ("%")) { + gen_push(k); + k = hier10 (lval2); + if (k & FETCH) + k = rvalue(lval2, k); + if(nosign(lval) || nosign(lval2)) { + gen_umod(); + } else { + gen_mod (); + } + } else + return (0); + } + +} + +/** + * increment, decrement, negation operators + * @param lval + * @return 0 or 1, fetch or no fetch + */ +int hier10 (LVALUE *lval) { + int k; + SYMBOL *ptr; + + if (match ("++")) { + if (((k = hier10 (lval)) & FETCH) == 0) { + needlval (); + return (0); + } + if (lval->indirect) + gen_push(k); + k = rvalue(lval, k); + gen_increment_primary_reg (lval); + store (lval); + return (HL_REG); + } else if (match ("--")) { + if (((k = hier10 (lval)) & FETCH) == 0) { + needlval (); + return (0); + } + if (lval->indirect) + gen_push(k); + k = rvalue(lval, k); + gen_decrement_primary_reg (lval); + store (lval); + return (HL_REG); + } else if (match ("-")) { + k = hier10 (lval); + if (k & FETCH) + k = rvalue(lval, k); + gen_twos_complement(); + return (HL_REG); + } else if (match ("~")) { + k = hier10 (lval); + if (k & FETCH) + k = rvalue(lval, k); + gen_complement (); + return (HL_REG); + } else if (match ("!")) { + k = hier10 (lval); + if (k & FETCH) + k = rvalue(lval, k); + gen_logical_negation(); + return (HL_REG); + } else if (ch()=='*' && nch() != '=') { + inbyte(); + k = hier10 (lval); + if (k & FETCH) + k = rvalue(lval, k); + if ((ptr = lval->symbol) != 0) + lval->indirect = ptr->type; + else + lval->indirect = CINT; + lval->ptr_type = 0; // flag as not pointer or array + return FETCH | k; + } else if (ch()=='&' && nch()!='&' && nch()!='=') { + inbyte(); + k = hier10 (lval); + if ((k & FETCH) == 0) { + error ("illegal address"); + return (0); + } + ptr = lval->symbol; + lval->ptr_type = ptr->type; + if (lval->indirect) { + if (k & DE_REG) { + gen_swap(); + } + return (HL_REG); + } + // global and non-array + gen_immediate (); + output_string ((ptr = lval->symbol)->name); + newline (); + lval->indirect = ptr->type; + return (HL_REG); + } else { + k = hier11 (lval); + if (match ("++")) { + if ((k & FETCH) == 0) { + needlval (); + return (0); + } + if (lval->indirect) + gen_push(k); + k = rvalue(lval, k); + gen_increment_primary_reg (lval); + store (lval); + gen_decrement_primary_reg (lval); + return (HL_REG); + } else if (match ("--")) { + if ((k & FETCH) == 0) { + needlval (); + return (0); + } + if (lval->indirect) + gen_push(k); + k = rvalue(lval, k); + gen_decrement_primary_reg (lval); + store (lval); + gen_increment_primary_reg (lval); + return (HL_REG); + } else + return (k); + } + +} + +/** + * array subscripting + * @param lval + * @return 0 or 1, fetch or no fetch + */ +int hier11(LVALUE *lval) { + int direct, k; + SYMBOL *ptr; + char sname[NAMESIZE]; + + k = primary(lval); + ptr = lval->symbol; + blanks(); + if ((ch () == '[') || (ch () == '(') || (ch () == '.') || ((ch () == '-') && (nch() == '>'))) + FOREVER { + if (match("[")) { + if (ptr == 0) { + error("can't subscript"); + junk(); + needbrack("]"); + return (0); + } else if (ptr->identity == POINTER) { + k = rvalue(lval, k); + } else if (ptr->identity != ARRAY) { + error("can't subscript"); + k = 0; + } + gen_push(k); + expression (YES); + needbrack ("]"); + gen_multiply(ptr->type, tag_table[ptr->tagidx].size); + gen_add (NULL,NULL); + //lval->symbol = 0; + lval->indirect = ptr->type; + lval->ptr_type = 0; + k = FETCH | HL_REG; + } else if (match ("(")) { + if (ptr == 0) { + callfunction(0); + } else if (ptr->identity != FUNCTION) { + k = rvalue(lval, k); + callfunction(0); + } else { + callfunction(ptr->name); + } + lval->symbol = 0; + k = 0; + } else if ((direct=match(".")) || match("->")) { + if (lval->tagsym == 0) { + error("can't take member"); + junk(); + return 0; + } + if (symname(sname) == 0 || + ((ptr=find_member(lval->tagsym, sname)) == 0)) { + error("unknown member"); + junk(); + return 0; + } + if ((k & FETCH) && direct == 0) { + k = rvalue(lval, k); + } + if (k == DE_REG) { + gen_swap(); + } + add_offset(ptr->offset); // move pointer from struct begin to struct member + lval->symbol = ptr; + lval->indirect = ptr->type; // lval->indirect = lval->val_type = ptr->type + lval->ptr_type = 0; + lval->tagsym = NULL_TAG; + if (ptr->type == STRUCT) { + lval->tagsym = &tag_table[ptr->tagidx]; + } + if (ptr->identity == POINTER) { + lval->indirect = CINT; + lval->ptr_type = ptr->type; + //lval->val_type = CINT; + } + if (ptr->identity==ARRAY || + (ptr->type==STRUCT && ptr->identity==VARIABLE)) { + // array or struct + lval->ptr_type = ptr->type; + //lval->val_type = CINT; + k = 0; + } else { + k = FETCH | HL_REG; + } + } + else return k; + } + if (ptr == 0) + return k; + if (ptr->identity == FUNCTION) { + gen_immediate(); + output_string(ptr->name); + newline(); + return 0; + } + return k; +} + diff --git a/Applications/SmallC/foo.c b/Applications/SmallC/foo.c new file mode 100644 index 00000000..6f189da0 --- /dev/null +++ b/Applications/SmallC/foo.c @@ -0,0 +1,2 @@ +poop() + diff --git a/Applications/SmallC/function.c b/Applications/SmallC/function.c new file mode 100644 index 00000000..ea4dc24d --- /dev/null +++ b/Applications/SmallC/function.c @@ -0,0 +1,196 @@ +/* + * File function.c: 2.1 (83/03/20,16:02:04) + */ + +#include +#include "defs.h" +#include "data.h" + +int argtop; + +/** + * begin a function + * called from "parse", this routine tries to make a function out + * of what follows + * modified version. p.l. woods + */ +void newfunc(void) { + char n[NAMESIZE]; + int idx, type; + fexitlab = getlabel(); + + if (!symname(n)) { + error("illegal function or declaration"); + do_kill(); + return; + } + if ((idx = find_global(n)) > -1) { + if (symbol_table[idx].identity != FUNCTION) + multidef(n); + else if (symbol_table[idx].offset == FUNCTION) + multidef(n); + else + symbol_table[idx].offset = FUNCTION; + } else + add_global(n, FUNCTION, CINT, FUNCTION, PUBLIC); + if (!match("(")) + error("missing open paren"); + output_string(n); + output_label_terminator(); + newline(); + local_table_index = NUMBER_OF_GLOBALS; //locptr = STARTLOC; + argstk = 0; + // ANSI style argument declaration + if (doAnsiArguments() == 0) { + // K&R style argument declaration + while (!match(")")) { + if (symname(n)) { + if (find_locale(n) > -1) + multidef(n); + else { + add_local(n, 0, 0, argstk, AUTO); + argstk = argstk + INTSIZE; + } + } else { + error("illegal argument name"); + junk(); + } + blanks(); + if (!streq(line + lptr, ")")) { + if (!match(",")) + error("expected comma"); + } + if (endst()) + break; + } + stkp = 0; + argtop = argstk; + while (argstk) { + if ((type = get_type()) != 0) { + getarg(type); + need_semicolon(); + } else { + error("wrong number args"); + break; + } + } + } + statement(YES); + print_label(fexitlab); + output_label_terminator(); + newline(); + gen_modify_stack(0); + gen_ret(); + stkp = 0; + local_table_index = NUMBER_OF_GLOBALS; //locptr = STARTLOC; +} + +/** + * declare argument types + * called from "newfunc", this routine adds an entry in the local + * symbol table for each named argument + * completely rewritten version. p.l. woods + * @param t argument type (char, int) + * @return + */ +void getarg(int t) { + int j, legalname, address, argptr; + char n[NAMESIZE]; + + FOREVER + { + if (argstk == 0) + return; + if (match("*")) + j = POINTER; + else + j = VARIABLE; + if (!(legalname = symname(n))) + illname(); + if (match("[")) { + while (inbyte() != ']') + if (endst()) + break; + j = POINTER; + } + if (legalname) { + if ((argptr = find_locale(n)) > -1) { + symbol_table[argptr].identity = j; + symbol_table[argptr].type = t; + address = argtop - symbol_table[argptr].offset; + symbol_table[argptr].offset = address; + } else + error("expecting argument name"); + } + argstk = argstk - INTSIZE; + if (endst()) + return; + if (!match(",")) + error("expected comma"); + } +} + +int doAnsiArguments(void) { + int type; + type = get_type(); + if (type == 0) { + return 0; // no type detected, revert back to K&R style + } + argtop = argstk; + argstk = 0; + FOREVER + { + if (type) { + doLocalAnsiArgument(type); + } else { + error("wrong number args"); + break; + } + if (match(",")) { + type = get_type(); + continue; + } + if (match(")")) { + break; + } + } + return 1; +} + +void doLocalAnsiArgument(int type) { + char symbol_name[NAMESIZE]; + int identity, address, argptr, ptr; + + if (match("*")) { + identity = POINTER; + } else { + identity = VARIABLE; + } + if (symname(symbol_name)) { + if (find_locale(symbol_name) > -1) { + multidef(symbol_name); + } else { + argptr = add_local (symbol_name, identity, type, 0, AUTO); + argstk = argstk + INTSIZE; + ptr = local_table_index; + while (ptr != NUMBER_OF_GLOBALS) { // modify stack offset as we push more params + ptr = ptr - 1; + address = symbol_table[ptr].offset; + symbol_table[ptr].offset = address + INTSIZE; + } + } + } else { + error("illegal argument name"); + junk(); + } + if (match("[")) { + while (inbyte() != ']') { + if (endst()) { + break; + } + } + identity = POINTER; + symbol_table[argptr].identity = identity; + } +} + diff --git a/Applications/SmallC/gen.c b/Applications/SmallC/gen.c new file mode 100644 index 00000000..46584dbc --- /dev/null +++ b/Applications/SmallC/gen.c @@ -0,0 +1,188 @@ +/* File gen.c: 2.1 (83/03/20,16:02:06) */ +/*% cc -O -c % + * + */ + +#include +#include +#include +#include +#include "defs.h" +#include "data.h" + +static char obuf[512]; +static char *optr = obuf; + +void oflush(void) +{ + if (write(output, obuf, optr-obuf) != optr-obuf) + error("I/O error"); + optr = obuf; +} + +/** + * return next available internal label number + */ +int getlabel(void) { + return (nxtlab++); +} + +/** + * print specified number as label + * @param label + */ +void print_label(int label) { + output_label_prefix (); + output_decimal (label); +} + +/** + * glabel - generate label + * not used ? + * @param lab label number + */ +void glabel(char *lab) { + output_string (lab); + output_label_terminator (); + newline (); +} + +/** + * gnlabel - generate numeric label + * @param nlab label number + * @return + */ +void generate_label(int nlab) { + print_label (nlab); + output_label_terminator (); + newline (); +} + +/** + * outputs one byte + * @param c + * @return + */ +int output_byte(char c) { + if (c == 0) + return (0); + if (optr == obuf + sizeof(obuf)) + oflush(); + *optr++ = c; +//FIX + oflush(); + return (c); +} + +/** + * outputs a string + * @param ptr the string + * @return + */ +void output_string(char ptr[]) { + int k; + k = 0; + while (output_byte (ptr[k++])); +} + +/** + * outputs a tab + * @return + */ +void print_tab(void) { + output_byte ('\t'); +} + +/** + * output line + * @param ptr + * @return + */ +void output_line(char ptr[]) +{ + output_with_tab (ptr); + newline (); +} + +/** + * tabbed output + * @param ptr + * @return + */ +void output_with_tab(char ptr[]) { + print_tab (); + output_string (ptr); +} + +#ifdef __linux__ +char *_itoa(int n) +{ + static char buf[32]; + snprintf(buf, 32, "%d", n); + return buf; +} +#endif + +/** + * output decimal number + * @param number + * @return + */ +void output_decimal(int number) { + char *p = _itoa(number); + output_string(p); +} + +/** + * stores values into memory + * @param lval + * @return + */ +void store(LVALUE *lval) { + if (lval->indirect == 0) + gen_put_memory (lval->symbol); + else + gen_put_indirect (lval->indirect); +} + +int rvalue(LVALUE *lval, int reg) { + if ((lval->symbol != 0) && (lval->indirect == 0)) + gen_get_memory (lval->symbol); + else + gen_get_indirect (lval->indirect, reg); + return HL_REG; +} + +/** + * parses test part "(expression)" input and generates assembly for jump + * @param label + * @param ft : false - test jz, true test jnz + * @return + */ +void test(int label, int ft) { + needbrack ("("); + expression (YES); + needbrack (")"); + gen_test_jump (label, ft); +} + +/** + * scale constant depending on type + * @param type + * @param otag + * @param size + * @return + */ +void scale_const(int type, int otag, int *size) { + switch (type) { + case CINT: + case UINT: + *size += *size; + break; + case STRUCT: + *size *= tag_table[otag].size; + break; + default: + break; + } +} diff --git a/Applications/SmallC/includes/ctype.h b/Applications/SmallC/includes/ctype.h new file mode 100644 index 00000000..07c42f3a --- /dev/null +++ b/Applications/SmallC/includes/ctype.h @@ -0,0 +1 @@ +/* Nothing needed in this file */ diff --git a/Applications/SmallC/includes/stdio.h b/Applications/SmallC/includes/stdio.h new file mode 100644 index 00000000..fcc9f117 --- /dev/null +++ b/Applications/SmallC/includes/stdio.h @@ -0,0 +1,6 @@ +#define stdin 0 +#define stdout 1 +#define stderr 2 +#define NULL 0 +#define EOF (-1) +#define FILE char diff --git a/Applications/SmallC/initials.c b/Applications/SmallC/initials.c new file mode 100644 index 00000000..bd39af79 --- /dev/null +++ b/Applications/SmallC/initials.c @@ -0,0 +1,141 @@ +#include +#include +#include "defs.h" +#include "data.h" + +/** + * erase the data storage + */ +void create_initials(void) { + /*int i; + for (i=0; i= NUMBER_OF_GLOBALS) { + error("initials table overrun"); + } + if (astreq (symbol_name, initials_table[initials_idx].name, NAMEMAX) != 0) { + result = 1; + break; + } else { // move to next symbol + // count position in data array + initials_data_idx += initials_table[initials_idx].data_len; + } + } + return result; +} + +/** + * add data to table for given symbol + * @param symbol_name + * @param type + * @param value + * @param tag + */ +void add_data_initials(char *symbol_name, int type, int value, TAG_SYMBOL *tag) { + int position; + if (find_symbol_initials(symbol_name) == 0) { + add_symbol_initials(symbol_name, tag == 0 ? type : STRUCT); + } + if (tag != 0) { + // find number of members, dim is total number of values added + int index = initials_table[initials_idx].dim % tag->number_of_members; + int member_type = member_table[tag->member_idx + index].type; + // add it recursively + add_data_initials(symbol_name, member_type, value, 0); + } else { + position = initials_table[initials_idx].data_len; + if (type & CCHAR) { + initials_data_table[initials_data_idx + position] = 0xff & value; + initials_table[initials_idx].data_len += 1; + } else if (type & CINT) { + initials_data_table[initials_data_idx + position] = (0xff00 & value) >> 8; + initials_data_table[initials_data_idx + position + 1] = 0xff & value; + initials_table[initials_idx].data_len += INTSIZE; + } + initials_table[initials_idx].dim += 1; + } +} + +/** + * get number of data items for given symbol + * @param symbol_name + * @return + */ +int get_size(char *symbol_name) { + int result = 0; + if (find_symbol_initials(symbol_name) != 0) { + result = initials_table[initials_idx].dim; + } + return result; +} + +/** + * get item at position + * @param symbol_name + * @param position + * @param itag index of tag in tag table + * @return + */ +int get_item_at(char *symbol_name, int position, TAG_SYMBOL *tag) { + int result = 0, i, type; + if (find_symbol_initials(symbol_name) != 0) { + if (initials_table[initials_idx].type & CCHAR) { + result = initials_data_table[initials_data_idx + position]; + } else if (initials_table[initials_idx].type & CINT) { + position *= INTSIZE; + result = (initials_data_table[initials_data_idx + position] << 8) + + (unsigned char)initials_data_table[initials_data_idx + position+1]; + } else if (initials_table[initials_idx].type == STRUCT) { + // find number of members + int number_of_members = tag->number_of_members; + // point behind the last full struct + int index = (position / number_of_members) * tag->size; + // move to required member + for (i=0; i < (position % number_of_members); i++) { + type = member_table[tag->member_idx + i].type; + if (type & CCHAR) { + index += 1; + } else { + index += INTSIZE; + } + } + // get value + type = member_table[tag->member_idx + i].type; + if (type & CCHAR) { + result = initials_data_table[initials_data_idx + index]; + } else { + result = (initials_data_table[initials_data_idx + index] << 8) + + (unsigned char)initials_data_table[initials_data_idx + index+1]; + } + } + } + return result; +} diff --git a/Applications/SmallC/io.c b/Applications/SmallC/io.c new file mode 100644 index 00000000..638dd977 --- /dev/null +++ b/Applications/SmallC/io.c @@ -0,0 +1,199 @@ +/* File io.c: 2.1 (83/03/20,16:02:07) */ +/*% cc -O -c % + * + */ + +#include +#include +#include +#include +#include +#include "defs.h" +#include "data.h" + +/* + * open input file + */ +int openin(char *p) +{ + strcpy(fname, p); + fixname (fname); + if (!checkname (fname)) + return (NO); + if ((input = open(fname, O_RDONLY)) == -1) { + pl ("Open failure\n"); + return (NO); + } + do_kill(); + return (YES); + +} + +/* + * open output file + */ +int openout(void) +{ + outfname (fname); + if ((output = open (fname, O_WRONLY|O_TRUNC|O_CREAT, 0644)) == -1) { + pl ("Open failure"); + return (NO); + } + do_kill(); + return (YES); + +} + +/* + * change input filename to output filename + */ +void outfname(char *s) +{ + while (*s) + s++; + *--s = 's'; + +} + +/** + * remove NL from filenames + */ +void fixname(char *s) +{ + while (*s && *s++ != LF); + if (!*s) return; + *(--s) = 0; + +} + +/** + * check that filename is "*.c" + */ +int checkname(char *s) +{ + while (*s) + s++; + if (*--s != 'c') + return (NO); + if (*--s != '.') + return (NO); + return (YES); + +} + +void do_kill(void) { + lptr = 0; + line[lptr] = 0; +} + +int igetc(int unit) +{ + unsigned char c; + int err; + err = read(unit, &c, 1); + if (err == 1) + return (int)c; + if (err == 0) { + if (unit == input) + input_eof = 1; + return -1; + } + writee("I/O error"); + exit(1); +} + +void readline(void) { + int k; + int unit; + + FOREVER { + if (input_eof) + return; + if ((unit = input2) == -1) + unit = input; + do_kill(); + while ((k = igetc(unit)) != EOF) { + if ((k == CR) || (k == LF) | (lptr >= LINEMAX)) + break; + line[lptr++] = k; + } + line[lptr] = 0; + if (k <= 0) + if (input2 != -1) { + input2 = inclstk[--inclsp]; + close (unit); + } + if (lptr) { + if ((ctext) & (cmode)) { + gen_comment (); + output_string (line); + newline (); + } + lptr = 0; + return; + } + } +} + +int inbyte(void) { + while (ch () == 0) { + if (input_eof) + return (0); + preprocess (); + } + return (gch ()); +} + +int inchar(void) { + if (ch () == 0) + readline (); + if (input_eof) + return (0); + return (gch ()); +} + +/** + * gets current char from input line and moves to the next one + * @return current char + */ +int gch(void) { + if (ch () == 0) + return (0); + else + return (line[lptr++] & 127); +} + +/** + * returns next char + * @return next char + */ +int nch (void) { + if (ch () == 0) + return (0); + else + return (line[lptr + 1] & 127); +} + +/** + * returns current char + * @return current char + */ +int ch (void) { + return (line[lptr] & 127); +} + +/* + * print a carriage return and a string only to console + * + */ +void pl (char *str) +{ + write(1, "\n", 1); + write(1, str, strlen(str)); +} + + +void writee(char *str) +{ + write(2, str, strlen(str)); +} diff --git a/Applications/SmallC/lex.c b/Applications/SmallC/lex.c new file mode 100644 index 00000000..a79aa829 --- /dev/null +++ b/Applications/SmallC/lex.c @@ -0,0 +1,228 @@ +/* File lex.c: 2.1 (83/03/20,16:02:09) */ +/*% cc -O -c % + * + */ + +#include +#include "defs.h" +#include "data.h" + +/** + * test if given character is alpha + * @param c + * @return + */ + +int alpha(char c) { + c = c & 127; + return (((c >= 'a') && (c <= 'z')) || + ((c >= 'A') && (c <= 'Z')) || + (c == '_')); +} + +/** + * test if given character is numeric + * @param c + * @return + */ +int numeric(char c) { + c = c & 127; + return ((c >= '0') && (c <= '9')); +} + +/** + * test if given character is alphanumeric + * @param c + * @return + */ +int alphanumeric(char c) { + return ((alpha (c)) || (numeric (c))); +} + +/** + * semicolon enforcer + * called whenever syntax requires a semicolon + */ +void need_semicolon(void) { + if (!match (";")) + error ("missing semicolon"); +} + +void junk(void) { + if (alphanumeric (inbyte ())) + while (alphanumeric (ch ())) + gch (); + else + while (alphanumeric (ch ())) { + if (ch () == 0) + break; + gch (); + } + blanks (); +} + +int endst(void) { + blanks (); + return ((streq (line + lptr, ";") | (ch () == 0))); +} + +/** + * enforces bracket + * @param str + * @return + */ +void needbrack(char *str) { + if (!match (str)) { + error ("missing bracket"); + gen_comment (); + output_string (str); + newline (); + } +} + +/** + * + * @param str1 + * @return + */ +int sstreq(char *str1) { + return (streq(line + lptr, str1)); +} + +/** + * indicates whether or not the current substring in the source line matches a + * literal string + * accepts the address of the current character in the source + * line and the address of the a literal string, and returns the substring length + * if a match occurs and zero otherwise + * @param str1 address1 + * @param str2 address2 + * @return + */ +int streq(char str1[], char str2[]) { + int k; + k = 0; + while (str2[k]) { + if ((str1[k] != str2[k])) + return (0); + k++; + } + return (k); +} + +/** + * compares two string both must be zero ended, otherwise no match found + * ensures that the entire token is examined + * @param str1 + * @param str2 + * @param len + * @return + */ +int astreq(char str1[], char str2[], int len) { + int k; + k = 0; + while (k < len) { + if ((str1[k] != str2[k])) + break; + if (str1[k] == 0) + break; + if (str2[k] == 0) + break; + k++; + } + if (alphanumeric (str1[k])) + return (0); + if (alphanumeric (str2[k])) + return (0); + return (k); +} + +/** + * looks for a match between a literal string and the current token in + * the input line. It skips over the token and returns true if a match occurs + * otherwise it retains the current position in the input line and returns false + * there is no verification that all of the token was matched + * @param lit + * @return + */ +int match(char *lit) { + int k; + blanks(); + if ((k = streq (line + lptr, lit)) != 0) { + lptr = lptr + k; + return (1); + } + return (0); +} + +/** + * compares two string both must be zero ended, otherwise no match found + * advances line pointer only if match found + * it assumes that an alphanumeric (including underscore) comparison + * is being made and guarantees that all of the token in the source line is + * scanned in the process + * @param lit + * @param len + * @return + */ +int amatch(char *lit, int len) { + int k; + + blanks(); + if ((k = astreq (line + lptr, lit, len)) != 0) { + lptr = lptr + k; + while (alphanumeric (ch ())) + inbyte (); + return (1); + } + return (0); +} + +void blanks(void) { + FOREVER { + while (ch () == 0) { + preprocess (); + if (input_eof) + break; + } + if (ch () == ' ') + gch (); + else if (ch () == 9) + gch (); + else + return; + } +} + +/** + * returns declaration type + * @return CCHAR, CINT, UCHAR, UINT + */ +int get_type(void) { + if (amatch ("register", 8)) { + if (amatch("char", 4)) + return CCHAR; + else if (amatch ("int", 3)) + return CINT; + else + return CINT; + } else if(amatch("unsigned", 8)) { + if (amatch("char", 4)) { + return UCHAR; + } else if (amatch("int", 3)) { + return UINT; + } + } else if(amatch("signed", 8)) { + if (amatch("char", 4)) { + return CCHAR; + } else if (amatch("int", 3)) { + return CINT; + } + } else if (amatch ("char", 4)) { + return CCHAR; + } else if (amatch ("int", 3)) { + return CINT; + } + return 0; +} + diff --git a/Applications/SmallC/lib/abs.c b/Applications/SmallC/lib/abs.c new file mode 100644 index 00000000..9a0adfe5 --- /dev/null +++ b/Applications/SmallC/lib/abs.c @@ -0,0 +1,5 @@ +/* abs (num) return absolute value */ +abs(num) int num;{ + if (num < 0) return (-num); + else return (num); + } diff --git a/Applications/SmallC/lib/atoi.c b/Applications/SmallC/lib/atoi.c new file mode 100644 index 00000000..265e3f2b --- /dev/null +++ b/Applications/SmallC/lib/atoi.c @@ -0,0 +1,21 @@ +#include +#define EOL 10 +atoi(s) char s[];{ + int i,n,sign; + for (i=0; + (s[i] == ' ') | (s[i] == EOL) | (s[i] == '\t'); + ++i) ; + sign = 1; + switch(s[i]){ + case '-': sign = -1; /* and fall through */ + case '+': ++i; + break; + } + for(n = 0; + isdigit(s[i]); + ++i) + n = 10 * n + s[i] - '0'; + return (sign * n); + +} + diff --git a/Applications/SmallC/lib/binary.c b/Applications/SmallC/lib/binary.c new file mode 100644 index 00000000..8b6cea51 --- /dev/null +++ b/Applications/SmallC/lib/binary.c @@ -0,0 +1,22 @@ +/* binary search for string word in table[0] .. table[n-1] + * reference CPL pg. 125 + */ +#include +binary(word, table, n) +char *word; +int table[]; +int n;{ + int low, high, mid, cond; + low = 0; + high = n - 1; + while (low <= high){ + mid = (low + high) / 2; + if ((cond = strcmp(word, table[mid])) < 0) + high = mid - 1; + else if (cond > 0) + low = mid + 1; + else + return (mid); + } + return (-1); + } diff --git a/Applications/SmallC/lib/charclass.c b/Applications/SmallC/lib/charclass.c new file mode 100644 index 00000000..39fb8735 --- /dev/null +++ b/Applications/SmallC/lib/charclass.c @@ -0,0 +1,33 @@ +isalpha(c) char c;{ + if ((c >= 'a' & c <= 'z') | + (c >= 'A' & c <= 'Z')) return(1); + else return(0); + } + +isupper(c) char c;{ + if (c >= 'A' & c <= 'Z') return(1); + else return(0); + } + +islower(c) char c;{ + if (c >= 'a' & c <= 'z') return(1); + else return(0); + } + +isdigit(c) char c;{ + if (c >= '0' & c <= '9') return(1); + else return(0); + } + +isspace(c) char c;{ + if (c == ' ' | c == '\t' | c == '\n') return(1); + else return(0); + } + +toupper(c) char c;{ + return ((c >= 'a' && c <= 'z') ? c - 32: c); + } + +tolower(c) char c;{ + return((c >= 'A' && c <= 'Z') ? c + 32: c); + } diff --git a/Applications/SmallC/lib/fgets.c b/Applications/SmallC/lib/fgets.c new file mode 100644 index 00000000..82e44d29 --- /dev/null +++ b/Applications/SmallC/lib/fgets.c @@ -0,0 +1,27 @@ +/* +#include +*/ +#define NULL 0 +#define FILE char + +fgets(s, n, iop) +int n; +char *s; +register FILE *iop; +{ + register c; + register char *cs; + + cs = s; + while (--n>0 && (c = fgetc(iop))>=0) { + *cs++ = c; + if (c=='\n') + break; + } + if (c<0 && cs==s) + return(NULL); + *cs++ = '\0'; + return(s); + +} + diff --git a/Applications/SmallC/lib/fputs.c b/Applications/SmallC/lib/fputs.c new file mode 100644 index 00000000..1f916b52 --- /dev/null +++ b/Applications/SmallC/lib/fputs.c @@ -0,0 +1,7 @@ +#include + +fputs(str, fp) FILE *fp; char *str; { + while(*str) fputc(*str++, fp); + +} + diff --git a/Applications/SmallC/lib/getchar.c b/Applications/SmallC/lib/getchar.c new file mode 100644 index 00000000..48fedfbb --- /dev/null +++ b/Applications/SmallC/lib/getchar.c @@ -0,0 +1,5 @@ +#include +getchar() { + return(fgetc(stdin)); +} + diff --git a/Applications/SmallC/lib/gets.c b/Applications/SmallC/lib/gets.c new file mode 100644 index 00000000..21385aea --- /dev/null +++ b/Applications/SmallC/lib/gets.c @@ -0,0 +1,28 @@ +#include +#define EOL 10 +#define BKSP 8 +#define CTRLU 0x15 +gets(s) char *s; { + char c, *ts; + ts = s; + while ((c = getchar()) != EOL && (c != EOF)) { + if (c == BKSP) { + if (ts > s) { + --ts; + /* CPM already echoed */ + putchar(' '); + putchar(BKSP); + } + } + else if (c == CTRLU) { + ts = s; + putchar(EOL); + putchar('#'); + } + else (*ts++) = c; + } + if ((c == EOF) && (ts == s)) return NULL; + (*ts) = NULL; + return s; +} + diff --git a/Applications/SmallC/lib/index.c b/Applications/SmallC/lib/index.c new file mode 100644 index 00000000..26c72046 --- /dev/null +++ b/Applications/SmallC/lib/index.c @@ -0,0 +1,18 @@ +/* index - find index of string t in s + * reference CPL 67. + */ +#include +#define EOS 0 +index(s, t) +char s[], t[];{ + int i, j, k; + for (i = 0; s[i] != EOS; i++){ + k=0; + for (j=i;t[k]!=EOS & s[j]==t[k]; i++) + j++; + ; + if (t[k] == EOS) + return(i); + } + return(-1); + } diff --git a/Applications/SmallC/lib/itoa.c b/Applications/SmallC/lib/itoa.c new file mode 100644 index 00000000..7411dd99 --- /dev/null +++ b/Applications/SmallC/lib/itoa.c @@ -0,0 +1,14 @@ +#include +#define EOS 0 +itoa(n,s) char s[];int n;{ + int i,sign; + if((sign = n) < 0) n = -n; + i = 0; + do { + s[i++] = n % 10 + '0'; + }while ((n = n/10) > 0); + if (sign < 0) s[i++] = '-'; + s[i] = EOS; + reverse(s); +} + diff --git a/Applications/SmallC/lib/printn.c b/Applications/SmallC/lib/printn.c new file mode 100644 index 00000000..be26340a --- /dev/null +++ b/Applications/SmallC/lib/printn.c @@ -0,0 +1,16 @@ +#include +/* print a number in any radish */ +#define DIGARR "0123456789ABCDEF" +printn(number, radix, file) +int number, radix; FILE *file;{ + int i; + char *digitreps; + if (number < 0 & radix == 10){ + fputc('-', file); + number = -number; + } + if ((i = number / radix) != 0) + printn(i, radix, file); + digitreps=DIGARR; + fputc(digitreps[number % radix], file); + } diff --git a/Applications/SmallC/lib/putchar.c b/Applications/SmallC/lib/putchar.c new file mode 100644 index 00000000..a96a6e31 --- /dev/null +++ b/Applications/SmallC/lib/putchar.c @@ -0,0 +1,5 @@ +#include +putchar(c) char c; { + return fputc(c, stdout); +} + diff --git a/Applications/SmallC/lib/puts.c b/Applications/SmallC/lib/puts.c new file mode 100644 index 00000000..7d5511f0 --- /dev/null +++ b/Applications/SmallC/lib/puts.c @@ -0,0 +1,6 @@ +#include +#define EOL 10 +puts(str) char *str;{ + while (*str) putchar(*str++); + putchar(EOL); + } diff --git a/Applications/SmallC/lib/rand.c b/Applications/SmallC/lib/rand.c new file mode 100644 index 00000000..97112d1d --- /dev/null +++ b/Applications/SmallC/lib/rand.c @@ -0,0 +1,20 @@ + +int xxseed; + +srand (x) int x; { + xxseed = x; + +} + +rand () { + xxseed = xxseed * 251 + 123; + if (xxseed < 0) xxseed = - xxseed; + return (xxseed); + +} + +getrand () { + puts ("Type a character"); + return (getchar() * 123); +} + diff --git a/Applications/SmallC/lib/reverse.c b/Applications/SmallC/lib/reverse.c new file mode 100644 index 00000000..c77151a6 --- /dev/null +++ b/Applications/SmallC/lib/reverse.c @@ -0,0 +1,17 @@ +#include +/* Reverse a character string, reference CPL p 59 */ +reverse(s) +char *s;{ + int i, j; + char c; + i = 0; + j = strlen(s) - 1; + while (i < j){ + c = s[i]; + s[i] = s[j]; + s[j] = c; + i++; + j--; + } + return(s); + } diff --git a/Applications/SmallC/lib/sbrk.c b/Applications/SmallC/lib/sbrk.c new file mode 100644 index 00000000..65ea2fc0 --- /dev/null +++ b/Applications/SmallC/lib/sbrk.c @@ -0,0 +1,17 @@ +extern char *brkend; +sbrk (incr) char *incr; { + char *stktop; + + stktop = Xstktop() - 200; + + /* do we have enough space? */ + if (brkend + incr < stktop) { + stktop = brkend; + brkend = brkend + incr; + return (stktop); + } + else + return (-1); + +} + diff --git a/Applications/SmallC/lib/shell.c b/Applications/SmallC/lib/shell.c new file mode 100644 index 00000000..13ad4560 --- /dev/null +++ b/Applications/SmallC/lib/shell.c @@ -0,0 +1,21 @@ +/* Shell sort of string v[0] .... v[n-1] into increasing + * order. + * Reference CPL pg. 108. + */ + +shellsort(v, n) +int v[]; +int n; + { + int gap, i, j; + char *temp; + for (gap = n/2; gap > 0; gap = gap / 2) + for (i = gap; i < n; i++) + for (j = i - gap; j >= 0; j = j - gap){ + if (strcmp(v[j], v[j+gap]) <= 0) + break; + temp = v[j]; + v[j] = v[j + gap]; + v[j + gap] = temp; + } + } diff --git a/Applications/SmallC/lib/strcat.c b/Applications/SmallC/lib/strcat.c new file mode 100644 index 00000000..811667e7 --- /dev/null +++ b/Applications/SmallC/lib/strcat.c @@ -0,0 +1,20 @@ +/* + * Concatenate s2 on the end of s1. S1's space must be large enough. + * Return s1. + */ + +strcat(s1, s2) +char *s1, *s2; +{ + char *os1; + + os1 = s1; + while (*s1++) + ; + *--s1; + while (*s1++ = *s2++) + ; + return(os1); + +} + diff --git a/Applications/SmallC/lib/strcmp.c b/Applications/SmallC/lib/strcmp.c new file mode 100644 index 00000000..d543d396 --- /dev/null +++ b/Applications/SmallC/lib/strcmp.c @@ -0,0 +1,13 @@ +/* + * Compare strings: s1>s2: >0 s1==s2: 0 s1 +/* + * Copy string s2 to s1. s1 must be large enough. + * return s1 + */ + +strcpy(s1, s2) +char *s1, *s2; +{ + char *os1; + + os1 = s1; + while (*s1++ = *s2++) + ; + return(os1); + +} + diff --git a/Applications/SmallC/lib/strlen.c b/Applications/SmallC/lib/strlen.c new file mode 100644 index 00000000..e3bd9d48 --- /dev/null +++ b/Applications/SmallC/lib/strlen.c @@ -0,0 +1,8 @@ +#include +/* return length of string, reference CPL p 36 */ +strlen(s) char *s;{ + int i; + i = 0; + while (*s++) i++; + return (i); + } diff --git a/Applications/SmallC/lib/strncat.c b/Applications/SmallC/lib/strncat.c new file mode 100644 index 00000000..c166216e --- /dev/null +++ b/Applications/SmallC/lib/strncat.c @@ -0,0 +1,25 @@ +/* + * Concatenate s2 on the end of s1. S1's space must be large enough. + * At most n characters are moved. + * Return s1. + */ + +strncat(s1, s2, n) +register char *s1, *s2; +register n; +{ + register char *os1; + + os1 = s1; + while (*s1++) + ; + --s1; + while (*s1++ = *s2++) + if (--n < 0) { + *--s1 = '\0'; + break; + } + return(os1); + +} + diff --git a/Applications/SmallC/lib/strncmp.c b/Applications/SmallC/lib/strncmp.c new file mode 100644 index 00000000..bdd5a30c --- /dev/null +++ b/Applications/SmallC/lib/strncmp.c @@ -0,0 +1,16 @@ +/* + * Compare strings (at most n bytes): s1>s2: >0 s1==s2: 0 s1= 0 && *s1 == *s2++) + if (*s1++ == '\0') + return(0); + return(n<0 ? 0 : *s1 - *--s2); + +} + diff --git a/Applications/SmallC/lib/strncpy.c b/Applications/SmallC/lib/strncpy.c new file mode 100644 index 00000000..e14cd4ca --- /dev/null +++ b/Applications/SmallC/lib/strncpy.c @@ -0,0 +1,23 @@ +/* + * Copy s2 to s1, truncating or null-padding to always copy n bytes + * return s1 + */ + +strncpy(s1, s2, n) +char *s1, *s2; +int n; +{ + register i; + register char *os1; + + os1 = s1; + for (i = 0; i < n; i++) + if ((*s1++ = *s2++) == '\0') { + while (++i < n) + *s1++ = '\0'; + return(os1); + } + return(os1); + +} + diff --git a/Applications/SmallC/main.c b/Applications/SmallC/main.c new file mode 100644 index 00000000..a26cc7ac --- /dev/null +++ b/Applications/SmallC/main.c @@ -0,0 +1,363 @@ +/* + * File main.c: 2.7 (84/11/28,10:14:56) + */ + +#include +#include +#include +#include +#include "defs.h" +#include "data.h" + +int main(int argc, char *argv[]) { + char *param = NULL, *bp; + int i; + macptr = 0; + ctext = 0; + errs = 0; + aflag = 1; + uflag = 0; + + for (i=1; i= litptr)) { + newline(); + break; + } + output_byte(','); + } + } +#endif +} + +/** + * dump all static variables + */ +void dumpglbs(void) { +#ifndef TINY + int dim, i, list_size, line_count, value; + if (!glbflag) + return; + current_symbol_table_idx = rglobal_table_index; + while (current_symbol_table_idx < global_table_index) { + SYMBOL *symbol = &symbol_table[current_symbol_table_idx]; + if (symbol->identity != FUNCTION) { + ppubext(symbol); + if (symbol->storage != EXTERN) { + output_string(symbol->name); + output_label_terminator(); + dim = symbol->offset; + list_size = 0; + line_count = 0; + if (find_symbol_initials(symbol->name)) { // has initials + list_size = get_size(symbol->name); + if (dim == -1) { + dim = list_size; + } + } + for (i=0; itype == STRUCT) { + dump_struct(symbol, i); + } else { + if (line_count % 10 == 0) { + newline(); + if ((symbol->type & CINT) || (symbol->identity == POINTER)) { + gen_def_word(); + } else { + gen_def_byte(); + } + } + if (i < list_size) { + // dump data + value = get_item_at(symbol->name, i, &tag_table[symbol->tagidx]); + output_number(value); + } else { + // dump zero, no more data available + output_number(0); + } + line_count++; + if (line_count % 10 == 0) { + line_count = 0; + } else { + if (i < dim-1) { + output_byte( ',' ); + } + } + } + } + newline(); + } + } else { + fpubext(symbol); + } + current_symbol_table_idx++; + } +#endif +} + +#ifndef TINY +/** + * dump struct data + * @param symbol struct variable + * @param position position of the struct in the array, or zero + */ +void dump_struct(SYMBOL *symbol, int position) { + int i, number_of_members, value; + number_of_members = tag_table[symbol->tagidx].number_of_members; + newline(); + for (i=0; itagidx].member_idx + i].type; + if (member_type & CINT) { + gen_def_word(); + } else { + gen_def_byte(); + } + if (position < get_size(symbol->name)) { + // dump data + value = get_item_at(symbol->name, position*number_of_members+i, &tag_table[symbol->tagidx]); + output_number(value); + } else { + // dump zero, no more data available + output_number(0); + } + newline(); + } +} +#endif + +/** + * report errors + */ +void errorsummary(void) { + if (ncmp) + error("missing closing bracket"); + newline(); + gen_comment(); + output_decimal(errcnt); + if (errcnt) errfile = YES; + output_string(" error(s) in compilation"); + newline(); + gen_comment(); + output_with_tab("literal pool:"); + output_decimal(litptr); + newline(); + gen_comment(); + output_with_tab("global pool:"); + output_decimal(global_table_index - rglobal_table_index); + newline(); + gen_comment(); + output_with_tab("Macro pool:"); + output_decimal(macptr); + newline(); + if (errcnt > 0) + pl("Error(s)"); +} + +/** + * test for C or similar filename, e.g. xxxxx.x, tests the dot at end-1 postion + * @param s the filename + * @return the last char if it contains dot, space otherwise + */ +int filename_typeof(char *s) { + s += strlen(s) - 2; + if (*s == '.') + return (*(s + 1)); + return (' '); +} + diff --git a/Applications/SmallC/preproc.c b/Applications/SmallC/preproc.c new file mode 100644 index 00000000..a00ec388 --- /dev/null +++ b/Applications/SmallC/preproc.c @@ -0,0 +1,364 @@ +/* File preproc.c: 2.3 (84/11/27,11:47:40) */ +/*% cc -O -c % + * + */ + +#include +#include +#include +#include +#include "defs.h" +#include "data.h" + +/** + * remove "brackets" surrounding include file name + * @see DEFLIB + */ +int fix_include_name (void) { + char c1, c2, *p, *ibp; + char buf[20]; + int fp; + char buf2[100]; + + ibp = &buf[0]; + + if ((c1 = gch ()) != '"' && c1 != '<') + return -1; + for (p = line + lptr; *p ;) + *ibp++ = *p++; + c2 = *(--p); + if (c1 == '"' ? (c2 != '"') : (c2 != '>')) { + error ("incorrect delimiter"); + return -1; + } + *(--ibp) = 0; + fp = -1; + if (c1 == '<' || ((fp = open(buf, O_RDONLY)) != -1)) { + strcpy(buf2, DEFLIB); + strlcat(buf2, buf, sizeof(buf2)); + fp = open(buf2, O_RDONLY); + } + return (fp); +} + +/** + * open an include file + */ +void doinclude(void) +{ + int inp2; + + blanks (); + if ((inp2 = fix_include_name ()) != -1) + if (inclsp < INCLSIZ) { + inclstk[inclsp++] = input2; + input2 = inp2; + } else { + close (inp2); + error ("too many nested includes"); + } + else { + error ("Could not open include file"); + } + do_kill(); + +} + +/** + * "asm" pseudo-statement + * enters mode where assembly language statements are passed + * intact through parser + */ +void doasm(void) +{ + cmode = 0; + FOREVER { + readline (); + if (match ("#endasm")) + break; + if (input_eof) + break; + output_string (line); + newline (); + } + do_kill(); + cmode = 1; + +} + +void dodefine(void) +{ + addmac(); +} + +void doundef(void) +{ + int mp; + char sname[NAMESIZE]; + + if (!symname(sname)) { + illname(); + do_kill(); + return; + } + + if ((mp = findmac(sname)) != 0) + delmac(mp); + do_kill(); + +} + +void preprocess(void) +{ + if (ifline()) return; + while (cpp()); +} + +void doifdef(int ifdef) +{ + char sname[NAMESIZE]; + int k; + + blanks(); + ++iflevel; + if (skiplevel) return; + k = symname(sname) && findmac(sname); + if (k != ifdef) skiplevel = iflevel; + +} + +int ifline(void) +{ + FOREVER { + readline(); + if (input_eof) return(1); + if (match("#ifdef")) { + doifdef(YES); + continue; + } else if (match("#ifndef")) { + doifdef(NO); + continue; + } else if (match("#else")) { + if (iflevel) { + if (skiplevel == iflevel) skiplevel = 0; + else if (skiplevel == 0) skiplevel = iflevel; + } else noiferr(); + continue; + } else if (match("#endif")) { + if (iflevel) { + if (skiplevel == iflevel) skiplevel = 0; + --iflevel; + } else noiferr(); + continue; + } + if (!skiplevel) return(0); + } + +} + +void noiferr(void) +{ + error("no matching #if..."); + +} + +/** + * preprocess - copies mline to line with special treatment of preprocess cmds + * @return + */ +int cpp(void) +{ + int k; + char c, sname[NAMESIZE]; + int tog; + int cpped; /* non-zero if something expanded */ + + cpped = 0; + /* don't expand lines with preprocessor commands in them */ + if (!cmode || line[0] == '#') return(0); + + mptr = lptr = 0; + while (ch ()) { + if ((ch () == ' ') | (ch () == 9)) { + keepch (' '); + while ((ch () == ' ') | (ch () == 9)) + gch (); + } else if (ch () == '"') { + keepch (ch ()); + gch (); + while (ch () != '"') { + if (ch () == 0) { + error ("missing quote"); + break; + } + if (ch() == '\\') keepch(gch()); + keepch (gch ()); + } + gch (); + keepch ('"'); + } else if (ch () == '\'') { + keepch ('\''); + gch (); + while (ch () != '\'') { + if (ch () == 0) { + error ("missing apostrophe"); + break; + } + if (ch() == '\\') keepch(gch()); + keepch (gch ()); + } + gch (); + keepch ('\''); + } else if ((ch () == '/') & (nch () == '*')) { + inchar (); + inchar (); + while ((((c = ch ()) == '*') & (nch () == '/')) == 0) + if (c == '$') { + inchar (); + tog = TRUE; + if (ch () == '-') { + tog = FALSE; + inchar (); + } + if (alpha (c = ch ())) { + inchar (); + toggle (c, tog); + } + } else { + if (ch () == 0) + readline (); + else + inchar (); + if (input_eof) + break; + } + inchar (); + inchar (); + } else if ((ch () == '/') & (nch () == '/')) { // one line comment + while(gch()); + } else if (alphanumeric(ch ())) { + k = 0; + while (alphanumeric(ch ())) { + if (k < NAMEMAX) + sname[k++] = ch (); + gch (); + } + sname[k] = 0; + if ((k = findmac (sname)) != 0) { + cpped = 1; + while ((c = macq[k++]) != 0) + keepch (c); + } else { + k = 0; + while ((c = sname[k++]) != 0) + keepch (c); + } + } else + keepch (gch ()); + } + keepch (0); + if (mptr >= MPMAX) + error ("line too long"); + lptr = mptr = 0; + while((line[lptr++] = mline[mptr++]) != 0); + lptr = 0; + return(cpped); + +} + +int keepch(char c) +{ + mline[mptr] = c; + if (mptr < MPMAX) + mptr++; + return (c); + +} + +void defmac(char *s) +{ + do_kill(); + strcpy(line, s); + addmac(); +} + +void addmac(void) +{ + char sname[NAMESIZE]; + int k; + int mp; + + if (!symname (sname)) { + illname(); + do_kill(); + return; + } + if ((mp = findmac(sname)) != 0) { + error("Duplicate define"); + delmac(mp); + } + k = 0; + while (putmac (sname[k++])); + while (ch () == ' ' || ch () == 9) + gch (); + //while (putmac (gch ())); + while (putmac(remove_one_line_comment(gch ()))); + if (macptr >= MACMAX) + error ("macro table full"); + +} + +/** + * removes one line comments from defines + * @param c + * @return + */ +int remove_one_line_comment(char c) { + if ((c == '/') && (ch() == '/')) { + while(gch()); + return 0; + } else { + return c; + } +} + +void delmac(int mp) { + --mp; --mp; /* step over previous null */ + while (mp >= 0 && macq[mp]) macq[mp--] = '%'; + +} + +int putmac(char c) +{ + macq[macptr] = c; + if (macptr < MACMAX) + macptr++; + return (c); + +} + +int findmac(char *sname) +{ + int k; + + k = 0; + while (k < macptr) { + if (astreq (sname, macq + k, NAMEMAX)) { + while (macq[k++]); + return (k); + } + while (macq[k++]); + while (macq[k++]); + } + return (0); + +} + +void toggle(char name, int onoff) { + switch (name) { + case 'C': + ctext = onoff; + break; + } +} + diff --git a/Applications/SmallC/primary.c b/Applications/SmallC/primary.c new file mode 100644 index 00000000..28c9af7f --- /dev/null +++ b/Applications/SmallC/primary.c @@ -0,0 +1,316 @@ +/* + * File primary.c: 2.4 (84/11/27,16:26:07) + */ + +#include +#include "defs.h" +#include "data.h" + +int primary(LVALUE *lval) { + char sname[NAMESIZE]; + int num[1], k, symbol_table_idx, offset, reg; + SYMBOL *symbol; + + lval->ptr_type = 0; // clear pointer/array type + lval->tagsym = 0; + if (match ("(")) { + k = hier1 (lval); + needbrack (")"); + return (k); + } + if (amatch("sizeof", 6)) { + needbrack("("); + gen_immediate(); + if (amatch("int", 3)) output_number(INTSIZE); + else if (amatch("char", 4)) output_number(1); + else if (symname(sname)) { + if (((symbol_table_idx = find_locale(sname)) > -1) || + ((symbol_table_idx = find_global(sname)) > -1)) { + symbol = &symbol_table[symbol_table_idx]; + if (symbol->storage == LSTATIC) + error("sizeof local static"); + offset = symbol->offset; + if ((symbol->type & CINT) || + (symbol->identity == POINTER)) + offset *= INTSIZE; + else if (symbol->type == STRUCT) + offset *= tag_table[symbol->tagidx].size; + output_number(offset); + } else { + error("sizeof undeclared variable"); + output_number(0); + } + } else { + error("sizeof only on type or variable"); + } + needbrack(")"); + newline(); + lval->symbol = 0; + lval->indirect = 0; + return(0); + } + if (symname (sname)) { + if ((symbol_table_idx = find_locale(sname)) > -1) { + symbol = &symbol_table[symbol_table_idx]; + reg = gen_get_locale(symbol); + lval->symbol = symbol; + lval->indirect = symbol->type; + if (symbol->type == STRUCT) { + lval->tagsym = &tag_table[symbol->tagidx]; + } + if (symbol->identity == ARRAY || + (symbol->identity == VARIABLE && symbol->type == STRUCT)) { + lval->ptr_type = symbol->type; + return reg; + } + if (symbol->identity == POINTER) { + lval->indirect = CINT; + lval->ptr_type = symbol->type; + } + return FETCH | reg; + } + if ((symbol_table_idx = find_global(sname)) > -1) { + symbol = &symbol_table[symbol_table_idx]; + if (symbol->identity != FUNCTION) { + lval->symbol = symbol; + lval->indirect = 0; + if (symbol->type == STRUCT) { + lval->tagsym = &tag_table[symbol->tagidx]; + } + if (symbol->identity != ARRAY && + (symbol->identity != VARIABLE || symbol->type != STRUCT)) { + if (symbol->identity == POINTER) { + lval->ptr_type = symbol->type; + } + return FETCH | HL_REG; + } + gen_immediate(); + output_string(symbol->name); + newline(); + lval->indirect = symbol->type; + lval->ptr_type = symbol->type; + return 0; + } + } + blanks(); + if (ch() != '(') + error("undeclared variable"); + symbol_table_idx = add_global(sname, FUNCTION, CINT, 0, PUBLIC); + symbol = &symbol_table[symbol_table_idx]; + lval->symbol = symbol; + lval->indirect = 0; + return 0; + } + lval->symbol = 0; + lval->indirect = 0; + if (constant(num)) + return 0; + else { + error("invalid expression"); + gen_immediate(); + output_number(0); + newline(); + junk(); + return 0; + } +} + +/** + * true if val1 -> int pointer or int array and val2 not pointer or array + * @param val1 + * @param val2 + * @return + */ +int dbltest(LVALUE *val1, LVALUE *val2) { + if (val1 == NULL) + return (FALSE); + if (val1->ptr_type) { + if (val1->ptr_type & CCHAR) + return (FALSE); + if (val2->ptr_type) + return (FALSE); + return (TRUE); + } + return (FALSE); +} + +/** + * determine type of binary operation + * @param lval + * @param lval2 + * @return + */ +void result(LVALUE *lval, LVALUE *lval2) { + if (lval->ptr_type && lval2->ptr_type) + lval->ptr_type = 0; + else if (lval2->ptr_type) { + lval->symbol = lval2->symbol; + lval->indirect = lval2->indirect; + lval->ptr_type = lval2->ptr_type; + } +} + +int constant(int val[]) { + if (number (val)) + gen_immediate (); + else if (quoted_char (val)) + gen_immediate (); + else if (quoted_string (val)) { + gen_immediate (); + print_label (litlab); + output_byte ('+'); + } else + return (0); + output_number (val[0]); + newline (); + return (1); +} + +int number(int val[]) { + int k, minus, base; + char c; + + k = minus = 1; + while (k) { + k = 0; + if (match("+")) + k = 1; + if (match("-")) { + minus = (-minus); + k = 1; + } + } + if (!numeric(c = ch ())) + return (0); + if (match("0x") || match ("0X")) + while (numeric(c = ch ()) || + (c >= 'a' && c <= 'f') || + (c >= 'A' && c <= 'F')) { + inbyte (); + k = k * 16 + (numeric (c) ? (c - '0') : ((c & 07) + 9)); + } + else { + base = (c == '0') ? 8 : 10; + while (numeric(ch())) { + c = inbyte (); + k = k * base + (c - '0'); + } + } + if (minus < 0) + k = (-k); + val[0] = k; + if(k < 0) { + return (UINT); + } else { + return (CINT); + } +} + +/** + * Test if we have one char enclosed in single quotes + * @param value returns the char found + * @return 1 if we have, 0 otherwise + */ +int quoted_char(int *value) { + int k; + char c; + + k = 0; + if (!match ("'")) + return (0); + while ((c = gch ()) != '\'') { + c = (c == '\\') ? spechar(): c; + k = (k & 255) * 256 + (c & 255); + } + *value = k; + return (1); +} + +/** + * Test if we have string enclosed in double quotes. e.g. "abc". + * Load the string into literal pool. + * @param position returns beginning of the string + * @return 1 if such string found, 0 otherwise + */ +int quoted_string(int *position) { + char c; + + if (!match ("\"")) + return (0); + *position = litptr; + while (ch () != '"') { + if (ch () == 0) + break; + if (litptr >= LITMAX) { + error ("string space exhausted"); + while (!match ("\"")) + if (gch () == 0) + break; + return (1); + } + c = gch(); + litq[litptr++] = (c == '\\') ? spechar(): c; + } + gch (); + litq[litptr++] = 0; + return (1); +} + +/** + * decode special characters (preceeded by back slashes) + */ +int spechar(void) { + char c; + c = ch(); + + if (c == 'n') c = LF; + else if (c == 't') c = TAB; + else if (c == 'r') c = CR; + else if (c == 'f') c = FFEED; + else if (c == 'b') c = BKSP; + else if (c == '0') c = EOS; + else if (c == EOS) return 0; + + gch(); + return (c); +} + +/** + * perform a function call + * called from "hier11", this routine will either call the named + * function, or if the supplied ptr is zero, will call the contents + * of HL + * @param ptr name of the function + */ +void callfunction(char *ptr) { + int nargs; + + nargs = 0; + blanks (); + if (ptr == 0) + gen_push (HL_REG); + while (!streq (line + lptr, ")")) { + if (endst ()) + break; + expression (NO); + if (ptr == 0) + gen_swap_stack (); + gen_push (HL_REG); + nargs = nargs + INTSIZE; + if (!match (",")) + break; + } + needbrack (")"); + if (aflag) + gnargs(nargs / INTSIZE); + if (ptr) + gen_call (ptr); + else + callstk (); + stkp = gen_modify_stack (stkp + nargs); +} + +void needlval(void) { + error ("must be lvalue"); +} + diff --git a/Applications/SmallC/prototype.h b/Applications/SmallC/prototype.h new file mode 100644 index 00000000..608501f7 --- /dev/null +++ b/Applications/SmallC/prototype.h @@ -0,0 +1,219 @@ +extern void header(void); +extern void newline(void); +extern void initmac(void); +extern void output_label_prefix(void); +extern void output_label_terminator (void); +extern void gen_comment(void); +extern void trailer(void); +extern void code_segment_gtext(void); +extern void data_segment_gdata(void); +extern void ppubext(SYMBOL *scptr); +extern void fpubext(SYMBOL *scptr); +extern void output_number(int num); +extern void gen_get_memory(SYMBOL *sym); +extern int gen_get_locale(SYMBOL *sym); +extern void gen_put_memory(SYMBOL *sym); +extern void gen_put_indirect(char typeobj); +extern void gen_get_indirect(char typeobj, int reg); +extern void gen_swap(void); +extern void gen_immediate(void); +extern void gen_push(int reg); +extern void gen_pop(void); +extern void gen_swap_stack(void); +extern void gen_call(char *sname); +extern void declare_entry_point(char *symbol_name); +extern void gen_ret(void); +extern void callstk(void); +extern void gen_jump(int label); +extern void gen_test_jump(int label, int ft); +extern void gen_def_byte(void); +extern void gen_def_storage(void); +extern void gen_def_word(void); +extern int gen_modify_stack(int newstkp); +extern void gen_multiply_by_two(void); +extern void gen_divide_by_two(void); +extern void gen_jump_case(void); +extern void gen_add(LVALUE *lval, LVALUE *lval2); +extern void gen_sub(void); +extern void gen_mult(void); +extern void gen_div(void); +extern void gen_udiv(void); +extern void gen_mod(void); +extern void gen_umod(void); +extern void gen_or(void); +extern void gen_xor(void); +extern void gen_and(void); +extern void gen_arithm_shift_right(void); +extern void gen_logical_shift_right(void); +extern void gen_arithm_shift_left(void); +extern void gen_twos_complement(void); +extern void gen_logical_negation(void); +extern void gen_complement(void); +extern void gen_convert_primary_reg_value_to_bool(void); +extern void gen_increment_primary_reg(LVALUE *lval); +extern void gen_decrement_primary_reg(LVALUE *lval); +extern void gen_equal(void); +extern void gen_not_equal(void); +extern void gen_less_than(void); +extern void gen_less_or_equal(void); +extern void gen_greater_than(void); +extern void gen_greater_or_equal(void); +extern void gen_unsigned_less_than(void); +extern void gen_unsigned_less_or_equal(void); +extern void gen_usigned_greater_than(void); +extern void gen_unsigned_greater_or_equal(void); +extern char *inclib(void); +extern void gnargs(int d); +extern int assemble(char *s); +extern void gen_immediate2(void); +extern void add_offset(int val); +extern void gen_multiply(int type, int size); +extern void error(char *ptr); +extern void doerror(char *ptr); +extern int nosign(LVALUE *is); +extern void expression(int comma); +extern int hier1(LVALUE *lval); +extern int hier1a(LVALUE *lval); +extern int hier1b(LVALUE *lval); +extern int hier1c(LVALUE *lval); +extern int hier2(LVALUE *lval); +extern int hier3(LVALUE *lval); +extern int hier4(LVALUE *lval); +extern int hier5(LVALUE *lval); +extern int hier6(LVALUE *lval); +extern int hier7(LVALUE *lval); +extern int hier8(LVALUE *lval); +extern int hier9(LVALUE *lval); +extern int hier10(LVALUE *lval); +extern int hier11(LVALUE *lval); +extern void newfunc(void); +extern void getarg(int t); +extern int doAnsiArguments(void); +extern void doLocalAnsiArgument(int type); +extern void oflush(void); +extern int getlabel(void); +extern void print_label(int label); +extern void glabel(char *lab); +extern void generate_label(int nlab); +extern int output_byte(char c); +extern void output_string(char ptr[]); +extern void print_tab(void); +extern void output_line(char ptr[]); +extern void output_with_tab(char ptr[]); +extern void output_decimal(int number); +extern void store(LVALUE *lval); +extern int rvalue(LVALUE *lval, int reg); +extern void test(int label, int ft); +extern void scale_const(int type, int otag, int *size); +extern void create_initials(void); +extern void add_symbol_initials(char *symbol_name, char type); +extern int find_symbol_initials(char *symbol_name); +extern void add_data_initials(char *symbol_name, int type, int value, TAG_SYMBOL *tag); +extern int get_size(char *symbol_name); +extern int get_item_at(char *symbol_name, int position, TAG_SYMBOL *tag); +extern int openin(char *p); +extern int openout(void); +extern void outfname(char *s); +extern void fixname(char *s); +extern int checkname(char *s); +extern void do_kill(void); +extern int igetc(int unit); +extern void readline(void); +extern int inbyte(void); +extern int inchar(void); +extern int gch(void); +extern int nch(void); +extern int ch(void); +extern void pl(char *str); +extern void writee(char *str); +extern int alpha(char c); +extern int numeric(char c); +extern int alphanumeric(char c); +extern void need_semicolon(void); +extern void junk(void); +extern int endst(void); +extern void needbrack(char *str); +extern int sstreq(char *str1); +extern int streq(char str1[], char str2[]); +extern int astreq(char str1[], char str2[], int len); +extern int match(char *lit); +extern int amatch(char *lit, int len); +extern void blanks(void); +extern int get_type(void); +extern void compile(char *file); +extern void frontend_version(void); +extern void usage(void); +extern void parse(void); +extern int do_declarations(int stclass, TAG_SYMBOL *mtag, int is_struct); +extern void dumplits(void); +extern void dumpglbs(void); +extern void dump_struct(SYMBOL *symbol, int position); +extern void errorsummary(void); +extern int filename_typeof(char *s); +extern int fix_include_name (void); +extern void doinclude(void); +extern void doasm(void); +extern void dodefine(void); +extern void doundef(void); +extern void preprocess(void); +extern void doifdef(int ifdef); +extern int ifline(void); +extern void noiferr(void); +extern int cpp(void); +extern int keepch(char c); +extern void defmac(char *s); +extern void addmac(void); +extern int remove_one_line_comment(char c); +extern void delmac(int mp); +extern int putmac(char c); +extern int findmac(char *sname); +extern void toggle(char name, int onoff); +extern int primary(LVALUE *lval); +extern int dbltest(LVALUE *val1, LVALUE *val2); +extern void result(LVALUE *lval, LVALUE *lval2); +extern int constant(int val[]); +extern int number(int val[]); +extern int quoted_char(int *value); +extern int quoted_string(int *position); +extern int spechar(void); +extern void callfunction(char *ptr); +extern void needlval(void); +extern int statement(int func); +extern int statement_declare(void); +extern int do_local_declares(int stclass); +extern void do_statement(void); +extern void do_compound(int func); +extern void doif(void); +extern void dowhile(void); +extern void dodo(void); +extern void dofor(void); +extern void doswitch(void); +extern void docase(void); +extern void dodefault(void); +extern void doreturn(void); +extern void dobreak(void); +extern void docont(void); +extern void dumpsw(WHILE *ws); +extern int find_tag(char *sname); +extern SYMBOL *find_member(TAG_SYMBOL *tag, char *sname); +extern void add_member(char *sname, char identity, char type, int offset, int storage_class); +extern int define_struct(char *sname, int storage, int is_struct); +extern void declare_global(int type, int storage, TAG_SYMBOL *mtag, int otag, int is_struct); +extern int initials(char *symbol_name, int type, int identity, int dim, int otag); +extern void struct_init(TAG_SYMBOL *tag, char *symbol_name); +extern int init(char *symbol_name, int type, int identity, int *dim, TAG_SYMBOL *tag); +extern void declare_local(int typ, int stclass, int otag); +extern int needsub(void); +extern int find_global (char *sname); +extern int find_locale (char *sname); +extern int add_global (char *sname, int identity, int type, int offset, int storage); +extern int add_local (char *sname, int identity, int type, int offset, int storage_class); +extern int symname(char *sname); +extern void illname(void); +extern void multidef(char *symbol_name); +extern void addwhile(WHILE *ptr); +extern void delwhile(void); +extern WHILE *readwhile(void); +extern WHILE *findwhile(void); +extern WHILE *readswitch(void); +extern void addcase(int val); diff --git a/Applications/SmallC/readme.txt.old b/Applications/SmallC/readme.txt.old new file mode 100644 index 00000000..b6e2e3ff --- /dev/null +++ b/Applications/SmallC/readme.txt.old @@ -0,0 +1,7 @@ + +There've been quite a few requests for this via net.micro.cpm, so's I +thought I'd post it thru mod.sources. This is Ron Cain's original Small +C compiler, but highly extended. Included are code generators for 8080, +6809, 68000, and VAX, as well as run-time support for 8080 CPM, VAX BSD4.1, +and a FLEX 6809 environment. See the README for a description of Small C's +limitations. diff --git a/Applications/SmallC/stmt.c b/Applications/SmallC/stmt.c new file mode 100644 index 00000000..c263556c --- /dev/null +++ b/Applications/SmallC/stmt.c @@ -0,0 +1,416 @@ +/* + * File stmt.c: 2.1 (83/03/20,16:02:17) + */ + +#include +#include "defs.h" +#include "data.h" + +/** + * statement parser + * called whenever syntax requires a statement. this routine + * performs that statement and returns a number telling which one + * @param func func is true if we require a "function_statement", which + * must be compound, and must contain "statement_list" (even if + * "declaration_list" is omitted) + * @return statement type + */ +int statement(int func) { + if ((ch () == 0) && input_eof) + return (0); + lastst = 0; + if (func) { + if (match ("{")) { + do_compound (YES); + return (lastst); + } else + error ("function requires compound statement"); + } + if (match ("{")) + do_compound (NO); + else + do_statement (); + return (lastst); +} + +/** + * declaration + */ +int statement_declare(void) { + if (amatch("register", 8)) + do_local_declares(DEFAUTO); + else if (amatch("auto", 4)) + do_local_declares(DEFAUTO); + else if (amatch("static", 6)) + do_local_declares(LSTATIC); + else if (do_local_declares(AUTO)) ; + else + return (NO); + return (YES); +} + +/** + * local declarations + * @param stclass + * @return + */ +int do_local_declares(int stclass) { + int type = 0; + int otag; // tag of struct object being declared + int sflag; // TRUE for struct definition, zero for union + char sname[NAMESIZE]; + blanks(); + if ((sflag=amatch("struct", 6)) || amatch("union", 5)) { + if (symname(sname) == 0) { // legal name ? + illname(); + } + if ((otag=find_tag(sname)) == -1) { // structure not previously defined + otag = define_struct(sname, stclass, sflag); + } + declare_local(STRUCT, stclass, otag); + } else if ((type = get_type()) != 0) { + declare_local(type, stclass, -1); + } else if (stclass == LSTATIC || stclass == DEFAUTO) { + declare_local(CINT, stclass, -1); + } else { + return(0); + } + need_semicolon(); + return(1); +} + +/** + * non-declaration statement + */ +void do_statement(void) { + if (amatch ("if", 2)) { + doif (); + lastst = STIF; + } else if (amatch ("while", 5)) { + dowhile (); + lastst = STWHILE; + } else if (amatch ("switch", 6)) { + doswitch (); + lastst = STSWITCH; + } else if (amatch ("do", 2)) { + dodo (); + need_semicolon (); + lastst = STDO; + } else if (amatch ("for", 3)) { + dofor (); + lastst = STFOR; + } else if (amatch ("return", 6)) { + doreturn (); + need_semicolon (); + lastst = STRETURN; + } else if (amatch ("break", 5)) { + dobreak (); + need_semicolon (); + lastst = STBREAK; + } else if (amatch ("continue", 8)) { + docont(); + need_semicolon (); + lastst = STCONT; + } else if (match (";")) + ; + else if (amatch ("case", 4)) { + docase (); + lastst = statement (NO); + } else if (amatch ("default", 7)) { + dodefault (); + lastst = statement (NO); + } else if (match ("#asm")) { + doasm (); + lastst = STASM; + } else if (match ("{")) + do_compound (NO); + else { + expression (YES); +/* if (match (":")) { + dolabel (); + lastst = statement (NO); + } else { +*/ need_semicolon (); + lastst = STEXP; +/* } +*/ } +} + +/** + * compound statement + * allow any number of statements to fall between "{" and "}" + * 'func' is true if we are in a "function_statement", which + * must contain "statement_list" + */ +void do_compound(int func) { + int decls; + + decls = YES; + ncmp++; + while (!match ("}")) { + if (input_eof) + return; + if (decls) { + if (!statement_declare ()) + decls = NO; + } else + do_statement (); + } + ncmp--; +} + +/** + * "if" statement + */ +void doif(void) { + int fstkp, flab1, flab2; + int flev; + + flev = local_table_index; + fstkp = stkp; + flab1 = getlabel (); + test (flab1, FALSE); + statement (NO); + stkp = gen_modify_stack (fstkp); + local_table_index = flev; + if (!amatch ("else", 4)) { + generate_label (flab1); + return; + } + gen_jump (flab2 = getlabel ()); + generate_label (flab1); + statement (NO); + stkp = gen_modify_stack (fstkp); + local_table_index = flev; + generate_label (flab2); +} + +/** + * "while" statement + */ +void dowhile(void) { + WHILE ws; + + ws.symbol_idx = local_table_index; + ws.stack_pointer = stkp; + ws.type = WSWHILE; + ws.case_test = getlabel (); + ws.while_exit = getlabel (); + addwhile (&ws); + generate_label (ws.case_test); + test (ws.while_exit, FALSE); + statement (NO); + gen_jump (ws.case_test); + generate_label (ws.while_exit); + local_table_index = ws.symbol_idx; + stkp = gen_modify_stack (ws.stack_pointer); + delwhile (); +} + +/** + * "do" statement + */ +void dodo(void) { + WHILE ws; + + ws.symbol_idx = local_table_index; + ws.stack_pointer = stkp; + ws.type = WSDO; + ws.body_tab = getlabel (); + ws.case_test = getlabel (); + ws.while_exit = getlabel (); + addwhile (&ws); + generate_label (ws.body_tab); + statement (NO); + if (!match ("while")) { + error ("missing while"); + return; + } + generate_label (ws.case_test); + test (ws.body_tab, TRUE); + generate_label (ws.while_exit); + local_table_index = ws.symbol_idx; + stkp = gen_modify_stack (ws.stack_pointer); + delwhile (); +} + +/** + * "for" statement + */ +void dofor(void) { + WHILE ws; + WHILE *pws; + + ws.symbol_idx = local_table_index; + ws.stack_pointer = stkp; + ws.type = WSFOR; + ws.case_test = getlabel (); + ws.incr_def = getlabel (); + ws.body_tab = getlabel (); + ws.while_exit = getlabel (); + addwhile (&ws); + pws = readwhile (); + needbrack ("("); + if (!match (";")) { + expression (YES); + need_semicolon (); + } + generate_label (pws->case_test); + if (!match (";")) { + expression (YES); + gen_test_jump (pws->body_tab, TRUE); + gen_jump (pws->while_exit); + need_semicolon (); + } else + pws->case_test = pws->body_tab; + generate_label (pws->incr_def); + if (!match (")")) { + expression (YES); + needbrack (")"); + gen_jump (pws->case_test); + } else + pws->incr_def = pws->case_test; + generate_label (pws->body_tab); + statement (NO); + gen_jump (pws->incr_def); + generate_label (pws->while_exit); + local_table_index = pws->symbol_idx; + stkp = gen_modify_stack (pws->stack_pointer); + delwhile (); +} + +/** + * "switch" statement + */ +void doswitch(void) { + WHILE ws; + WHILE *ptr; + + ws.symbol_idx = local_table_index; + ws.stack_pointer = stkp; + ws.type = WSSWITCH; + ws.case_test = swstp; + ws.body_tab = getlabel (); + ws.incr_def = ws.while_exit = getlabel (); + addwhile (&ws); + gen_immediate (); + print_label (ws.body_tab); + newline (); + gen_push (HL_REG); + needbrack ("("); + expression (YES); + needbrack (")"); + stkp = stkp + INTSIZE; // '?case' will adjust the stack + gen_jump_case (); + statement (NO); + ptr = readswitch (); + gen_jump (ptr->while_exit); + dumpsw (ptr); + generate_label (ptr->while_exit); + local_table_index = ptr->symbol_idx; + stkp = gen_modify_stack (ptr->stack_pointer); + swstp = ptr->case_test; + delwhile (); +} + +/** + * "case" label + */ +void docase(void) { + int val; + + val = 0; + if (readswitch ()) { + if (!number (&val)) + if (!quoted_char (&val)) + error ("bad case label"); + addcase (val); + if (!match (":")) + error ("missing colon"); + } else + error ("no active switch"); +} + +/** + * "default" label + */ +void dodefault(void) { + WHILE *ptr; + int lab; + + if ((ptr = readswitch ()) != 0) { + ptr->incr_def = lab = getlabel (); + generate_label (lab); + if (!match (":")) + error ("missing colon"); + } else + error ("no active switch"); +} + +/** + * "return" statement + */ +void doreturn(void) { + if (endst () == 0) + expression (YES); + gen_jump(fexitlab); +} + +/** + * "break" statement + */ +void dobreak(void) { + WHILE *ptr; + + if ((ptr = readwhile ()) == 0) + return; + gen_modify_stack (ptr->stack_pointer); + gen_jump (ptr->while_exit); +} + +/** + * "continue" statement + */ +void docont(void) { + WHILE *ptr; //int *ptr; + + if ((ptr = findwhile ()) == 0) + return; + gen_modify_stack (ptr->stack_pointer); + if (ptr->type == WSFOR) + gen_jump (ptr->incr_def); + else + gen_jump (ptr->case_test); +} + +/** + * dump switch table + */ +void dumpsw(WHILE *ws) { + int i,j; + + data_segment_gdata (); + generate_label (ws->body_tab); + if (ws->case_test != swstp) { + j = ws->case_test; + while (j < swstp) { + gen_def_word (); + i = 4; + while (i--) { + output_number (swstcase[j]); + output_byte (','); + print_label (swstlab[j++]); + if ((i == 0) | (j >= swstp)) { + newline (); + break; + } + output_byte (','); + } + } + } + gen_def_word (); + print_label (ws->incr_def); + output_string (",0"); + newline (); + code_segment_gtext (); +} diff --git a/Applications/SmallC/struct.c b/Applications/SmallC/struct.c new file mode 100644 index 00000000..c80995a3 --- /dev/null +++ b/Applications/SmallC/struct.c @@ -0,0 +1,95 @@ +/* + * File struct.c: (12/12/12,21:31:33) + */ + +#include +#include +#include "defs.h" +#include "data.h" + +/** + * look up a tag in tag table by name + * @param sname + * @return index + */ +int find_tag(char *sname) { + int index; + + index = 0; + while (index < tag_table_index) { + if (astreq (sname, tag_table[index].name, NAMEMAX)) { + return index; + } + ++index; + } + return -1; +} + +/** + * determine if 'sname' is a member of the struct with tag 'tag' + * @param tag + * @param sname + * @return pointer to member symbol if it is, else 0 + */ +SYMBOL *find_member(TAG_SYMBOL *tag, char *sname) { + int member_idx; + + member_idx = tag->member_idx; + + while (member_idx < tag->member_idx + tag->number_of_members) { + if (strcmp(member_table[member_idx].name, sname) == 0) + return &member_table[member_idx]; + ++member_idx; + } + return 0; +} + +/** + * add new structure member to table + * @param sname + * @param identity - variable, array, pointer, function + * @param typ + * @param offset + * @param storage + * @return + */ +void add_member(char *sname, char identity, char type, int offset, int storage_class) { + char *buffer_ptr; + SYMBOL *symbol; + if (member_table_index >= NUMMEMB) { + error("symbol table overflow"); + return; + } + symbol = &member_table[member_table_index]; + buffer_ptr = symbol->name; + while (alphanumeric(*buffer_ptr++ = *sname++)); + symbol->identity = identity; + symbol->type = type; + symbol->storage = storage_class; + symbol->offset = offset; + + member_table_index++; +} + +int define_struct(char *sname, int storage, int is_struct) { + TAG_SYMBOL *symbol; + char *buffer_ptr; + + //tag_table_index++; + if (tag_table_index >= NUMTAG) { + error("struct table overflow"); + return 0; + } + symbol = &tag_table[tag_table_index]; + buffer_ptr = symbol->name; + while (alphanumeric(*buffer_ptr++ = *sname++)); + symbol->size = 0; + symbol->member_idx = member_table_index; + + needbrack("{"); + do { + do_declarations(storage, &tag_table[tag_table_index], is_struct); + } while (!match ("}")); + symbol->number_of_members = member_table_index - symbol->member_idx; + return tag_table_index++; +} diff --git a/Applications/SmallC/sym.c b/Applications/SmallC/sym.c new file mode 100644 index 00000000..2a138c9b --- /dev/null +++ b/Applications/SmallC/sym.c @@ -0,0 +1,418 @@ +/* + * File sym.c: 2.1 (83/03/20,16:02:19) + */ + +#include +#include "defs.h" +#include "data.h" + +/** + * declare a static variable + * @param type + * @param storage + * @param mtag tag of struct whose members are being declared, or zero + * @param otag tag of struct object being declared. only matters if mtag is non-zero + * @param is_struct struct or union or no meaning + * @return + */ +void declare_global(int type, int storage, TAG_SYMBOL *mtag, int otag, int is_struct) { + int dim, identity; + char sname[NAMESIZE]; + + FOREVER { + FOREVER { + if (endst ()) + return; + dim = 1; + if (match ("*")) { + identity = POINTER; + } else { + identity = VARIABLE; + } + if (!symname (sname)) + illname (); + if (find_global (sname) > -1) + multidef (sname); + if (match ("[")) { + dim = needsub (); + //if (dim || storage == EXTERN) { + identity = ARRAY; + //} else { + // identity = POINTER; + //} + } + // add symbol + if (mtag == 0) { // real variable, not a struct/union member + identity = initials(sname, type, identity, dim, otag); + add_global (sname, identity, type, (dim == 0 ? -1 : dim), storage); + if (type == STRUCT) { + symbol_table[current_symbol_table_idx].tagidx = otag; + } + break; + } else if (is_struct) { + // structure member, mtag->size is offset + add_member(sname, identity, type, mtag->size, storage); + // store (correctly scaled) size of member in tag table entry + if (identity == POINTER) + type = CINT; + scale_const(type, otag, &dim); + mtag->size += dim; + } + else { + // union member, offset is always zero + add_member(sname, identity, type, 0, storage); + // store maximum member size in tag table entry + if (identity == POINTER) + type = CINT; + scale_const(type, otag, &dim); + if (mtag->size < dim) + mtag->size = dim; + } + } + if (!match (",")) + return; + } +} + +/** + * initialize global objects + * @param symbol_name + * @param type char or integer or struct + * @param identity + * @param dim + * @return 1 if variable is initialized + */ +int initials(char *symbol_name, int type, int identity, int dim, int otag) { + int dim_unknown = 0; + litptr = 0; + if(dim == 0) { // allow for xx[] = {..}; declaration + dim_unknown = 1; + } + if (!(type & CCHAR) && !(type & CINT) && !(type == STRUCT)) { + error("unsupported storage size"); + } + if(match("=")) { + // an array or struct + if(match("{")) { + // aggregate initialiser + if ((identity == POINTER || identity == VARIABLE) && type == STRUCT) { + // aggregate is structure or pointer to structure + dim = 0; + struct_init(&tag_table[otag], symbol_name); + } + else { + while((dim > 0) || (dim_unknown)) { + if (identity == ARRAY && type == STRUCT) { + // array of struct + needbrack("{"); + struct_init(&tag_table[otag], symbol_name); + --dim; + needbrack("}"); + } + else { + if (init(symbol_name, type, identity, &dim, 0)) { + dim_unknown++; + } + } + if(match(",") == 0) { + break; + } + } + if(--dim_unknown == 0) + identity = POINTER; + } + needbrack("}"); + // single constant + } else { + init(symbol_name, type, identity, &dim, 0); + } + } + return identity; +} + +/** + * initialise structure + * @param tag + */ +void struct_init(TAG_SYMBOL *tag, char *symbol_name) { + int dim ; + int member_idx; + + member_idx = tag->member_idx; + while (member_idx < tag->member_idx + tag->number_of_members) { + init(symbol_name, member_table[tag->member_idx + member_idx].type, + member_table[tag->member_idx + member_idx].identity, &dim, tag); + ++member_idx; + if ((match(",") == 0) && (member_idx != (tag->member_idx + tag->number_of_members))) { + error("struct initialisaton out of data"); + break ; + } + } +} + +/** + * evaluate one initializer, add data to table + * @param symbol_name + * @param type + * @param identity + * @param dim + * @param tag + * @return + */ +int init(char *symbol_name, int type, int identity, int *dim, TAG_SYMBOL *tag) { + int value, number_of_chars; + if(identity == POINTER) { + error("cannot assign to pointer"); + } + if(quoted_string(&value)) { + if((identity == VARIABLE) || !(type & CCHAR)) + error("found string: must assign to char pointer or array"); + number_of_chars = litptr - value; + *dim = *dim - number_of_chars; + while (number_of_chars > 0) { + add_data_initials(symbol_name, CCHAR, litq[value++], tag); + number_of_chars = number_of_chars - 1; + } + } else if (number(&value)) { + add_data_initials(symbol_name, CINT, value, tag); + *dim = *dim - 1; + } else if(quoted_char(&value)) { + add_data_initials(symbol_name, CCHAR, value, tag); + *dim = *dim - 1; + } else { + return 0; + } + return 1; +} + +/** + * declare local variables + * works just like "declglb", but modifies machine stack and adds + * symbol table entry with appropriate stack offset to find it again + * @param typ + * @param stclass + * @param otag index of tag in tag_table + */ +void declare_local(int typ, int stclass, int otag) { + int k, j; + char sname[NAMESIZE]; + + FOREVER { + FOREVER { + if (endst()) + return; + if (match("*")) + j = POINTER; + else + j = VARIABLE; + if (!symname(sname)) + illname(); + if (-1 != find_locale(sname)) + multidef (sname); + if (match("[")) { + k = needsub(); + if (k) { + j = ARRAY; + if (typ & CINT) { + k = k * INTSIZE; + } else if (typ == STRUCT) { + k = k * tag_table[otag].size; + } + } else { + j = POINTER; + k = INTSIZE; + } + } else { + if (j == POINTER) { + k = INTSIZE; + } else { + switch (typ) { + case CCHAR: + case UCHAR: + k = 1; + break; + case STRUCT: + k = tag_table[otag].size; + break; + default: + k = INTSIZE; + } + } + } + if (stclass != LSTATIC) { + stkp = gen_modify_stack(stkp - k); + add_local(sname, j, typ, stkp, AUTO); + } else + add_local(sname, j, typ, k, LSTATIC); + break; + } + if (!match(",")) + return; + } +} + +/** + * get required array size. [xx] + * @return array size + */ +int needsub(void) { + int num[1]; + + if (match ("]")) + return (0); + if (!number (num)) { + error ("must be constant"); + num[0] = 1; + } + if (num[0] < 0) { + error ("negative size illegal"); + num[0] = (-num[0]); + } + needbrack ("]"); + return (num[0]); +} + +/** + * search global table for given symbol name + * @param sname + * @return table index + */ +int find_global (char *sname) { + int idx; + + idx = 0; + while (idx < global_table_index) { + if (astreq (sname, symbol_table[idx].name, NAMEMAX)) + return (idx); + idx++; + } + return (-1); +} + +/** + * search local table for given symbol name + * @param sname + * @return table index + */ +int find_locale (char *sname) { + int idx; + + idx = local_table_index; + while (idx >= NUMBER_OF_GLOBALS) { + idx--; + if (astreq (sname, symbol_table[idx].name, NAMEMAX)) + return (idx); + } + return (-1); +} + +/** + * add new symbol to global table + * @param sname + * @param identity + * @param type + * @param offset size in bytes + * @param storage + * @return new index + */ +int add_global (char *sname, int identity, int type, int offset, int storage) { + SYMBOL *symbol; + char *buffer_ptr; + if ((current_symbol_table_idx = find_global(sname)) > -1) { + return (current_symbol_table_idx); + } + if (global_table_index >= NUMBER_OF_GLOBALS) { + error ("global symbol table overflow"); + return (0); + } + current_symbol_table_idx = global_table_index; + symbol = &symbol_table[current_symbol_table_idx]; + buffer_ptr = symbol->name; + while (alphanumeric(*buffer_ptr++ = *sname++)); + symbol->identity = identity; + symbol->type = type; + symbol->storage = storage; + symbol->offset = offset; + global_table_index++; + return (current_symbol_table_idx); +} + +/** + * add new symbol to local table + * @param sname + * @param identity + * @param type + * @param offset size in bytes + * @param storage_class + * @return + */ +int add_local (char *sname, int identity, int type, int offset, int storage_class) { + int k; + SYMBOL *symbol; + char *buffer_ptr; + + if ((current_symbol_table_idx = find_locale (sname)) > -1) { + return (current_symbol_table_idx); + } + if (local_table_index >= NUMBER_OF_GLOBALS + NUMBER_OF_LOCALS) { + error ("local symbol table overflow"); + return (0); + } + current_symbol_table_idx = local_table_index; + symbol = &symbol_table[current_symbol_table_idx]; + buffer_ptr = symbol->name; + while (alphanumeric(*buffer_ptr++ = *sname++)); + symbol->identity = identity; + symbol->type = type; + symbol->storage = storage_class; + if (storage_class == LSTATIC) { + data_segment_gdata(); + print_label(k = getlabel()); + output_label_terminator(); + gen_def_storage(); + output_number(offset); + newline(); + code_segment_gtext(); + offset = k; + } + symbol->offset = offset; + local_table_index++; + return (current_symbol_table_idx); +} + +/** + * test if next input string is legal symbol name + */ +int symname(char *sname) { + int k; + + blanks(); + if (!alpha (ch ())) + return (0); + k = 0; + while (alphanumeric(ch ())) + if (k < NAMEMAX) + sname[k++] = gch (); + sname[k] = 0; + return (1); +} + +/** + * print error message + */ +void illname(void) { + error ("illegal symbol name"); +} + +/** + * print error message + * @param symbol_name + * @return + */ +void multidef(char *symbol_name) { + error ("already defined"); + gen_comment (); + output_string (symbol_name); + newline (); +} + diff --git a/Applications/SmallC/while.c b/Applications/SmallC/while.c new file mode 100644 index 00000000..84d523e7 --- /dev/null +++ b/Applications/SmallC/while.c @@ -0,0 +1,86 @@ +/* File while.c: 2.1 (83/03/20,16:02:22) */ +/*% cc -O -c % + * + */ + +#include +#include +#include "defs.h" +#include "data.h" + +void addwhile(WHILE *ptr) { +//int ptr[]; + //int k; + + //if (wsptr == WSMAX) { + if (while_table_index == WSTABSZ) { + error ("too many active whiles"); + return; + } + //k = 0; + //while (k < WSSIZ) + // *wsptr++ = ptr[k++]; + memcpy(&ws[while_table_index++], ptr, sizeof(WHILE)); +} + +void delwhile(void) { + if (readwhile ()) { + //wsptr = wsptr - WSSIZ; + while_table_index--; + } +} + +WHILE *readwhile(void) { + if (while_table_index == 0) { + //if (wsptr == ws) { + error ("no active do/for/while/switch"); + return (0); + } else { + //return (wsptr-WSSIZ); + return &ws[while_table_index - 1]; + } +} + +WHILE *findwhile(void) { + //int *ptr; + int while_table_idx; + + //for (ptr = wsptr; ptr != ws;) { + while_table_idx = while_table_index; + for (; while_table_idx != 0;) { + //ptr = ptr - WSSIZ; + while_table_idx--; + //if (ptr[WSTYP] != WSSWITCH) + // return (ptr); + if (ws[while_table_idx].type != WSSWITCH) + return &ws[while_table_idx]; + } + error ("no active do/for/while"); + return (0); +} + +WHILE *readswitch(void) { + WHILE *ptr; //int *ptr; + + if ((ptr = readwhile ()) != 0) { + //if (ptr[WSTYP] == WSSWITCH) + if (ptr->type == WSSWITCH) { + return (ptr); + } + } + return (0); +} + +void addcase(int val) { + int lab; + + if (swstp == SWSTSZ) + error ("too many case labels"); + else { + swstcase[swstp] = val; + swstlab[swstp++] = lab = getlabel (); + print_label (lab); + output_label_terminator (); + newline (); + } +} -- 2.34.1