Small C 3.0 with some cleanups and ANSI processing
authorAlan Cox <alan@linux.intel.com>
Wed, 22 Jun 2016 19:34:02 +0000 (20:34 +0100)
committerAlan Cox <alan@linux.intel.com>
Wed, 22 Jun 2016 19:34:02 +0000 (20:34 +0100)
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.

62 files changed:
Applications/SmallC/8080/Makefile [new file with mode: 0644]
Applications/SmallC/8080/arglist.c [new file with mode: 0644]
Applications/SmallC/8080/bdos.c [new file with mode: 0644]
Applications/SmallC/8080/bdos1.c [new file with mode: 0644]
Applications/SmallC/8080/chio8080.c [new file with mode: 0644]
Applications/SmallC/8080/cret.asm [new file with mode: 0644]
Applications/SmallC/8080/crun.asm [new file with mode: 0644]
Applications/SmallC/8080/exit.c [new file with mode: 0644]
Applications/SmallC/8080/inout.c [new file with mode: 0644]
Applications/SmallC/8080/io8080.c [new file with mode: 0644]
Applications/SmallC/M_README [new file with mode: 0644]
Applications/SmallC/Makefile [new file with mode: 0644]
Applications/SmallC/README [new file with mode: 0644]
Applications/SmallC/README.2 [new file with mode: 0644]
Applications/SmallC/code6809.c [new file with mode: 0644]
Applications/SmallC/code8080.c [new file with mode: 0644]
Applications/SmallC/data.c [new file with mode: 0644]
Applications/SmallC/data.h [new file with mode: 0644]
Applications/SmallC/defs.h [new file with mode: 0644]
Applications/SmallC/error.c [new file with mode: 0644]
Applications/SmallC/expr.c [new file with mode: 0644]
Applications/SmallC/foo.c [new file with mode: 0644]
Applications/SmallC/function.c [new file with mode: 0644]
Applications/SmallC/gen.c [new file with mode: 0644]
Applications/SmallC/includes/ctype.h [new file with mode: 0644]
Applications/SmallC/includes/stdio.h [new file with mode: 0644]
Applications/SmallC/initials.c [new file with mode: 0644]
Applications/SmallC/io.c [new file with mode: 0644]
Applications/SmallC/lex.c [new file with mode: 0644]
Applications/SmallC/lib/abs.c [new file with mode: 0644]
Applications/SmallC/lib/atoi.c [new file with mode: 0644]
Applications/SmallC/lib/binary.c [new file with mode: 0644]
Applications/SmallC/lib/charclass.c [new file with mode: 0644]
Applications/SmallC/lib/fgets.c [new file with mode: 0644]
Applications/SmallC/lib/fputs.c [new file with mode: 0644]
Applications/SmallC/lib/getchar.c [new file with mode: 0644]
Applications/SmallC/lib/gets.c [new file with mode: 0644]
Applications/SmallC/lib/index.c [new file with mode: 0644]
Applications/SmallC/lib/itoa.c [new file with mode: 0644]
Applications/SmallC/lib/printn.c [new file with mode: 0644]
Applications/SmallC/lib/putchar.c [new file with mode: 0644]
Applications/SmallC/lib/puts.c [new file with mode: 0644]
Applications/SmallC/lib/rand.c [new file with mode: 0644]
Applications/SmallC/lib/reverse.c [new file with mode: 0644]
Applications/SmallC/lib/sbrk.c [new file with mode: 0644]
Applications/SmallC/lib/shell.c [new file with mode: 0644]
Applications/SmallC/lib/strcat.c [new file with mode: 0644]
Applications/SmallC/lib/strcmp.c [new file with mode: 0644]
Applications/SmallC/lib/strcpy.c [new file with mode: 0644]
Applications/SmallC/lib/strlen.c [new file with mode: 0644]
Applications/SmallC/lib/strncat.c [new file with mode: 0644]
Applications/SmallC/lib/strncmp.c [new file with mode: 0644]
Applications/SmallC/lib/strncpy.c [new file with mode: 0644]
Applications/SmallC/main.c [new file with mode: 0644]
Applications/SmallC/preproc.c [new file with mode: 0644]
Applications/SmallC/primary.c [new file with mode: 0644]
Applications/SmallC/prototype.h [new file with mode: 0644]
Applications/SmallC/readme.txt.old [new file with mode: 0644]
Applications/SmallC/stmt.c [new file with mode: 0644]
Applications/SmallC/struct.c [new file with mode: 0644]
Applications/SmallC/sym.c [new file with mode: 0644]
Applications/SmallC/while.c [new file with mode: 0644]

diff --git a/Applications/SmallC/8080/Makefile b/Applications/SmallC/8080/Makefile
new file mode 100644 (file)
index 0000000..f256081
--- /dev/null
@@ -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 (file)
index 0000000..f747b46
--- /dev/null
@@ -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 <tel:+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 (file)
index 0000000..b475f18
--- /dev/null
@@ -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 (file)
index 0000000..aa00c93
--- /dev/null
@@ -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 (file)
index 0000000..4cdd2e2
--- /dev/null
@@ -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 (file)
index 0000000..ea3d06c
--- /dev/null
@@ -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 (file)
index 0000000..d60070a
--- /dev/null
@@ -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 <r<r 1}
+?rdel:  mov     a,e
+        ral
+        mov     e,a
+        mov     a,d
+        ral
+        mov     d,a
+        ora     e
+        ret
+; {BC : DE}
+?cmpbd: mov     a,e
+        sub     c
+        mov     a,d
+        sbb     b
+        ret
+; case jump
+?case:  xchg                    ;switch value to DE
+        pop     h               ;get table address
+?case1: call    ?case4          ;get case value
+        mov     a,e
+        cmp     c               ;equal to switch value ?
+        jnz     ?case2          ;no
+        mov     a,d
+        cmp     b               ;equal to switch value ?
+        jnz     ?case2          ;no
+        call    ?case4          ;get case label
+        jz      ?case3          ;end of table, go to default
+        push    b
+        ret                     ;case jump
+?case2: call    ?case4          ;get case label
+        jnz     ?case1          ;next case
+?case3: dcx     h
+        dcx     h
+        dcx     h
+        mov     d,m
+        dcx     h
+        mov     e,m
+        xchg
+        pchl                    ;default jump
+?case4: mov     c,m
+        inx     h
+        mov     b,m
+        inx     h
+        mov     a,c
+        ora     b
+        ret
+;
+;
+;
+Xstktop:        lxi     h,0     ;return current stack pointer (for sbrk)
+        dad     sp
+        ret
+        cseg
+etext:
+        dseg
+brkend: dw      edata           ;current "break"
+edata:
+;
+;
+;
+        end
diff --git a/Applications/SmallC/8080/exit.c b/Applications/SmallC/8080/exit.c
new file mode 100644 (file)
index 0000000..10a7fe1
--- /dev/null
@@ -0,0 +1,6 @@
+exit(retcode) int retcode; {
+#asm
+        jmp     0
+#endasm
+}
+
diff --git a/Applications/SmallC/8080/inout.c b/Applications/SmallC/8080/inout.c
new file mode 100644 (file)
index 0000000..16f3f18
--- /dev/null
@@ -0,0 +1,28 @@
+inp(pno) char pno; {
+        pno;
+#asm
+        mov     a,l
+        sta     ininst+1 <tel:+1>
+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 <tel:+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 (file)
index 0000000..f6c457f
--- /dev/null
@@ -0,0 +1,305 @@
+/*      Basic CP/M file I/O:
+fopen,fclose,fgetc,fputc,feof
+
+Original:       Paul Tarvydas
+Fixed by:       Chris Lewis
+*/
+#include <stdio.h>
+
+#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 (++i<NBLOCKS);
+            bdos(SETDMA, DEFAULT_DMA);
+            /* if i still 0, no blocks read =>eof*/
+            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 <tel:+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 <tel:+1>);
+                return fileno;
+            }
+        }
+    }
+    return NULL;
+
+}
+
+clearfcb(fcb) char fcb[];
+{
+    int i;
+    for (i=0; i<FCBSIZ; fcb[i++] = 0);
+    /* blank out name field */
+    for (i=1; i<12; fcb[i++] = ' ');
+    return fcb;
+
+}
+
+movname(fcb, str) char fcb[], *str;
+{
+    int i;
+    char c;
+    i = 1; /* first char of name @ pos 1 */
+    *fcb = 0;
+    if (':' == str[1]) {
+        c = toupper(str[0]);
+        if (('A' <= c) & ('B' >= 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 <tel:+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<NBUFFS; modes[i++] = FREE);
+
+}
+
+fcbaddr(unit) int unit;
+{
+    /* returns address of fcb associated with given unit -
+        unit taken with origin 0 (ie. std's not included) */
+    return &fcbs[unit * FCBSIZ];
+
+}
+
+buffaddr(unit) int unit;
+{
+    return &buffs[unit * BUFSIZ];
+
+}
+
+feof (unit) FILE *unit;
+{
+    if ((unit == stdin) & eofstdin)
+        return 1;
+    if (modes[unit - UNIT_OFFSET] == READ_EOF)
+        return 1;
+    return 0;
+}
+
diff --git a/Applications/SmallC/M_README b/Applications/SmallC/M_README
new file mode 100644 (file)
index 0000000..8dff612
--- /dev/null
@@ -0,0 +1,14 @@
+                ***  Moderator's README ***
+
+This directory contains the base source code for the smallC compiler
+(actually three versions:  the 8080, 6809 and vax code generators are
+here also.)
+
+The "includes" directory contains headers which are intended to be
+included in
+user programs - the place where these files reside should be set in the
+Makefile
+as INCDIR.  The directories "6809", "8080", and "vax" contain runtime
+support
+for the respective compilers.  The directory "lib" contains the source code
+for some common C library functions (portable ones).
diff --git a/Applications/SmallC/Makefile b/Applications/SmallC/Makefile
new file mode 100644 (file)
index 0000000..29b30e7
--- /dev/null
@@ -0,0 +1,27 @@
+.SUFFIXES: .c .rel
+
+CC = fcc
+CFLAGS = -DTINY -DM8080
+COPT = -O2
+
+OBJS = initials.rel data.rel error.rel expr.rel function.rel gen.rel io.rel lex.rel main.rel preproc.rel \
+       primary.rel stmt.rel sym.rel while.rel code6809.rel code8080.rel struct.rel
+
+INC = data.h defs.h prototype.h
+
+all:    scc8080
+
+
+scc8080: $(OBJS)
+       $(CC) -o scc8080 --nostdio $(OBJS)
+
+#scc6809: $(OBJS)
+#      $(CC) -o scc8080 --nostdio $(OBJS)
+
+clean:
+       rm -f $(OBJ) scc8080 *.rel *~
+
+.c.rel:
+       $(CC) $(COPT) $(CFLAGS) -c $< -o $@
+
+$(OBJS) : $(INC)
diff --git a/Applications/SmallC/README b/Applications/SmallC/README
new file mode 100644 (file)
index 0000000..ee2f917
--- /dev/null
@@ -0,0 +1,89 @@
+
+README for version imported from github SmallC-85
+-------------------------------------------------
+
+Revived version of SmallC based on Chris Lewis' port to UNIX V. I have
+mainly rewritten code to use structures and to make it compile using GCC
+silently without warnigns.
+
+Support for one line comments from C99 specification was added as well
+as capability to handle Windows EOLs.
+
+Initialisation of global variables is also possible. When not initialised
+global var is assigned zero at compile time.
+
+Furthermore support for ANSI style method declaration, support for unsigned types, 
+support for undocumented 8085 istructions LHLX, SHLX, LDSI, ARHL and support
+for structs and unions have been added.
+
+Generated code is suitable for ASXXXX assembler/linker.
+
+
+SmallC compiled for win32 can be downloaded here:
+https://drive.google.com/file/d/0B2TmWnRjWCj2alRqZHM1VEgwNFE/edit?usp=sharing
+
+-------------------------- original posting ------------------------------
+
+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/README.2 b/Applications/SmallC/README.2
new file mode 100644 (file)
index 0000000..28d50e2
--- /dev/null
@@ -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 (file)
index 0000000..b4762f7
--- /dev/null
@@ -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 <stdio.h>
+#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 (file)
index 0000000..847ff5c
--- /dev/null
@@ -0,0 +1,798 @@
+/*      File code8080.c: 2.2 (84/08/31,10:05:09) */
+/*% cc -O -c %
+ *
+ */
+
+#include <stdio.h>
+#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 (file)
index 0000000..d6c9740
--- /dev/null
@@ -0,0 +1,65 @@
+/*      File data.c: 2.2 (84/11/27,16:26:13) */
+/*% cc -O -c %
+ *
+ */
+
+#include <stdio.h>
+#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 (file)
index 0000000..2ca78fc
--- /dev/null
@@ -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 (file)
index 0000000..c6fbc22
--- /dev/null
@@ -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 (file)
index 0000000..4de46c3
--- /dev/null
@@ -0,0 +1,45 @@
+/*      File error.c: 2.1 (83/03/20,16:02:00) */
+/*% cc -O -c %
+ *
+ */
+
+#include <stdio.h>
+#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 (file)
index 0000000..f502393
--- /dev/null
@@ -0,0 +1,787 @@
+/*
+ * File expr.c: 2.2 (83/06/21,11:24:26)
+ */
+
+#include <stdio.h>
+#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 (file)
index 0000000..6f189da
--- /dev/null
@@ -0,0 +1,2 @@
+poop()
+
diff --git a/Applications/SmallC/function.c b/Applications/SmallC/function.c
new file mode 100644 (file)
index 0000000..ea4dc24
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * File function.c: 2.1 (83/03/20,16:02:04)
+ */
+
+#include <stdio.h>
+#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 (file)
index 0000000..46584db
--- /dev/null
@@ -0,0 +1,188 @@
+/*      File gen.c: 2.1 (83/03/20,16:02:06) */
+/*% cc -O -c %
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#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 (file)
index 0000000..07c42f3
--- /dev/null
@@ -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 (file)
index 0000000..fcc9f11
--- /dev/null
@@ -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 (file)
index 0000000..bd39af7
--- /dev/null
@@ -0,0 +1,141 @@
+#include <stdio.h>
+#include <string.h>
+#include "defs.h"
+#include "data.h"
+
+/**
+ * erase the data storage
+ */
+void create_initials(void) {
+    /*int i;
+    for (i=0; i<INITIALS_SIZE; i++) {
+        initials_data_table[i] = 0;
+    }
+    for (i=0; i<NUMBER_OF_GLOBALS; i++) {
+        initials_table[i].type = 0;
+        initials_table[i].name[0] = 0;
+        initials_table[i].dim = 0;
+        initials_table[i].data_len = 0;
+    }*/
+}
+
+/**
+ * add new symbol to table, initialise begin position in data array
+ * @param symbol_name
+ * @param type
+ */
+void add_symbol_initials(char *symbol_name, char type) {
+    strcpy(initials_table[initials_idx].name, symbol_name);
+    initials_table[initials_idx].type = type;
+}
+
+/**
+ * find symbol in table, count position in data array
+ * @param symbol_name
+ * @return
+ */
+int find_symbol_initials(char *symbol_name) {
+    int result = 0;
+    initials_data_idx = 0;
+    for (initials_idx=0; initials_table[initials_idx].type != 0; initials_idx++) {
+        if (initials_idx >= 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 (file)
index 0000000..638dd97
--- /dev/null
@@ -0,0 +1,199 @@
+/*      File io.c: 2.1 (83/03/20,16:02:07) */
+/*% cc -O -c %
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#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 (file)
index 0000000..a79aa82
--- /dev/null
@@ -0,0 +1,228 @@
+/*      File lex.c: 2.1 (83/03/20,16:02:09) */
+/*% cc -O -c %
+ *
+ */
+
+#include <stdio.h>
+#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 (file)
index 0000000..9a0adfe
--- /dev/null
@@ -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 (file)
index 0000000..265e3f2
--- /dev/null
@@ -0,0 +1,21 @@
+#include <stdio.h>
+#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 (file)
index 0000000..8b6cea5
--- /dev/null
@@ -0,0 +1,22 @@
+/* binary search for string word in table[0] .. table[n-1]
+ *      reference CPL pg. 125
+ */
+#include <stdio.h>
+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 (file)
index 0000000..39fb873
--- /dev/null
@@ -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 (file)
index 0000000..82e44d2
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+#include        <stdio.h>
+*/
+#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 (file)
index 0000000..1f916b5
--- /dev/null
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+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 (file)
index 0000000..48fedfb
--- /dev/null
@@ -0,0 +1,5 @@
+#include <stdio.h>
+getchar() {
+        return(fgetc(stdin));
+}
+
diff --git a/Applications/SmallC/lib/gets.c b/Applications/SmallC/lib/gets.c
new file mode 100644 (file)
index 0000000..21385ae
--- /dev/null
@@ -0,0 +1,28 @@
+#include <stdio.h>
+#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 (file)
index 0000000..26c7204
--- /dev/null
@@ -0,0 +1,18 @@
+/*      index - find index of string t in s
+ *      reference CPL 67.
+ */
+#include <stdio.h>
+#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 (file)
index 0000000..7411dd9
--- /dev/null
@@ -0,0 +1,14 @@
+#include <stdio.h>
+#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 (file)
index 0000000..be26340
--- /dev/null
@@ -0,0 +1,16 @@
+#include <stdio.h>
+/* 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 (file)
index 0000000..a96a6e3
--- /dev/null
@@ -0,0 +1,5 @@
+#include <stdio.h>
+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 (file)
index 0000000..7d5511f
--- /dev/null
@@ -0,0 +1,6 @@
+#include <stdio.h>
+#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 (file)
index 0000000..97112d1
--- /dev/null
@@ -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 (file)
index 0000000..c77151a
--- /dev/null
@@ -0,0 +1,17 @@
+#include <stdio.h>
+/* 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 (file)
index 0000000..65ea2fc
--- /dev/null
@@ -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 (file)
index 0000000..13ad456
--- /dev/null
@@ -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 (file)
index 0000000..811667e
--- /dev/null
@@ -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 (file)
index 0000000..d543d39
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Compare strings:  s1>s2: >0  s1==s2: 0  s1<s2: <0
+ */
+
+strcmp(s1, s2)
+char *s1, *s2;
+{
+
+        while (*s1 == *s2++)
+                if (*s1++=='\0')
+                        return(0);
+        return(*s1 - *--s2);
+        }
diff --git a/Applications/SmallC/lib/strcpy.c b/Applications/SmallC/lib/strcpy.c
new file mode 100644 (file)
index 0000000..66da42c
--- /dev/null
@@ -0,0 +1,18 @@
+#include <stdio.h>
+/*
+ * 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 (file)
index 0000000..e3bd9d4
--- /dev/null
@@ -0,0 +1,8 @@
+#include <stdio.h>
+/* 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 (file)
index 0000000..c166216
--- /dev/null
@@ -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 (file)
index 0000000..bdd5a30
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Compare strings (at most n bytes):  s1>s2: >0  s1==s2: 0  s1<s2: <0
+ */
+
+strncmp(s1, s2, n)
+char *s1, *s2;
+int n;
+{
+
+        while (--n >= 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 (file)
index 0000000..e14cd4c
--- /dev/null
@@ -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 (file)
index 0000000..a26cc7a
--- /dev/null
@@ -0,0 +1,363 @@
+/*
+ * File main.c: 2.7 (84/11/28,10:14:56)
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#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<argc; i++) {
+        param = argv[i];
+        if (*param == '-') {
+            while (*++param) {
+                switch (*param) {
+                    case 't': case 'T': // output c source as asm comments
+                        ctext = 1;
+                        break;
+                    case 'a': case 'A': // no argument count in A to function calls
+                        aflag = 0;
+                        break;
+                    case 'u': case 'U': // use undocumented 8085 instructions
+                        uflag = 1;
+                        break;
+                    case 'd': case 'D': // define macro
+                        bp = ++param;
+                        if (!*param) usage();
+                        while (*param && *param != '=') param++;
+                        if (*param == '=') *param = '\t';
+                        while (*param) param++;
+                        param--;
+                        defmac(bp);
+                        break;
+                    default:
+                        usage();
+                }
+            }
+        } else {
+            usage();
+            break;
+        }
+    }
+
+    if (i == argc) {
+        compile(NULL); // training mode - read code from stdin
+        exit(errs != 0);
+    }
+    usage();
+}
+
+/**
+ * compile one file if filename is NULL redirect do to stdin/stdout
+ * @param file filename
+ * @return 
+ */
+void compile(char *file) {
+    if (file == NULL || filename_typeof(file) == 'c') {
+        global_table_index = 0;
+        local_table_index = NUMBER_OF_GLOBALS;
+        while_table_index = 0;
+        tag_table_index = 0;
+        inclsp =
+        iflevel =
+        skiplevel =
+        swstp =
+        litptr =
+        stkp =
+        errcnt =
+        ncmp =
+        lastst =
+        //quote[1] =
+        0;
+        input2 = -1;
+        //quote[0] = '"';
+        cmode = 1;
+        glbflag = 1;
+        nxtlab = 0;
+        litlab = getlabel();
+        defmac("end\tmemory");
+        //add_global("memory", ARRAY, CCHAR, 0, EXTERN);
+        //add_global("stack", ARRAY, CCHAR, 0, EXTERN);
+        rglobal_table_index = global_table_index; //rglbptr = glbptr;
+        //add_global("etext", ARRAY, CCHAR, 0, EXTERN);
+        //add_global("edata", ARRAY, CCHAR, 0, EXTERN);
+        defmac("short\tint");
+        initmac();
+        // compiler body
+        if (file == NULL) {
+            input = 0;
+        } else if (!openin(file))
+            return;
+        if (file == NULL) {
+            output = 1;
+        } else if (!openout())
+            return;
+        header();
+        code_segment_gtext();
+        parse();
+        close(input);
+        data_segment_gdata();
+        dumplits();
+        dumpglbs();
+        errorsummary();
+        trailer();
+        oflush();
+        close(output);
+        pl("");
+        errs = errs || errfile;
+    } else {
+        writee("Don't understand file ");
+        writee(file);
+        errs = 1;
+    }
+}
+
+void frontend_version(void) {
+    output_string("\tFront End (2.7,84/11/28)");
+    output_string("\n;\tFront End for ASXXXX (2.8,13/01/20)");
+}
+
+/**
+ * prints usage
+ * @return exits the execution
+ */
+void usage(void) {
+    writee("unknown argument.\n");
+    exit(1);
+}
+
+/**
+ * process all input text
+ * at this level, only static declarations, defines, includes,
+ * and function definitions are legal.
+ */
+void parse(void) {
+    while (!input_eof) {
+        if (amatch("extern", 6))
+            do_declarations(EXTERN, NULL_TAG, 0);
+        else if (amatch("static", 6))
+            do_declarations(STATIC, NULL_TAG, 0);
+        else if (do_declarations(PUBLIC, NULL_TAG, 0));
+        else if (match("#asm"))
+            doasm();
+        else if (match("#include"))
+            doinclude();
+        else if (match("#define")) {
+            dodefine();
+        }
+        else if (match("#undef"))
+            doundef();
+        else {
+            newfunc();
+        }
+        blanks();
+    }
+}
+
+/**
+ * parse top level declarations
+ * @param stclass storage
+ * @param mtag
+ * @param is_struct
+ * @return 
+ */
+int do_declarations(int stclass, TAG_SYMBOL *mtag, int is_struct) {
+    int type;
+    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_global(STRUCT, stclass, mtag, otag, is_struct);
+    } else if ((type = get_type()) != 0) {
+        declare_global(type, stclass, mtag, 0, is_struct);
+    } else if (stclass == PUBLIC) {
+        return (0);
+    } else {
+        declare_global(CINT, stclass, mtag, 0, is_struct);
+    }
+    need_semicolon();
+    return (1);
+}
+
+/**
+ * dump the literal pool
+ */
+void dumplits(void) {
+    int j, k;
+
+#ifndef TINY
+    if (litptr == 0)
+        return;
+    print_label(litlab);
+    output_label_terminator();
+    k = 0;
+    while (k < litptr) {
+        gen_def_byte();
+        j = 8;
+        while (j--) {
+            output_number(litq[k++] & 127);
+            if ((j == 0) | (k >= 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; i<dim; i++) {
+                    if (symbol->type == 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; i<number_of_members; i++) {
+        // i is the index of current member, get type
+        int member_type = member_table[tag_table[symbol->tagidx].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 (file)
index 0000000..a00ec38
--- /dev/null
@@ -0,0 +1,364 @@
+/*      File preproc.c: 2.3 (84/11/27,11:47:40) */
+/*% cc -O -c %
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#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 (file)
index 0000000..28c9af7
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+ * File primary.c: 2.4 (84/11/27,16:26:07)
+ */
+
+#include <stdio.h>
+#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 (file)
index 0000000..608501f
--- /dev/null
@@ -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 (file)
index 0000000..b6e2e3f
--- /dev/null
@@ -0,0 +1,7 @@
+\r
+There've been quite a few requests for this via net.micro.cpm, so's I\r
+thought I'd post it thru mod.sources.  This is Ron Cain's original Small\r
+C compiler, but highly extended.  Included are code generators for 8080,\r
+6809, 68000, and VAX, as well as run-time support for 8080 CPM, VAX BSD4.1,\r
+and a FLEX 6809 environment.  See the README for a description of Small C's\r
+limitations.\r
diff --git a/Applications/SmallC/stmt.c b/Applications/SmallC/stmt.c
new file mode 100644 (file)
index 0000000..c263556
--- /dev/null
@@ -0,0 +1,416 @@
+/*
+ * File stmt.c: 2.1 (83/03/20,16:02:17)
+ */
+
+#include <stdio.h>
+#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 (file)
index 0000000..c80995a
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * File struct.c: (12/12/12,21:31:33)
+ */
+
+#include <stdio.h>
+#include <string.h>
+#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 (file)
index 0000000..2a138c9
--- /dev/null
@@ -0,0 +1,418 @@
+/*
+ * File sym.c: 2.1 (83/03/20,16:02:19)
+ */
+
+#include <stdio.h>
+#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 (file)
index 0000000..84d523e
--- /dev/null
@@ -0,0 +1,86 @@
+/*      File while.c: 2.1 (83/03/20,16:02:22) */
+/*% cc -O -c %
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#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 ();
+    }
+}