├── .gitignore ├── Caldera-license.pdf ├── Makefile ├── README.md ├── c72 ├── cvtab.sh ├── docs └── ctour.pdf ├── examples ├── cp.c ├── fizzbuzz.c └── helloworld.c ├── fix_tab.sh ├── src ├── c0.h ├── c00.c ├── c01.c ├── c02.c ├── c03.c ├── c0t.c ├── c1.h ├── c10.c ├── c11.c ├── c1t.c ├── cctab.s ├── config.h ├── cvopt.c ├── efftab.s ├── pdp11_mov.s ├── regtab.s └── sptab.s ├── test.sh └── test ├── addition.c ├── addition_expected.txt ├── addition_stack.c ├── addition_stack_expected.txt ├── assign_div.c ├── assign_div_expected.txt ├── assign_eff.c ├── assign_eff_expected.txt ├── assign_mul.c ├── assign_mul_expected.txt ├── assign_op_eff.c ├── assign_op_eff_expected.txt ├── assign_or.c ├── assign_or_expected.txt ├── assign_shr.c ├── assign_shr_expected.txt ├── goto.c ├── goto_expected.txt ├── if.c ├── if_expected.txt ├── incdec_eff.c ├── incdec_eff_expected.txt ├── incdec_post_stack.c ├── incdec_post_stack_expected.txt ├── incdec_pre_stack.c ├── incdec_pre_stack_expected.txt ├── relational.c ├── relational_expected.txt ├── switch.c └── switch_expected.txt /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.tmp 3 | docs 4 | *.exe 5 | cmake* 6 | src/*_conv.s 7 | /src/sptab_old.s 8 | -------------------------------------------------------------------------------- /Caldera-license.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vegesm/c72/e151588a40fba563e1c82d865183bd2721a65363/Caldera-license.pdf -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS =-Wno-implicit-int -Wno-int-conversion -m32 3 | 4 | c0_src = $(wildcard src/c0*.c) 5 | c1_src = $(wildcard src/c1*.c) 6 | 7 | c1_tabs = $(wildcard src/*tab.s) 8 | c1_tabs_converted = $(c1_tabs:%tab.s=%tab_conv.s) 9 | 10 | all: c0 c1 11 | 12 | c0: $(c0_src) src/c0.h 13 | $(CC) $(CFLAGS) -o c0 $(c0_src) 14 | 15 | c1: $(c1_src) $(c1_tabs_converted) src/c1.h 16 | $(CC) $(CFLAGS) -D __DIR__=\"`realpath src`\" -o c1 $(c1_src) $(c1_tabs_converted) 17 | 18 | cvopt: src/cvopt.c 19 | $(CC) $(CFLAGS) -o cvopt src/cvopt.c 20 | 21 | %tab_conv.s: %tab.s cvopt 22 | ./cvtab.sh $< > $@ 23 | 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # c72 2 | A port of the [earliest C compiler](https://www.bell-labs.com/usr/dmr/www/primevalC.html) to x86. The compiler generates 32-bit code and works on modern Linux with a current libc. It follows the architecture of the original implementation closely, keeping the bugs and missing features. 3 | 4 | ## Usage 5 | To compile the compiler: 6 | ```shell 7 | # install 32-bit libraries 8 | sudo apt-get install gcc-multilib 9 | 10 | make 11 | ./c72 examples/fizzbuzz.c fizzbuzz 12 | ./fizzbuzz 13 | ``` 14 | Note: if you get errors on missing "bits/libc-header-start.h" headers make sure you have the 32bit libc installed. 15 | 16 | I've also attached an [early implementation of cp](https://www.tuhs.org/cgi-bin/utree.pl?file=V5/usr/source/s1/cp.c) from UNIX v5. It worked with minor modifications with this compiler, on my Ubuntu 18.04. It's pretty neat, to have a nearly 50 years old code compile with a nearly 50 years old compiler and run on a modern OS! 17 | 18 | 19 | ## Differences to modern C 20 | 21 | This version of C is from around 1972. While the general syntax is pretty much the same as today, 22 | there are tons of missing features: 23 | - no preprocessor, no for loops 24 | - bitwise NOT and XOR is not implemented 25 | - no short-circuiting AND and OR 26 | - even though there is a keyword for `float` and `double`, floating point calculations are not implemented, you can not even write a floating point literal 27 | - the type system is very weak: pointers, chars, ints can be freely converted into one another 28 | - types of the function parameters are not checked, anything can be passed to any function 29 | - compound assignment operators are reversed, they are `=+`, `=*` 30 | - only integer global variables can be defined, and the syntax is strange: 31 | ``` 32 | /* defines globalvar to have the value of 2 */ 33 | globalvar 2; 34 | 35 | /* equivalent to int globalarr[]={1, 2, 3}; */ 36 | globalarr[] 1, 2, 3; 37 | ``` 38 | - variable names can be of any length but only the first 8 characters are used; i.e. deadbeef1 and deadbeef2 are effectively the same variables 39 | 40 | 41 | ## Internals 42 | The compiler has two stages: `c0` and `c1`. `c0` parses the input C file and generates a half-assembly half-parsed syntax tree temporary file. It is not meant to make the second stage easily portable, rather the memory restrictions of the PDP-11 made the split necessary. Then `c1` generates the final assembly, translating the syntax trees to actual code. 43 | 44 | `c0` is a fairly straightforward parser. One interesting bit is that `a[b]` is parsed and then converted to `*(a+b)` already in this very early version of C (if you are not familiar with the C standard, `a[b]` is defined to be equivalent to `*((a)+(b))`). 45 | 46 | `c1` uses a set of code-generation tables to create the final assmebly. For example, addition is defined as: 47 | ``` 48 | %n,aw 49 | F 50 | add A2,R 51 | ``` 52 | The part starting with `%` is the pattern the syntax tree has to match. This pattern means the first operand can be anything (`n`), the second operand is a word sized (`w`) variable (`a` - addressible). Then the code generation instructions say that calculate and place the first operand in the current register (`F`), and create an `add` instruction where the source argument is the address of the second operand (`A2`) and the target argument is the current register (`R`). 53 | For example, the C code `2+x` would generate the following assembly: 54 | 55 | ```asm 56 | mov $2, %eax 57 | add 4(%ebp), %eax 58 | ``` 59 | Here I assumed that `x` is the first parameter of the function so it is placed right after the stack frame. 60 | 61 | If you are interested in a more in-depth description see Dennis Ritchie's [A Tour through the UNIX C compiler](docs/ctour.pdf). Although it is for a newer version with some differences, it is still helpful to understand `c1`. 62 | 63 | -------------------------------------------------------------------------------- /c72: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | BUILD_FOLDER=. 5 | ASM_PATH="${1%.*}.s" 6 | 7 | $BUILD_FOLDER/c0 $1 $1.tmp 8 | $BUILD_FOLDER/c1 $1.tmp $ASM_PATH 9 | 10 | rm $1.tmp 11 | 12 | gcc -m32 $ASM_PATH -o $2 13 | 14 | 15 | -------------------------------------------------------------------------------- /cvtab.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | UNDERSCORE=_ 4 | if [ "$(expr substr $(uname -s) 1 5)" = "Linux" ]; then 5 | UNDERSCORE= 6 | fi 7 | 8 | # remove multiline comments by converting '*/' to @ and then doing a lazy match 9 | # remove leading underscore on Linux 10 | cat $1 | sed -r 's|\*/|@|g' | sed -r ':a;N;$!ba;s|/\*[^@]+@||g' | \ 11 | ./cvopt | sed -r 's/_(eff|reg|sp|cc)tab/'$UNDERSCORE'\1tab/' -------------------------------------------------------------------------------- /docs/ctour.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vegesm/c72/e151588a40fba563e1c82d865183bd2721a65363/docs/ctour.pdf -------------------------------------------------------------------------------- /examples/cp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This is an early implementation of cp from https://www.tuhs.org/cgi-bin/utree.pl?file=V5/usr/source/s1/cp.c 3 | * It works nearly as-is, the only change that pointer declarations had to be changed to array declarations. 4 | * 5 | * Usage: 6 | * cp oldfile newfile 7 | */ 8 | 9 | main(argc,argv) 10 | char argv[][]; 11 | { 12 | int buf[256]; 13 | int fold, fnew, n, ct, tell; 14 | char p1[], p2[], bp[]; 15 | int mode; 16 | 17 | tell = 0; 18 | if(argc == 4 & argv[1][0] == '-' & argv[1][1] == 't') { 19 | argc--; 20 | argv++; 21 | tell = 1; 22 | } 23 | if(argc != 3) { 24 | write(1, "Usage: cp oldfile newfile\n", 26); 25 | exit(1); 26 | } 27 | if((fold = open(argv[1], 0)) < 0) { 28 | write(1, "Cannot open old file.\n", 22); 29 | exit(1); 30 | } 31 | fstat(fold, buf); 32 | mode = buf[4]; 33 | 34 | if((fnew = creat(argv[2], mode)) < 0){ 35 | stat(argv[2], buf); 36 | if((buf[4] & 060000) == 040000) { 37 | p1 = argv[1]; 38 | p2 = argv[2]; 39 | bp = buf; 40 | while(*bp++ = *p2++); 41 | bp[-1] = '/'; 42 | p2 = bp; 43 | while(*bp = *p1++) 44 | if(*bp++ == '/') 45 | bp = p2; 46 | if((fnew = creat(buf, mode)) < 0) { 47 | write(1, "Cannot creat new file.\n", 23); 48 | exit(1); 49 | } 50 | } else { 51 | write(1, "Cannot creat new file.\n", 23); 52 | exit(1); 53 | } 54 | } 55 | ct = 0; 56 | while(n = read(fold, buf, 512)) { 57 | if(n < 0) { 58 | write(1, "Read error\n", 11); 59 | exit(1); 60 | } else 61 | if(write(fnew, buf, n) != n){ 62 | write(1, "Write error.\n", 13); 63 | exit(1); 64 | } 65 | ct++; 66 | } 67 | if(tell) { 68 | conf(ct, 6, buf); 69 | buf[3] = '\n'; 70 | write(1, buf, 7); 71 | } 72 | exit(0); 73 | } 74 | 75 | conf(n,width,buf) 76 | char buf[]; 77 | { 78 | auto i,a; 79 | 80 | i = width; 81 | while(i--) buf[i] = ' '; 82 | 83 | buf[(a = n/10)?conf(a,--width,buf):--width] = n%10 + '0'; 84 | 85 | return(++width); 86 | } 87 | 88 | -------------------------------------------------------------------------------- /examples/fizzbuzz.c: -------------------------------------------------------------------------------- 1 | main() { 2 | auto n, i; 3 | n = 20; 4 | 5 | i = 1; /* no for loops */ 6 | while (i <= n) { 7 | if (i % 15 == 0) { 8 | printf("fizzbuzz\n"); 9 | } else if (i % 3 == 0) { 10 | printf("fizz\n"); 11 | } else if (i % 5 == 0) { 12 | printf("buzz\n"); 13 | } else { 14 | printf("%d\n", i); 15 | } 16 | i++; 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /examples/helloworld.c: -------------------------------------------------------------------------------- 1 | main() { 2 | extern printf; 3 | printf("Hello world!\n"); 4 | } 5 | 6 | globint 4; 7 | globarr[] 1, 2, 3; -------------------------------------------------------------------------------- /fix_tab.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | 4 | 5 | # convert original asm listing and remove comments 6 | cat $1 | sed -r 's|/(.*)|/\*\1 */|g' | \ 7 | # convert the lookup table at the start to use .int directives 8 | sed -r 's/([0-9]+)\.;[[:blank:]]+([A-Za-z0-9]+)/.int \1, \2/g' | \ 9 | # replace .even directive with .balign, replace first row of the lookup table 10 | sed 's/\.even/.balign 4/g' | sed -r 's/_(eff|reg|sp|cc)tab=\.;[[:blank:]]*\.\+2/_\1tab=.;.int .+4/g' | \ 11 | # replace single `0` characters with .int directive 12 | sed -r 's/^([[:blank:]]+)0$/\1.int 0/g' 13 | 14 | # sed -r 's/_(eff|reg|sp|cc)tab=\.;[[:blank:]]*\.\+2/_\1tab=.int .,.+4/g' -------------------------------------------------------------------------------- /src/c0.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include "config.h" 3 | //#define DEBUG 4 | 5 | /* c00.c */ 6 | void init(char[], int); 7 | int *lookup(void); 8 | int symbol(void); 9 | int subseq(int, int, int); 10 | int getstr(void); 11 | int getcc(void); 12 | int mapch(int); 13 | int tree(void); 14 | void declare(int); 15 | 16 | /* c01.c */ 17 | void build(int); 18 | int *convert(int[], int, int, int); 19 | void chkw(int[]); 20 | int lintyp(int); 21 | void error(char[]); 22 | void error1(char[],int); 23 | void error2(char[],int,int); 24 | int *block(int, ...); 25 | void chklval(int[]); 26 | int max(int, int); 27 | 28 | /* c02.c */ 29 | void function(char[]); 30 | void extdef(void); 31 | void statement(int); 32 | int* pexpr(void); 33 | void pswitch(void); 34 | void blkhed(void); 35 | void blkend(void); 36 | void errflush(int); 37 | void declist(void); 38 | int easystmt(void); 39 | 40 | /* c03.c */ 41 | void jumpc(int[], int, int); 42 | void rcexpr(int[], int); 43 | void jump(int); 44 | void label(int); 45 | void retseq(void); 46 | void slabel(void); 47 | void setstk(int); 48 | void defvec(void); 49 | void defstat(int[]); 50 | 51 | int length(int); 52 | int rlength(int); 53 | void putwrd(int); 54 | void printn(int,int); 55 | void cc_printf(char[], ...); 56 | void cc_putchar(int); 57 | 58 | /* globals */ 59 | extern int ossiz; 60 | extern int ospace[]; 61 | extern const int regtab; 62 | extern const int efftab; 63 | extern const int cctab; 64 | extern const int sptab; 65 | extern int symbuf[]; 66 | extern int const pssiz; 67 | extern int const namsiz; 68 | extern int const nwps; 69 | extern int hshused; 70 | extern int const hshsiz; 71 | extern int const hshlen; 72 | extern int hshtab[]; 73 | extern int *space; 74 | extern int *cp; 75 | extern const int cmsiz; 76 | extern int cmst[]; 77 | extern int ctyp; 78 | extern int isn; 79 | extern const int swsiz; 80 | extern int swtab[]; 81 | extern int *swp; 82 | extern int contlab; 83 | extern int brklab; 84 | extern int deflab; 85 | extern const int nreg; 86 | extern int maprel[]; 87 | extern int stack; 88 | extern int peeksym; 89 | extern int peekc; 90 | extern int eof; 91 | extern int line; 92 | extern int *csym; 93 | extern int cval; 94 | extern const int ncpw; 95 | extern int nerror; 96 | extern FILE *fout; 97 | extern int *paraml; 98 | extern int *parame; 99 | extern tmpfil; 100 | 101 | /* code tables */ 102 | extern char ctab[]; 103 | extern int opdope[]; 104 | extern int cvtab[]; 105 | #define printf cc_printf 106 | #define putchar cc_putchar 107 | -------------------------------------------------------------------------------- /src/c00.c: -------------------------------------------------------------------------------- 1 | /* C compiler 2 | 3 | Copyright 1972 Bell Telephone Laboratories, Inc. 4 | 5 | */ 6 | 7 | #include "c0.h" 8 | #include 9 | 10 | ossiz = 250; 11 | int ospace[250]; /* fake */ 12 | 13 | /* 14 | * Adds the string s with id t to the hash table. 15 | */ 16 | void init(char *s, int t) { 17 | char *sp; 18 | int *np, i; 19 | 20 | /* copy s to symbuf */ 21 | i = namsiz; 22 | sp = symbuf; 23 | while(i--) 24 | if ((*sp++ = *s++)=='\0') --s; 25 | np = lookup(); 26 | *np++ = 1; 27 | *np = t; 28 | } 29 | 30 | /* 31 | * First pass of the C compiler. It parses the input and generates an intermediate(?) output, 32 | * containing parsed expression trees with some additional assembly code. 33 | * 34 | * Short overview: the compiler parses global elements, which can be either functions or 35 | * global variable declarations. In functions, each expression is parsed into a tree, which is stored 36 | * in ospace. Interestingly, the next pass of the compiler is expected to be loaded at the same location as this pass. 37 | * So, the child node pointers in the tree are simply saved directly in the output and are expected to be loaded 38 | * back at the same memory location. 39 | * 40 | * The tree parser also does a rough estimation of how many registers are needed for calculating a tree 41 | * using the Sethi-Ullman algorithm. Additionally, sides of a binary operation can be flipped such that 42 | * the more difficult subtree comes first. See the C compiler tour in the UNIX manual. 43 | */ 44 | main(int argc, char *argv[]) { 45 | if(argc<3) { 46 | error("Arg count"); 47 | exit(1); 48 | } 49 | if(freopen(argv[1], "r", stdin)==NULL) { 50 | error1("Can't find %s", argv[1]); 51 | exit(1); 52 | } 53 | if((fout=fopen(argv[2], "w"))==NULL) { 54 | error1("Can't create %s", argv[2]); 55 | exit(1); 56 | } 57 | // fout = stdout; 58 | 59 | init("int", 0); 60 | init("char", 1); 61 | init("float", 2); 62 | init("double", 3); 63 | /* init("long", 4); */ 64 | init("auto", 5); 65 | init("extern", 6); 66 | init("static", 7); 67 | init("goto", 10); 68 | init("return", 11); 69 | init("if", 12); 70 | init("while", 13); 71 | init("else", 14); 72 | init("switch", 15); 73 | init("case", 16); 74 | init("break", 17); 75 | init("continue", 18); 76 | init("do", 19); 77 | init("default", 20); 78 | while(!eof) { 79 | extdef(); 80 | blkend(); 81 | } 82 | fflush(stdout); 83 | 84 | exit(nerror!=0); 85 | } 86 | 87 | /* 88 | * Looks up an element in the hash table. The key is in symbuf. 89 | * Returns a pointer to the 4 word long data section. 90 | * Following these 4 words, another 4 words contain the key. 91 | */ 92 | int *lookup() { 93 | int i, j, *np, *sp, *rp; 94 | 95 | i = 0; 96 | sp = symbuf; 97 | j = nwps; 98 | while(j--) 99 | i += *sp++; 100 | if (i<0) i = -i; 101 | i %= hshsiz; /* the hash of symbuf */ 102 | 103 | i *= pssiz; 104 | while(*(np = &hshtab[i+4])) { 105 | sp = symbuf; 106 | j = nwps; 107 | while(j--) 108 | if (*np++ != *sp++) goto no; /* key does not match, go to next one */ 109 | return(&hshtab[i]); 110 | no: if ((i += pssiz) >= hshlen) i = 0; 111 | } 112 | 113 | /* not found, add new element */ 114 | if(hshused++ > hshsiz) { 115 | error("Symbol table overflow"); 116 | exit(1); 117 | } 118 | rp = np = &hshtab[i]; 119 | sp = symbuf; 120 | j = 4; 121 | while(j--) /* clear out data */ 122 | *np++ = 0; 123 | j = nwps; 124 | while(j--) /* copy key into &hshtab[i+4] */ 125 | *np++ = *sp++; 126 | return(rp); 127 | } 128 | 129 | /* 130 | * The lexer, returns the opcode of the next symbol. If the caller does not want to use the symbol, 131 | * it can "push it back" using the peeksym global variable. 132 | * 133 | * The return value is the opcode of the current symbol. See c0t.c for the mapping between 134 | * the symbols and numbers. 135 | * If the current symbol is a number/character literal, the cval variable is set to the numeric value. 136 | * If the current symbol is a string, cval contains its label. 137 | * If the current symbol is a keyword, cval contains its id. 138 | * If the current symbol is a name, csym will point to the corresponding entry in the hashtable. 139 | * See csym comments at the bottom for its contents. 140 | */ 141 | int symbol() { 142 | int b, c; 143 | char *sp; 144 | 145 | if (peeksym>=0) { /* if we have a peeked symbol, return that */ 146 | c = peeksym; 147 | peeksym = -1; 148 | return(c); 149 | } 150 | if (peekc) { /* use peeked character, if has one */ 151 | c = peekc; 152 | peekc = 0; 153 | } else 154 | if (eof) 155 | return(0); else 156 | c = getchar(); 157 | loop: 158 | switch(ctab[c]) { 159 | 160 | case 125: /* newline */ 161 | line++; 162 | 163 | case 126: /* white space */ 164 | c = getchar(); 165 | goto loop; 166 | 167 | case 0: /* EOF */ 168 | eof++; 169 | return(0); 170 | 171 | case 40: /* + */ 172 | return(subseq(c,40,30)); 173 | 174 | case 41: /* - */ 175 | return(subseq(c,41,31)); 176 | 177 | case 80: /* = */ 178 | if (subseq(' ',0,1)) return(80); 179 | c = symbol(); 180 | if (c>=40 & c<=49) /* c is binary operator */ 181 | return(c+30); 182 | if (c==80) /* = */ 183 | return(60); 184 | peeksym = c; 185 | return(80); 186 | 187 | case 63: /* < */ 188 | if (subseq(c,0,1)) return(46); 189 | return(subseq('=',63,62)); 190 | 191 | case 65: /* > */ 192 | if (subseq(c,0,1)) return(45); 193 | return(subseq('=',65,64)); 194 | 195 | case 34: /* ! */ 196 | return(subseq('=',34,61)); 197 | 198 | case 43: /* / */ 199 | if (subseq('*',1,0)) 200 | return(43); 201 | com: 202 | /* inside a comment */ 203 | c = getchar(); 204 | com1: 205 | if (c=='\0') { 206 | eof++; 207 | error("Nonterminated comment"); 208 | return(0); 209 | } 210 | if (c=='\n') 211 | line++; 212 | if (c!='*') 213 | goto com; 214 | c = getchar(); 215 | if (c!='/') 216 | goto com1; 217 | c = getchar(); 218 | goto loop; 219 | 220 | case 124: /* number */ 221 | cval = 0; 222 | if (c=='0') 223 | b = 8; else 224 | b = 10; 225 | while(ctab[c]==124) { 226 | cval = cval*b + c -'0'; 227 | c = getchar(); 228 | } 229 | peekc = c; 230 | return(21); 231 | 232 | case 122: /* " */ 233 | return(getstr()); 234 | 235 | case 121: /* ' */ 236 | return(getcc()); 237 | 238 | case 123: /* letter */ 239 | sp = symbuf; 240 | while(ctab[c]==123 | ctab[c]==124) { /* while c is alphanumeric */ 241 | if (sp<((char *)symbuf)+namsiz) *sp++ = c; 242 | c = getchar(); 243 | } 244 | while(sp<((char *)symbuf)+namsiz) 245 | *sp++ = '\0'; 246 | peekc = c; 247 | csym = lookup(); /* find in hashtable */ 248 | if (csym[0]==1) { /* keyword */ 249 | cval = csym[1]; 250 | return(19); 251 | } 252 | return(20); 253 | 254 | case 127: /* unknown */ 255 | error("Unknown character"); 256 | c = getchar(); 257 | goto loop; 258 | 259 | } 260 | return(ctab[c]); 261 | } 262 | 263 | /* 264 | * Peeks at the next char and if it is c then eats it and returns b, otherwise returns a. 265 | * Useful for two character symbols, e.g. to distinguish between ! and != 266 | * call subseq('=', note_equal_code, logical_not_code). 267 | */ 268 | int subseq(int c, int a, int b) { 269 | if (!peekc) 270 | peekc = getchar(); 271 | if (peekc != c) 272 | return(a); 273 | peekc = 0; 274 | return(b); 275 | } 276 | 277 | /* 278 | * Gets a string. It assumes the opening quotation mark has been already processed. 279 | */ 280 | int getstr() { 281 | int c; 282 | 283 | printf(".data;l%d:.byte ", cval=isn++); 284 | while((c=mapch('"')) >= 0) 285 | printf("%d,", c); 286 | printf("0;.balign 4;.text\n"); 287 | return(22); 288 | } 289 | 290 | /* 291 | * Reads a character literal. Assumes opening ' has been read already. 292 | */ 293 | int getcc() 294 | { 295 | int c, cc; 296 | char *cp; 297 | 298 | cval = 0; 299 | cp = &cval; 300 | cc = 0; 301 | while((c=mapch('\'')) >= 0) 302 | if(cc++ < ncpw) 303 | *cp++ = c; 304 | if(cc>ncpw) 305 | error("Long character constant"); 306 | return(21); 307 | } 308 | 309 | 310 | /* 311 | * Processes a character from a string/character literal. c contains the delimiter char. 312 | * This function handles mapping of escape sequences. 313 | */ 314 | int mapch(int c) 315 | { 316 | int a; 317 | 318 | if((a=getchar())==c) 319 | return(-1); 320 | switch(a) { 321 | 322 | case '\n': 323 | case 0: 324 | error("Nonterminated string"); 325 | peekc = a; 326 | return(-1); 327 | 328 | case '\\': 329 | switch (a=getchar()) { 330 | 331 | case 't': 332 | return('\t'); 333 | 334 | case 'n': 335 | return('\n'); 336 | 337 | case '0': 338 | return('\0'); 339 | 340 | case 'r': 341 | return('\r'); 342 | 343 | case '\n': 344 | line++; 345 | return('\n'); 346 | } 347 | 348 | } 349 | return(a); 350 | } 351 | 352 | /* 353 | * Builds an expression tree. The outline of the algorithm: 354 | * There are three stacks: 355 | * cmst - tree node stack, contains the partially built parts of the expression tree. 356 | * opst - operator stack, contains the ids of the operators. The bottom element is the EOF operator 357 | * prst - precedence stack, contains the precedences of operators. Note that the precedence stack only contains 358 | * element, if the precedence has increased, so it is not in one-to-one correspondence with opst. 359 | * 360 | * The algorithm goes over the operator produced by the symbol function. Leaf nodes (numbers, 361 | * string/char literals, names) are placed on the node stack. If an operator is encountered, 362 | * it is placed on the operator stack if its precedence is higher than the current precedence. 363 | * Otherwise, the operator and tree node stack is unwinded by building partial subtrees, 364 | * until the top of the prst is smaller than current operator's precedence. 365 | */ 366 | int tree() { 367 | int *op, opst[20], *pp, prst[20], andflg, o, 368 | p, ps, os; 369 | 370 | space = ospace; 371 | op = opst; /* top of operator stack */ 372 | pp = prst; /* top of precedence stack */ 373 | cp = cmst; /* top of tree node stack */ 374 | *op = 200; /* stack EOF */ 375 | *pp = 06; 376 | andflg = 0; 377 | 378 | advanc: 379 | switch (o=symbol()) { 380 | 381 | /* name */ 382 | case 20: 383 | if (*csym==0) /* storage not yet decided */ 384 | if((peeksym=symbol())==6) /* (, mark function calls as extern */ 385 | *csym = 6; /* extern */ 386 | else { 387 | if(csym[2]==0) /* unseen so far */ 388 | csym[2] = isn++; 389 | } 390 | if(*csym==6) /* extern */ 391 | *cp++ = block(5,20,csym[1],0,*csym, 392 | csym[4],csym[5],csym[6],csym[7]); 393 | else 394 | *cp++ = block(2,20,csym[1],0,*csym,csym[2]); 395 | goto tand; 396 | 397 | /* short constant */ 398 | case 21: 399 | case21: 400 | *cp++ = block(1,21,ctyp,0,cval); /* ctyp is always 0 */ 401 | goto tand; 402 | 403 | /* string constant */ 404 | case 22: 405 | *cp++ = block(1,22,17,0,cval); /* 17 is char[] */ 406 | 407 | tand: 408 | if(cp>=cmst+cmsiz) { 409 | error("Expression overflow"); 410 | exit(1); 411 | } 412 | if (andflg) 413 | goto syntax; 414 | andflg = 1; 415 | goto advanc; 416 | 417 | /* ++, -- */ 418 | case 30: 419 | case 31: 420 | if (andflg) /* convert to postfix */ 421 | o += 2; 422 | goto oponst; 423 | 424 | /* ! */ 425 | case 34: 426 | if (andflg) 427 | goto syntax; 428 | goto oponst; 429 | 430 | /* - */ 431 | case 41: 432 | if (!andflg) { 433 | peeksym = symbol(); 434 | if (peeksym==21) { /* negative literal */ 435 | peeksym = -1; 436 | cval = -cval; 437 | goto case21; 438 | } 439 | o = 37; 440 | } 441 | andflg = 0; 442 | goto oponst; 443 | 444 | /* & */ 445 | /* * */ 446 | case 47: 447 | case 42: 448 | if (andflg) 449 | andflg = 0; else 450 | if(o==47) 451 | o = 35; 452 | else 453 | o = 36; 454 | goto oponst; 455 | 456 | /* ( */ 457 | case 6: 458 | if (andflg) { 459 | /* this is a function call */ 460 | o = symbol(); 461 | if (o==7) /* ) */ 462 | o = 101; else { /* 101 - call without args */ 463 | peeksym = o; 464 | o = 100; 465 | andflg = 0; 466 | } 467 | } 468 | goto oponst; 469 | 470 | /* ) */ 471 | /* ] */ 472 | case 5: 473 | case 7: 474 | if (!andflg) 475 | goto syntax; 476 | goto oponst; 477 | } 478 | 479 | /* binary operators */ 480 | if (!andflg) 481 | goto syntax; 482 | andflg = 0; 483 | 484 | oponst: /* place operator on stack */ 485 | p = (opdope[o]>>9) & 077; /* extract operator precedence */ 486 | opon1: 487 | ps = *pp; /* currently highest precedence */ 488 | if (p>ps | p==ps & (opdope[o]&0200)!=0) { /* right-assoc */ 489 | putin: 490 | switch (o) { 491 | 492 | case 6: /* ( */ 493 | case 4: /* [ */ 494 | case 100: /* call */ 495 | p = 04; 496 | } 497 | if(op>=opst+20) { /* 20 is the size of opstack */ 498 | error("expression overflow"); 499 | exit(1); 500 | } 501 | *++op = o; 502 | *++pp = p; 503 | goto advanc; 504 | } 505 | --pp; /* pop precedence stack */ 506 | switch (os = *op--) { 507 | 508 | /* EOF */ 509 | case 200: 510 | peeksym = o; 511 | return(*--cp); 512 | 513 | /* call */ 514 | case 100: 515 | if (o!=7) /* unmatching parenthesis */ 516 | goto syntax; 517 | build(os); 518 | goto advanc; 519 | 520 | /* mcall */ 521 | case 101: 522 | *cp++ = 0; /* 0 arg call */ 523 | os = 100; 524 | goto fbuild; 525 | 526 | /* ( */ 527 | case 6: 528 | if (o!=7) /* unmatching parenthesis */ 529 | goto syntax; 530 | goto advanc; 531 | 532 | /* [ */ 533 | case 4: 534 | if (o!=5) 535 | goto syntax; 536 | build(4); 537 | goto advanc; 538 | } 539 | fbuild: 540 | build(os); 541 | goto opon1; /* unwinds precedence stack till at the same level as o */ 542 | 543 | syntax: 544 | error("Expression syntax"); 545 | errflush(o); 546 | return(0); 547 | } 548 | 549 | /* 550 | * Processes a variable declaration, the preceding type/storage keyword has been processed already. 551 | * kw - the id of the preceding type/storage keyword, 8 for function parameter list. 552 | */ 553 | void declare(int kw) { 554 | int o; 555 | 556 | while((o=symbol())==20) { /* name */ 557 | if(kw>=5) { /* type or storage location keyword? */ 558 | if(*csym>0) 559 | error1("%p redeclared", &csym[4]); /* storage area redeclared */ 560 | *csym = kw; 561 | } else { 562 | if ((csym[1]&017)!=0) /* type already defined, adding pointer behavior is allowed */ 563 | error1("%p redeclared", &csym[4]); 564 | csym[1] |= csym[1]&0760 | kw; // set kw to lower 4 bits 565 | if (*csym==0) 566 | *csym = -2; 567 | } 568 | /* add pointer indirection */ 569 | while((o=symbol())==4) { /* [ */ 570 | if((o=symbol())==21) { /* const */ 571 | if(csym[1]>=020) 572 | error("Bad vector"); 573 | csym[3] = cval; 574 | o = symbol(); 575 | } 576 | if (o!=5) /* ] */ 577 | goto syntax; 578 | csym[1] += 020; 579 | } 580 | if(kw==8) { /* parameter */ 581 | *csym = -1; 582 | if (paraml==0) /* paraml points to the first element in the parameter list */ 583 | paraml = csym; 584 | else 585 | *parame = csym; /* set previous parameter's first word to point to the current parameter */ 586 | parame = csym; 587 | } 588 | if (o!=9) /* , */ 589 | break; 590 | } 591 | if(o==1 & kw!=8 | o==7 & kw==8) /* not parameter list and ; or parameter list and ) */ 592 | return; 593 | syntax: 594 | error("Declaration syntax"); 595 | errflush(o); 596 | } 597 | 598 | /* constants for code generator tables */ 599 | const int regtab = 0; 600 | const int efftab = 1; 601 | const int cctab = 2; 602 | const int sptab = 3; 603 | 604 | /* hash table */ 605 | int symbuf[2]; /* buffer for the key to look up in has table. 8 byte long, should be 8/sizeof(int); original value was 4 */ 606 | const int pssiz = 8; /* size of an entry in the hashtable in words, should be 4 + nwps */ 607 | const int namsiz = 8; /* maximum length of a (variable) name */ 608 | const int nwps = 2; /* number of words per symbuf - originally 4 */ 609 | int hshused = 0; /* number of elements in the hash table */ 610 | const int hshsiz = 100; /* maximum number of elements in the table */ 611 | const int hshlen = 800; /* size of the table in word, equals to pssiz*hshsiz */ 612 | int hshtab[800]; /* The hash table for symbols. For eahc entry, the first 4 bytes are the data, the next 4 bytes are the key. */ 613 | 614 | int *space= 0; 615 | int *cp= 0; /* top of the cmst stack */ 616 | const int cmsiz = 40; /* size of the cmst stack */ 617 | int cmst[40]; /* the tree node stack, contains pointers to the nodes */ 618 | int ctyp = 0; /* id of the int type, constant */ 619 | int isn = 1; /* current label number */ 620 | const int swsiz = 120; 621 | int swtab[120]; 622 | int *swp = 0; 623 | int contlab = 0; /* label for a continue statement in the current loop */ 624 | int brklab = 0; /* label for a break statement in the current loop */ 625 | int deflab = 0; /* label for the default statement in the current switch */ 626 | const int nreg = 4; /* number of general registers available */ 627 | int maprel[]={ 60,61,64,65,62,63,68,69,66,67}; /* maps binary relations to the their flipped pairs */ 628 | int stack = 0; 629 | int peeksym = -1; /* peeked symbol */ 630 | int peekc = 0; /* peeked character */ 631 | int eof = 0; /* true if reached end of file */ 632 | int line = 1; /* current line */ 633 | int *csym = 0; /* current symbol, see meaning below */ 634 | int cval = 0; /* contains the currently read character literal, int literal, label for string literal */ 635 | const int ncpw = 4; /* number of characters per word */ 636 | int nerror = 0; /* number of errors during parsing */ 637 | FILE *fout; /* putchar prints characters to this file */ 638 | int *paraml; /* head of the parameter list */ 639 | int *parame; /* last element in the parameter list */ 640 | 641 | 642 | /* 643 | * csym - current symbol description, points to the corresponding element in the hash table. 644 | * Meaning of the 4 words 645 | * 0 - if 1 then keyword, otherwise storage scope (keyword ID), 8 for function parameters 646 | * -1 (temporary) for function parameters csym[0] forms a linked list, -1 marks the end 647 | * -2 default storage scope (auto) 648 | * 1 - keyword 649 | * 2 - label 650 | * 5 - auto 651 | * 6 - extern 652 | * 7 - static 653 | * 10 - function parameter (set by blkhed) 654 | * 1 - type description 655 | * lower 4 bits contain raw type (char/double/int) 656 | * then 020 is added for every indirection 657 | * e.g. 020 refers to int[] 658 | * 2 - location/label 659 | * in case of parameters/auto the offset from the stack frame 660 | * in case of statics, the label of the variable 661 | * 3 - the length in case of arrays, 0 otherwise 662 | * 4 - the name of the symbol 663 | * 664 | * cval - value in the current symbol 665 | * if number literal - the number 666 | * if char literal - character ascii code 667 | * if keyword - the keyword ID 668 | * if string - the label in the assembly output 669 | */ 670 | -------------------------------------------------------------------------------- /src/c01.c: -------------------------------------------------------------------------------- 1 | #include "c0.h" 2 | #include 3 | #include 4 | 5 | /* 6 | * Builds a new node of the operator tree and pushes it onto the cmst stack. 7 | * The necessary parameters are popped from cmst. 8 | */ 9 | void build(int op) { 10 | int *p1, t1, d1, *p2, t2, d2, t; 11 | int d, dope, lr, cvn; 12 | 13 | /* replace a[b] with *(a+b) */ 14 | if (op==4) { /* [] */ 15 | build(40); /* + */ 16 | op = 36; 17 | } 18 | dope = opdope[op]; 19 | if ((dope&01)!=0) { /* binary */ 20 | p2 = *--cp; /* second subtree */ 21 | if(p2 != 0) { /* if op was mcall originally, there is a fake 0 null pointer here, ignore it */ 22 | t2 = p2[1]; 23 | d2 = p2[2]; 24 | } 25 | } 26 | p1 = *--cp; /* first subtree */ 27 | t1 = p1[1]; 28 | d1 = p1[2]; 29 | switch (op) { 30 | 31 | /* , */ 32 | case 9: 33 | *cp++ = block(2, 9, 0, 0, p1, p2); 34 | return; 35 | 36 | /* ? */ 37 | case 90: 38 | if (*p2!=8) 39 | error("Illegal conditional"); 40 | goto goon; 41 | 42 | /* call */ 43 | case 100: 44 | *cp++ = block(2,100,t1,24,p1,p2); 45 | return; 46 | 47 | /* * */ 48 | case 36: 49 | if ((t1 -= 16)<0) { 50 | error("Illegal indirection"); 51 | t1 += 16; 52 | } 53 | if (*p1!=20 & d1==0) 54 | d1 = 1; 55 | *cp++ = block(1,36,t1,d1,p1); 56 | return; 57 | 58 | /* & unary */ 59 | case 35: 60 | if (*p1 == 36) { /* * - shorten &*p to p */ 61 | *cp++ = p1[3]; 62 | return; 63 | } 64 | if (*p1 == 20) { /* name */ 65 | *cp++ = block(1,p1[3]==5?29:35,t1+16,1,p1); /* is it auto? */ 66 | return; 67 | } 68 | error("Illegal lvalue"); 69 | } 70 | goon: 71 | if ((dope&02)!=0) /* lvalue needed on left? */ 72 | chklval(p1); 73 | if ((dope&020)!=0) /* word operand on left? */ 74 | chkw(p1); 75 | if ((dope&040)!=0) /* word operand on right? */ 76 | chkw(p2); 77 | if ((dope&01)!=0) { /* binary op? */ 78 | cvn = cvtab[9*lintyp(t1)+lintyp(t2)]; /* conversion from t1 to t2 ?? */ 79 | if ((dope&010)!=0) { /* assignment? */ 80 | t = t1; 81 | lr = 1; /* right argument must be converted */ 82 | cvn &= 07; 83 | } else { 84 | t = (cvn&0100)!=0? t2:t1; /* who determines the result type */ 85 | lr = cvn&0200; 86 | cvn = (cvn>>3)&07; 87 | } 88 | if (cvn) { 89 | if (cvn==07) { 90 | error("Illegal conversion"); 91 | goto nocv; 92 | } 93 | cvn += (dope&010)!=0? 83:93; /* assignment? */ 94 | if (lr) { /* right argument needs to be converted */ 95 | t2 = t; 96 | d2 = (p2=convert(p2, t, d2, cvn))[2]; /* this also emits the conversion operation */ 97 | } else { 98 | t1 = t; 99 | d1 = (p1=convert(p1, t, d1, cvn))[2]; 100 | } 101 | nocv:; } 102 | if (d2>d1 && (dope&0100)!=0) { /* flip operands, if second tree is more difficult */ 103 | if ((dope&04)!=0) /* relational? */ 104 | op = maprel[op-60]; 105 | d = d1; 106 | d1 = d2; 107 | d2 = d; 108 | d = p1; 109 | p1 = p2; 110 | p2 = d; 111 | d = t1; 112 | t1 = t2; 113 | t2 = d; 114 | } 115 | if (d1==d2) /* calculating registers needed for this node using Sethi-Ullman */ 116 | d = d1+1; else 117 | d = max(d1,d2); 118 | if ((dope&04)!=0) 119 | t = 0; /* relational ops have integer type */ 120 | *cp++ = block(2,op,t,d,p1,p2); 121 | return; 122 | } 123 | *cp++ = block(1,op,t1,d1==0?1:d1,p1); /* unary operator */ 124 | } 125 | 126 | /* 127 | * Creates a node for type conversion. This operation can be in place, 128 | * i.e. modifies an existing node in the tree. 129 | * t - new type 130 | * d - current difficulty 131 | * cvn - conversion opcode 132 | */ 133 | int *convert(int *p, int t, int d, int cvn) { 134 | int c; 135 | if (*p==21) { /* constant */ 136 | c = p[3]; /* the current value of the constant */ 137 | switch(cvn) { 138 | 139 | case 99: /* c18, int -> double[] */ 140 | c <<= 1; 141 | 142 | case 98: /* c14, int -> float[] */ 143 | case 97: /* c12, int -> int[] */ 144 | c <<= 2; 145 | 146 | p[3] = c; 147 | return(p); 148 | } 149 | } 150 | return(block(1, cvn, t, max(1,d), p)); 151 | } 152 | 153 | /* check if p is a word type */ 154 | void chkw(int *p) { 155 | int t; 156 | 157 | if ((t=p[1])>1 && t<16) 158 | error("Integer operand required"); 159 | } 160 | 161 | /* Index of type in cvtable */ 162 | int lintyp(int t) { 163 | return(t<16? t:(t<32? t-12: 8)); 164 | } 165 | 166 | 167 | void error(char *s) { 168 | error2(s, 0, 0); 169 | } 170 | 171 | void error1(char *s, int p1) { 172 | error2(s, p1, 0); 173 | } 174 | 175 | void error2(char *s, int p1, int p2) { 176 | FILE *f; 177 | 178 | nerror++; 179 | fflush(fout); 180 | f = fout; 181 | fout = stderr; 182 | printf("%d: ", line); 183 | printf(s, p1, p2); 184 | putchar('\n'); 185 | fflush(stderr); 186 | fout = f; 187 | } 188 | 189 | /* 190 | * Creates a new node and appends it to the end of *ospace. The parameters of the node 191 | * are passed after the argument n, which contains the number of optional parameters. 192 | * Each node has 3 mandatory parameters and any number of optional ones. The mandatory parameters: 193 | * op - operator id 194 | * t - type 195 | * d - difficulty, number of registers to calculate the node, or statement difficulty level in c1 196 | * These are followed by the (op dependent) optional parameters, which usually are the subtrees. 197 | */ 198 | int *block(int n, ...) 199 | { 200 | auto *p; 201 | va_list arguments; 202 | 203 | #ifdef DEBUG 204 | va_list dbg_args; 205 | va_start(dbg_args, n); 206 | int op = va_arg(dbg_args, int); 207 | int type = va_arg(dbg_args, int); 208 | int regcnt = va_arg(dbg_args, int); 209 | printf("loc %d: %d t=%d d=%d nump=%d ", space-ospace, op, type, regcnt, n); 210 | for (int i = 0; i < n; ++i) { 211 | int d = va_arg(dbg_args, int); 212 | printf("%d (%d) ", d, (int*)d-ospace); 213 | } 214 | printf("\n"); 215 | va_end(dbg_args); 216 | #endif 217 | 218 | p = space; 219 | va_start(arguments, n); 220 | n += 3; 221 | if(space+n >= ospace+ossiz) { 222 | error("Expression overflow"); 223 | exit(1); 224 | } 225 | while(n--) 226 | *space++ = va_arg(arguments, int); 227 | 228 | va_end(arguments); 229 | return(p); 230 | } 231 | 232 | /* check if p is an lvalue (name or pointer) */ 233 | void chklval(p) 234 | int p[]; { 235 | if (*p!=20) 236 | if (*p!=36) 237 | error("Lvalue required"); 238 | } 239 | 240 | int max(a, b) 241 | { 242 | if (a>b) 243 | return(a); 244 | return(b); 245 | } 246 | 247 | -------------------------------------------------------------------------------- /src/c02.c: -------------------------------------------------------------------------------- 1 | #include "c0.h" 2 | 3 | /* 4 | * Parses a function, the function name and the opening parenthesis of the 5 | * argument list has already been read. name contains the name of the function. 6 | */ 7 | void function(char *name) { 8 | printf( ".text; %p:\n", name); 9 | 10 | printf("push\t%ebp\nmov\t%esp, %ebp\n"); /* set up stack frame */ 11 | declare(8); /* read parameter list */ 12 | declist(); /* type declarations of parameters */ 13 | 14 | statement(1); 15 | retseq(); 16 | } 17 | 18 | /* Parses the next function/global variable definition. */ 19 | void extdef() { 20 | int o, c, *cs; 21 | char *s; 22 | 23 | if(((o=symbol())==0) || o==1) /* EOF */ 24 | return; 25 | if(o!=20) /* not a name -> syntax error */ 26 | goto syntax; 27 | csym[0] = 6; 28 | cs = &csym[4]; // name of the symbol 29 | printf(".globl %p\n", cs); 30 | s = ".data; %p:.int 1f\n"; 31 | switch(o=symbol()) { 32 | 33 | case 6: /* ( - function definition*/ 34 | function(cs); 35 | return; 36 | 37 | case 21: /* const - variable has default value*/ 38 | printf(".data; %p: .int %d\n", cs, cval); 39 | if((o=symbol())!=1) /* ; */ 40 | goto syntax; 41 | return; 42 | 43 | case 1: /* ; */ 44 | printf(".bss\n %p: .=.+4\n", cs); /* unitialized variable */ 45 | return; 46 | 47 | case 4: /* [ */ 48 | c = 0; 49 | if((o=symbol())==21) { /* const */ 50 | c = cval<<2; /* multiply by two (number of bytes per word), should be changed for 32bit systems */ 51 | o = symbol(); 52 | } 53 | if(o!=5) /* ] */ 54 | goto syntax; 55 | printf(s, cs); 56 | if((o=symbol())==1) { /* ; */ 57 | printf(".bss; 1:.=.+%d\n", c); 58 | return; 59 | } 60 | /* symbol list, e.g.: 61 | arrname[] 23, 43 ,5; */ 62 | printf("1: .int "); 63 | while(o==21) { /* const */ 64 | printf("%d", cval); 65 | c -= 4; 66 | if((o=symbol())==1) { /* ; */ 67 | printf("\n"); 68 | goto done; 69 | } 70 | if(o!=9) /* , */ 71 | goto syntax; 72 | else { 73 | printf(", "); 74 | o = symbol(); 75 | } 76 | } 77 | goto syntax; 78 | done: 79 | if(c>0) 80 | printf(".=.+%d\n", c); 81 | return; 82 | 83 | case 0: /* EOF */ 84 | return; 85 | } 86 | 87 | syntax: 88 | error("External definition syntax"); 89 | errflush(o); 90 | statement(0); 91 | } 92 | 93 | /* 94 | * Parses (a block of) statements. 95 | * d - true if this is a start of a function block 96 | */ 97 | void statement(int d) { 98 | int o, o1, o2, o3, *np; 99 | 100 | stmt: 101 | switch(o=symbol()) { 102 | 103 | /* EOF */ 104 | case 0: 105 | error("Unexpected EOF"); 106 | /* ; */ 107 | case 1: 108 | /* } */ 109 | case 3: 110 | return; 111 | 112 | /* { */ 113 | case 2: { 114 | if(d) 115 | blkhed(); /* process definitions at the start of the function */ 116 | /* recursively process this block of code */ 117 | while (!eof) { 118 | if ((o=symbol())==3) /* } */ 119 | goto bend; 120 | peeksym = o; 121 | statement(0); 122 | } 123 | error("Missing '}'"); 124 | bend: 125 | return; 126 | } 127 | 128 | /* keyword */ 129 | case 19: 130 | switch(cval) { 131 | 132 | /* goto */ 133 | case 10: 134 | o1 = block(1,102,0,0,tree()); 135 | rcexpr(o1, regtab); 136 | goto semi; 137 | 138 | /* return */ 139 | case 11: 140 | if((peeksym=symbol())==6) /* ( */ 141 | rcexpr(pexpr(), regtab); 142 | retseq(); 143 | goto semi; 144 | 145 | /* if */ 146 | case 12: 147 | jumpc(pexpr(), o1=isn++, 0); 148 | statement(0); 149 | if ((o=symbol())==19 & cval==14) { /* else */ 150 | o2 = isn++; 151 | jump(o2); 152 | label(o1); 153 | statement(0); 154 | label(o2); 155 | return; 156 | } 157 | peeksym = o; 158 | label(o1); 159 | return; 160 | 161 | /* while */ 162 | case 13: 163 | o1 = contlab; 164 | o2 = brklab; 165 | label(contlab = isn++); 166 | jumpc(pexpr(), brklab=isn++, 0); 167 | o3 = easystmt(); 168 | statement(0); 169 | jump(contlab); 170 | label(brklab); 171 | contlab = o1; 172 | brklab = o2; 173 | return; 174 | 175 | /* break */ 176 | case 17: 177 | if(brklab==0) 178 | error("Nothing to break from"); 179 | jump(brklab); 180 | goto semi; 181 | 182 | /* continue */ 183 | case 18: 184 | if(contlab==0) 185 | error("Nothing to continue"); 186 | jump(contlab); 187 | goto semi; 188 | 189 | /* do */ 190 | case 19: 191 | o1 = contlab; 192 | o2 = brklab; 193 | contlab = isn++; 194 | brklab = isn++; 195 | label(o3 = isn++); 196 | statement(0); 197 | label(contlab); 198 | contlab = o1; 199 | if ((o=symbol())==19 & cval==13) { /* while */ 200 | jumpc(tree(), o3, 1); 201 | label(brklab); 202 | brklab = o2; 203 | goto semi; 204 | } 205 | goto syntax; 206 | 207 | /* case */ 208 | case 16: 209 | if ((o=symbol())!=21) /* constant */ 210 | goto syntax; 211 | if ((o=symbol())!=8) /* : */ 212 | goto syntax; 213 | if (swp==0) { 214 | error("Case not in switch"); 215 | goto stmt; 216 | } 217 | if(swp>=swtab+swsiz) { 218 | error("Switch table overflow"); 219 | } else { 220 | *swp++ = isn; /* add value and label to switch table */ 221 | *swp++ = cval; 222 | label(isn++); 223 | } 224 | goto stmt; 225 | 226 | /* switch */ 227 | case 15: 228 | o1 = brklab; 229 | brklab = isn++; 230 | np = pexpr(); 231 | if (np[1]>1 & np[1]<16) 232 | error("Integer required"); 233 | rcexpr(np, regtab); 234 | pswitch(); 235 | brklab = o1; 236 | return; 237 | 238 | /* default */ 239 | case 20: 240 | if (swp==0) 241 | error("Default not in switch"); 242 | if ((o=symbol())!=8) /* : */ 243 | goto syntax; 244 | deflab = isn++; 245 | label(deflab); 246 | goto stmt; 247 | } 248 | 249 | error("Unknown keyword"); 250 | goto syntax; 251 | 252 | /* name */ 253 | case 20: 254 | if (peekc==':') { /* label */ 255 | peekc = 0; 256 | if (csym[0]>0) { 257 | error("Redefinition"); 258 | goto stmt; 259 | } 260 | csym[0] = 2; 261 | csym[1] = 020; /* int[] */ 262 | if (csym[2]==0) 263 | csym[2] = isn++; 264 | slabel(); 265 | goto stmt; 266 | } 267 | } 268 | 269 | peeksym = o; 270 | rcexpr(tree(), efftab); 271 | goto semi; 272 | 273 | semi: 274 | if ((o=symbol())!=1) /* ; */ 275 | goto syntax; 276 | return; 277 | 278 | syntax: 279 | error("Statement syntax"); 280 | errflush(o); 281 | goto stmt; 282 | } 283 | 284 | /* 285 | * Parses an expression enclosed in parenthesis. 286 | * Returns the address to the parsed tree. 287 | */ 288 | int* pexpr() 289 | { 290 | int o, t; 291 | 292 | if ((o=symbol())!=6) /* ( */ 293 | goto syntax; 294 | t = tree(); 295 | if ((o=symbol())!=7) /* ) */ 296 | goto syntax; 297 | return(t); 298 | syntax: 299 | error("Statement syntax"); 300 | errflush(o); 301 | return(0); 302 | } 303 | 304 | /* Parses the contents of a switch block. */ 305 | void pswitch() { 306 | int *sswp, dl, cv, swlab; /* holder for the previous switch table, label of previous default label, iterator, switch table label */ 307 | 308 | sswp = swp; /* save swp */ 309 | if (swp==0) 310 | swp = swtab; 311 | swlab = isn++; 312 | printf("mov\t$l%d, %ebx\njmp bswitch\n", swlab); 313 | dl = deflab; /* save deflab */ 314 | deflab = 0; 315 | statement(0); 316 | if (!deflab) { 317 | deflab = isn++; 318 | label(deflab); 319 | } 320 | /* generate switch table */ 321 | printf("l%d:.data;l%d:", brklab, swlab); 322 | while(swp>sswp & swp>swtab) { 323 | cv = *--swp; 324 | printf(".int %d, l%d\n", cv, *--swp); /* prints condition, label to code */ 325 | } 326 | printf(".int l%d, 0\n.text\n", deflab); 327 | deflab = dl; 328 | swp = sswp; 329 | } 330 | 331 | /* 332 | * Function block head: processes variable definitions. 333 | */ 334 | void blkhed() 335 | { 336 | int al, pl, *cs, hl; 337 | 338 | declist(); 339 | stack = al = -4; /* sizeof(int*), offset of the first automatic local variable from the stack frame */ 340 | pl = 2*4; /* 2*sizeof(int*), offset of the first parameter from the stack frame */ 341 | while(paraml) { 342 | *parame = 0; /* set the end of linked list to 0 (originally -1), will break the loop */ 343 | paraml = *(cs = paraml); /* next element in list */ 344 | cs[2] = pl; /* location relative to stack frame */ 345 | *cs = 10; 346 | pl += rlength(cs[1]); 347 | } 348 | cs = hshtab; 349 | hl = hshsiz; 350 | while(hl--) { /* go through symbol table, i.e. all defined names */ 351 | if (cs[4]) 352 | switch(cs[0]) { /* if defined */ 353 | 354 | /* sort unmentioned */ 355 | case -2: 356 | cs[0] = 5; /* auto */ 357 | 358 | /* auto */ 359 | case 5: 360 | if (cs[3]) { /* array */ 361 | // al -= (cs[3]*length(cs[1]-020)+1) & 077776; /* push array on stack, round up to even */ 362 | al -= (cs[3]*length(cs[1]-020)+1) & (~1); /* push array on stack TODO shouldn't this be 4?? */ 363 | setstk(al); 364 | defvec(); 365 | } 366 | cs[2] = al; 367 | al -= rlength(cs[1]); 368 | goto loop; 369 | 370 | /* parameter */ 371 | case 10: 372 | cs[0] = 5; 373 | goto loop; 374 | 375 | /* static */ 376 | case 7: 377 | cs[2] = isn++; 378 | defstat(cs); 379 | goto loop; 380 | 381 | loop:; 382 | } 383 | cs = cs+pssiz; 384 | } 385 | setstk(al); 386 | } 387 | 388 | /* 389 | * Clears all elements from the symbol table, 390 | * except keywords. 391 | */ 392 | void blkend() { 393 | int i, hl; 394 | 395 | i = 0; 396 | hl = hshsiz; 397 | while(hl--) { /* iterate over table backwards */ 398 | if(hshtab[i+4]) /* if defined */ 399 | if (hshtab[i]==0) 400 | error1("%p undefined", &hshtab[i+4]); 401 | if(hshtab[i]!=1) { /* not keyword */ 402 | hshused--; 403 | hshtab[i+4] = 0; 404 | } 405 | i += pssiz; 406 | } 407 | } 408 | 409 | /* Throw away symbols until end of statement. */ 410 | void errflush(int o) { 411 | while(o>3) /* ; { } */ 412 | o = symbol(); 413 | peeksym = o; 414 | } 415 | 416 | /* 417 | * Variable declarations. Either function parameter type declaration 418 | * or function local variable declarations. 419 | */ 420 | void declist() 421 | { 422 | int o; 423 | 424 | while((o=symbol())==19 & cval<10) /* cval<10 means it is a type/storage area definition (int/char/extern/static) */ 425 | declare(cval); 426 | peeksym = o; 427 | } 428 | 429 | /* 430 | * Detects whether the next statement is expected to be small - i.e. not a compound statement 431 | * This usually means it is a single statement or conditional. 432 | * e.g. goto, break, or not a label or block */ 433 | int easystmt() 434 | { 435 | if((peeksym=symbol())==20) /* name */ 436 | return(peekc!=':'); /* not label */ 437 | if (peeksym==19) { /* keyword */ 438 | switch(cval) 439 | 440 | case 10: /* goto */ 441 | case 11: /* return */ 442 | case 17: /* break */ 443 | case 18: /* continue */ 444 | return(1); 445 | return(0); 446 | } 447 | return(peeksym!=2); /* { */ 448 | } 449 | 450 | 451 | -------------------------------------------------------------------------------- /src/c03.c: -------------------------------------------------------------------------------- 1 | #include "c0.h" 2 | #include 3 | /* 4 | * Records a conditional jump. If the jump is short (easystmt is true), 5 | * it generates a branch isntruction, otherwise a jump instruction. 6 | * 7 | * tree - tree containing a conditional expression 8 | * lbl - where to jump 9 | * cond - decides whether to jump when condition is true or false 10 | */ 11 | void jumpc(int *tree, int lbl, int cond) 12 | { 13 | rcexpr(block(1,103,tree,lbl,cond), cctab); 14 | } 15 | 16 | /* 17 | * Prints the binary representation of the tree. 18 | * table - the expression translation table used in the next pass. 19 | */ 20 | void rcexpr(int *tree, int table) 21 | { 22 | int c, *sp; 23 | 24 | putchar('#'); 25 | c = space-ospace; 26 | sp = ospace; 27 | 28 | putwrd(ospace); /* save start of array location (original code expects it to be loaded at the same place */ 29 | putwrd(c); 30 | putwrd(tree); 31 | putwrd(table); 32 | putwrd(line); 33 | while(c--) 34 | putwrd(*sp++); 35 | #ifdef DEBUG 36 | printf("\n"); 37 | #endif 38 | } 39 | 40 | void jump(int lab) { 41 | printf("jmp\tl%d\n", lab); 42 | } 43 | 44 | void label(int l) { 45 | printf("l%d:", l); 46 | } 47 | 48 | /* Generates code for a return statement. */ 49 | void retseq() { 50 | printf("leave\nret\n"); 51 | } 52 | 53 | /* Label for a static variable */ 54 | void slabel() { 55 | printf(".data; l%d: .int 1f; .text; 1:\n", csym[2]); 56 | } 57 | 58 | /* 59 | * Reserves space on the stack. 60 | * a - amount of bytes to add to the stack 61 | */ 62 | void setstk(int a) { 63 | int ts; 64 | 65 | ts = a-stack; /* relative distance */ 66 | stack = a; 67 | switch(ts) { 68 | 69 | case 0: 70 | return; 71 | 72 | // case -2: /* -2 */ 73 | // printf("tst -(sp)\n"); 74 | // return; 75 | // 76 | // case -4: /* -4 */ 77 | // printf("cmp -(sp),-(sp)\n"); 78 | // return; 79 | } 80 | printf("add $%d,%esp\n", ts); 81 | } 82 | 83 | /* define array on stack, simply saves the pointer to the top of the stack */ 84 | void defvec() { 85 | printf("push\t%esp\n"); 86 | stack -= 4; /* word size */ 87 | } 88 | 89 | /* 90 | * Define static variable. 91 | * s - pointer to symbol table entry 92 | */ 93 | void defstat(int *s) { 94 | int len; 95 | 96 | len = length(s[1]); 97 | if (s[3]) /* array */ 98 | printf(".data; l%d:1f; .bss; 1:.=.+%d; .balign 4; .text\n", s[2], 99 | s[3]*len); 100 | else /* scalar */ 101 | printf(".bss\n l%d:.=.+%d; .balign 4; .text\n", s[2], len); 102 | } 103 | 104 | /* 105 | * Length of the datatype, t is the type descriptor. 106 | * The id of the type is the id of the keyword + 020 for every indirection. 107 | */ 108 | int length(int t) { 109 | 110 | if (t<0) 111 | t += 020; 112 | if (t>=020) /* array/pointer */ 113 | return(4); 114 | switch(t) { 115 | 116 | case 0: /* int */ 117 | return(4); 118 | 119 | case 1: /* char */ 120 | return(1); 121 | 122 | case 2: /* float */ 123 | return(4); 124 | 125 | case 3: /* double */ 126 | return(8); 127 | 128 | case 4: /* ??? */ 129 | return(4); 130 | 131 | } 132 | return(1024); 133 | } 134 | 135 | /* rounded length */ 136 | int rlength(int c) { 137 | int l; 138 | 139 | return((l=length(c))==1? 4: l); 140 | } 141 | 142 | 143 | /* prints the number n in base b */ 144 | void printn(int n, int b) { 145 | int a; 146 | 147 | if(a=n/b) /* assignment, not test for equality */ 148 | printn(a, b); /* recursive */ 149 | putchar(n%b + '0'); 150 | } 151 | 152 | void putwrd(int a) { 153 | printf("%d;", a); 154 | } 155 | 156 | void cc_putchar(int c) 157 | { 158 | putc(c, fout); 159 | } 160 | 161 | void cc_printf(char *fmt, ...) 162 | { 163 | static char *s; 164 | auto *adx, x, c, *i; 165 | va_list arguments; 166 | 167 | va_start(arguments, fmt); 168 | loop: 169 | while((c = *fmt++) != '%') { 170 | if(c == '\0') { 171 | va_end(arguments); 172 | return; 173 | } 174 | putchar(c); 175 | } 176 | switch (c = *fmt++) { 177 | 178 | case 'd': /* decimal */ 179 | case 'o': /* octal */ 180 | x = va_arg(arguments, int); 181 | if(x < 0) { 182 | x = -x; 183 | if(x<0) { /* - infinity */ 184 | if(c=='o') 185 | printf("100000"); 186 | else 187 | printf("-32767"); 188 | goto loop; 189 | } 190 | putchar('-'); 191 | } 192 | printn(x, c=='o' ? 8 : 10); 193 | goto loop; 194 | 195 | case 's': /* string */ 196 | x = va_arg(arguments, int); 197 | s = x; 198 | while(c = *s++) { 199 | putchar(c); 200 | } 201 | goto loop; 202 | 203 | case 'p': 204 | s = va_arg(arguments, int*); 205 | #ifdef WIN32 206 | putchar('_'); 207 | #endif 208 | c = namsiz; 209 | while(c--) 210 | if(*s) 211 | putchar(*s++); 212 | goto loop; 213 | } 214 | putchar('%'); 215 | fmt--; 216 | goto loop; 217 | } 218 | 219 | -------------------------------------------------------------------------------- /src/c0t.c: -------------------------------------------------------------------------------- 1 | #include "c0.h" 2 | 3 | // Converts ascii characters to symbols 4 | // 127 means unknown character, 123 are letters, 124 digits 5 | char ctab[]={ 0, 127, 127, 127, 127, 127, 127, 127, /* 0 - 7 */ 6 | 127, 126, 125, 127, 127, 126, 127, 127, /* 8 - 15 */ 7 | 127, 127, 127, 127, 127, 127, 127, 127, /* 16 - 23 */ 8 | 127, 127, 127, 127, 127, 127, 127, 127, /* 24 - 31 */ 9 | 126, 34, 122, 127, 127, 44, 47, 121, /* 32 - 39 */ 10 | 6, 7, 42, 40, 9, 41, 127, 43, /* 40 - 47 */ 11 | 124, 124, 124, 124, 124, 124, 124, 124, /* 48 - 55 */ 12 | 124, 124, 8, 1, 63, 80, 65, 90, /* 56 - 63 */ 13 | 127, 123, 123, 123, 123, 123, 123, 123, /* 64 - 72 */ 14 | 123, 123, 123, 123, 123, 123, 123, 123, 15 | 123, 123, 123, 123, 123, 123, 123, 123, 16 | 123, 123, 123, 4, 127, 5, 49, 127, 17 | 127, 123, 123, 123, 123, 123, 123, 123, 18 | 123, 123, 123, 123, 123, 123, 123, 123, 19 | 123, 123, 123, 123, 123, 123, 123, 123, 20 | 123, 123, 123, 2, 48, 3, 127, 127}; 21 | 22 | 23 | int opdope[] ={ 24 | 000000, // EOF 25 | 000000, // ; 26 | 000000, // { 27 | 000000, // } 28 | 036000, // [ 29 | 002000, // ] 30 | 036000, // ( 31 | 002000, // ) 32 | 014201, // : 33 | 007001, // , 34 | 000000, // 10 35 | 000000, // 11 36 | 000000, // 12 37 | 000000, // 13 38 | 000000, // 14 39 | 000000, // 15 40 | 000000, // 16 41 | 000000, // 17 42 | 000000, // 18 43 | 000000, // 19 44 | 000000, // name 45 | 000000, // short constant 46 | 000000, // string 47 | 000000, // float 48 | 000000, // double 49 | 000000, // 25 50 | 000000, // 26 51 | 000000, // 27 52 | 000000, // 28 53 | 000000, // 29 54 | 034202, // ++pre 55 | 034202, // --pre 56 | 034202, // ++post 57 | 034202, // --post 58 | 034220, // !un 59 | 034202, // &un 60 | 034220, // *un 61 | 034200, // -un 62 | 034220, // ~un 63 | 000000, // 39 64 | 030101, // + 65 | 030001, // - 66 | 032101, // * 67 | 032001, // // 68 | 032001, // % 69 | 026061, // >> 70 | 026061, // << 71 | 020161, // & 72 | 016161, // | 73 | 016161, // ^ 74 | 000000, // 50 75 | 000000, // 51 76 | 000000, // 52 77 | 000000, // 53 78 | 000000, // 54 79 | 000000, // 55 80 | 000000, // 56 81 | 000000, // 57 82 | 000000, // 58 83 | 000000, // 59 84 | 022105, // == 85 | 022105, // != 86 | 024105, // <= 87 | 024105, // < 88 | 024105, // >= 89 | 024105, // > 90 | 024105, //

p 93 | 024105, // >=p 94 | 012213, // =+ 95 | 012213, // =- 96 | 012213, // =* 97 | 012213, // =// 98 | 012213, // =% 99 | 012253, // =>> 100 | 012253, // =<< 101 | 012253, // =& 102 | 012253, // =| 103 | 012253, // =^ 104 | 012213, // = 105 | 000000, // 81 106 | 000000, // 82 107 | 000000, // 83 108 | 000000, // int -> float (for assignment operator) 109 | 000000, // int -> double 110 | 000000, // float -> int 111 | 000000, // float -> double 112 | 000000, // double -> int 113 | 000000, // double -> float 114 | 014201, // ? 115 | 000000, // 91 116 | 000000, // 92 117 | 000000, // 93 118 | 000000, // int -> float 119 | 000000, // int -> double 120 | 000000, // float -> double 121 | 000000, // int -> int[] 122 | 000000, // int -> float[] 123 | 000000, // int -> double[] 124 | 036001, // call 125 | 036001, // mcall 126 | }; 127 | 128 | /* descriptor of covnersions. a:b means first argument has type t, second has type b */ 129 | int cvtab[] ={ 130 | 0000, // i:i 131 | 0000, // i:c 132 | 0113, // i:f 133 | 0125, // i:d 134 | 0140, // i:i[] 135 | 0100, // i:c[] 136 | 0150, // i:f[] 137 | 0160, // i:d[] 138 | 0140, // i:[][] 139 | 140 | 0100, // c:i 141 | 0100, // c:c 142 | 0113, // c:f 143 | 0125, // c:d 144 | 0140, // c:i[] 145 | 0100, // c:c[] 146 | 0150, // c:f[] 147 | 0160, // c:d[] 148 | 0140, // c[][] 149 | 150 | 0211, // f:i 151 | 0211, // f:c 152 | 0000, // f:f 153 | 0136, // f:d 154 | 0211, // f:i[] 155 | 0211, // f:c[] 156 | 0211, // f:f[] 157 | 0211, // f:d[] 158 | 0211, // f:[][] 159 | 160 | 0222, // d:i 161 | 0222, // d:c 162 | 0234, // d:f 163 | 0000, // d:d 164 | 0222, // d:i[] 165 | 0222, // d:c[] 166 | 0222, // d:f[] 167 | 0222, // d:d[] 168 | 0222, // d:[][] 169 | 170 | 0240, // i[]:i 171 | 0240, // i[]:c 172 | 0113, // i[]:f 173 | 0125, // i[]:d 174 | 0000, // i[]:i[] 175 | 0000, // i[]:c[] 176 | 0100, // i[]:f[] 177 | 0100, // i[]:d[] 178 | 0100, // i[]:[][] 179 | 180 | 0000, // c[]:i 181 | 0000, // c[]:c 182 | 0113, // c[]:f 183 | 0125, // c[]:d 184 | 0200, // c[]:i[] 185 | 0000, // c[]:c[] 186 | 0200, // c[]:f[] 187 | 0200, // c[]:d[] 188 | 0200, // c[]:[][] 189 | 190 | 0250, // f[]:i 191 | 0250, // f[]:c 192 | 0113, // f[]:f 193 | 0125, // f[]:d 194 | 0000, // f[]:i[] 195 | 0000, // f[]:c[] 196 | 0000, // f[]:f[] 197 | 0100, // f[]:d[] 198 | 0000, // f[]:[][] 199 | 200 | 0260, // d[]:i 201 | 0260, // d[]:c 202 | 0113, // d[]:f 203 | 0125, // d[]:d 204 | 0000, // d[]:i[] 205 | 0000, // d[]:c[] 206 | 0000, // d[]:f[] 207 | 0000, // d[]:d[] 208 | 0000, // d[]:[][] 209 | 210 | 0240, // [][]:i 211 | 0240, // [][]:c 212 | 0113, // [][]:f 213 | 0125, // [][]:d 214 | 0000, // [][]:i[] 215 | 0000, // [][]:c[] 216 | 0100, // [][]:f[] 217 | 0100, // [][]:d[] 218 | 0000, // [][]:[][] 219 | }; -------------------------------------------------------------------------------- /src/c1.h: -------------------------------------------------------------------------------- 1 | #ifndef LEGACY_CC_C1_H 2 | #define LEGACY_CC_C1_H 3 | 4 | #include 5 | #include 6 | #include "config.h" 7 | 8 | /* c10.c */ 9 | char *match(int*, int*, int); 10 | void rcexpr(int*, int*, int); 11 | int cexpr(int*, int*, int); 12 | void pname(int *); 13 | int dcalc(int *, int); 14 | int notcompat(int,int ); 15 | void prins(int, int); 16 | void printreg(int); 17 | void printlreg(int); 18 | int collcon(int*); 19 | int isfloat(int *, char *s[]); 20 | 21 | /* c11.c */ 22 | void cbranch(int[], int, int, int); 23 | void branch(int,int,int); 24 | void jump(int); 25 | void label(int); 26 | void popstk(int); 27 | int length(int); 28 | int rlength(int); 29 | int getwrd(); 30 | void printn(int,int); 31 | void cc_printf(char*,...); 32 | void cc_putchar(int); 33 | void error(char[]); 34 | void error1(char[],int); 35 | void error2(char[],int,int); 36 | 37 | int *fixp(int*); 38 | 39 | /* Globals */ 40 | extern int *regtab; 41 | extern int *efftab; 42 | extern int *cctab; 43 | extern int *sptab; 44 | 45 | extern int opdope[]; 46 | extern int ospace[]; 47 | extern int *baseptr; 48 | extern const int nreg; 49 | extern int isn; 50 | extern const int namsiz; 51 | extern FILE* fout; 52 | extern int line; 53 | extern int tmpfil; 54 | extern int nerror; 55 | extern int fltmod; 56 | 57 | extern int instabcode[]; 58 | extern char *instabstr[]; 59 | 60 | #define printf cc_printf 61 | #define putchar cc_putchar 62 | 63 | #endif //LEGACY_CC_C1_H 64 | -------------------------------------------------------------------------------- /src/c10.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | C compiler, part 2 4 | 5 | Copyright 1972 Bell Telephone Laboratories, Inc. 6 | 7 | */ 8 | #include "c1.h" 9 | #include 10 | 11 | int ospace[1000]; /* fake */ 12 | 13 | /* 14 | * Second pass of the compiler. The code was expected to be loaded at the same location as the first pass, 15 | * such that ospace is at the same location as in the first pass. Because of this, pointers in the 16 | * expression trees were saved using the absolute address. The fixp function converts the incorrect addresses 17 | * to ones pointing into this pass' ospace. Throughout this code, unfixed pointer means the fixp function 18 | * hasn't been called for the pointer yet. 19 | * 20 | * For details of the algorithm, see the "A Tour through the UNIX C Compiler" in the UNIX v7 manual. 21 | * Though it is for a newer version of C, almost everything is applicable to this compiler. 22 | * The difficulty levels used in this compiler: 23 | * z - 4 - zero 24 | * c - 8 - number 25 | * i - 12 - name/string/float/double, pointer address(&) 26 | * a - 16 - addressible by PDP11 address instructions 27 | * e - 20 - easy statement, value can be calculated using the available registers only 28 | * n - 63 - anything 29 | */ 30 | int main(int argc, char *argv[]) 31 | { 32 | int *sp, c, *table, *tabtab[4], tree; 33 | 34 | if (argc<3) { 35 | error("Arg count"); 36 | exit(1); 37 | } 38 | if(freopen(argv[1], "r", stdin)==NULL) { 39 | error1("Can't find %s", argv[1]); 40 | exit(1); 41 | } 42 | if((fout=fopen(argv[2], "wb"))==NULL) { 43 | error1("Can't create %s", argv[2]); 44 | exit(1); 45 | } 46 | printf(".include \"" __DIR__ "/pdp11_mov.s\"\n"); 47 | 48 | tabtab[0] = regtab; 49 | tabtab[1] = efftab; 50 | tabtab[2] = cctab; 51 | tabtab[3] = sptab; 52 | while((c=getchar())>0) { 53 | if(c=='#') { /* expression */ 54 | sp = ospace; 55 | baseptr=getwrd(); 56 | c = getwrd(); 57 | tree = getwrd(); 58 | table = tabtab[getwrd()]; 59 | line = getwrd(); 60 | while(c--) 61 | *sp++ = getwrd(); 62 | rcexpr(tree, table, 0); 63 | } else 64 | putchar(c); 65 | } 66 | 67 | exit(nerror!=0); 68 | } 69 | 70 | /* 71 | * Finds a code generation template in the generation table. 72 | * Returns a pointer to the template string. 73 | * 74 | * tree is an unfixed pointer 75 | * nreg - number of available registers 76 | */ 77 | char *match(int *tree, int *table, int nreg) 78 | { 79 | int op, d1, d2, t1, t2, *p1, *p2; 80 | char *mp; 81 | 82 | /* t1/t2 - type of the result of subtree, d1/d2 - difficulty of the subtree */ 83 | 84 | if (tree==0) 85 | return(0); 86 | 87 | tree = fixp(tree); 88 | op = *tree; 89 | if (op>=29) /* if not leaf */ 90 | p1 = fixp(tree[3]); 91 | else 92 | p1 = tree; 93 | t1 = p1[1]; 94 | d1 = dcalc(p1, nreg); 95 | if ((opdope[op]&01)!=0) { /* binary? */ 96 | if(tree[4]!=0) { /* in function calls second argument is empty at this point */ 97 | p2 = fixp(tree[4]); 98 | t2 = p2[1]; 99 | d2 = dcalc(p2, nreg); 100 | } else { 101 | p2 = 0; 102 | } 103 | } 104 | 105 | /* Look up the entries for this operator */ 106 | while(*table) { 107 | if (*table++ == op) goto foundop; 108 | table++; 109 | } 110 | return(0); 111 | foundop: 112 | table = *table; 113 | nxtry: 114 | /* Iterate over the list of templates for this op */ 115 | mp = table; 116 | if (*mp == 0) 117 | return(0); 118 | if (d1 > (*mp&077) | (*mp>=0100)&(*p1!=36)) /* tree1 has a difficulty level <= than this condition, or this is a pointer */ 119 | goto notyet; 120 | if (notcompat(t1, mp[1])) 121 | goto notyet; 122 | if ((opdope[op]&01)!=0 & p2!=0) { /* binary op, check second argument */ 123 | if (d2 > (mp[2]&077) | (mp[2]>=0100)&(*p2!=36)) 124 | goto notyet; 125 | if (notcompat(t2,mp[3])) 126 | goto notyet; 127 | } 128 | now: 129 | return(table[1]); /* parameters are 4bytes = 1 word */ 130 | notyet: 131 | table = table+2; /* jump to next entry in table (on entry is 4 bytes + 1 sizeof(int *) ) */ 132 | goto nxtry; 133 | } 134 | 135 | /* 136 | * Generates code for this expression. If the instruction does not have a matching entry 137 | * in one of the specialized code tables, it falls back to regtab and moves the result 138 | * to the appropriate place. 139 | * 140 | * tree is an unfixed pointer 141 | * reg - result should go into this register if table==regtab; 142 | * Additionally, the code generator should leave lower numbered registers alone, 143 | * and only use reg or higher numbered registers. 144 | */ 145 | void rcexpr(int *tree, int *table, int reg) 146 | { 147 | int *origtree; 148 | 149 | if(tree==0) 150 | return; 151 | 152 | origtree = tree; 153 | tree = fixp(tree); 154 | 155 | if(*tree >= 103) { /* conditional jump */ 156 | cbranch(tree[1],tree[2],tree[3],0); 157 | return; 158 | } 159 | 160 | if (cexpr(origtree, table, reg)) 161 | return; 162 | 163 | if (table!=regtab) { 164 | if (cexpr(origtree, regtab, reg)) { 165 | if (table == sptab) { 166 | printf("push\t"); 167 | printreg(reg); 168 | putchar('\n'); 169 | } 170 | if (table == cctab) { 171 | printf("test "); 172 | printreg(reg); 173 | putchar(','); 174 | printreg(reg); 175 | putchar('\n'); 176 | } 177 | return; 178 | } 179 | } 180 | error1("No match for op %d", *tree); 181 | } 182 | 183 | /* 184 | * Generate code using the given table. If a template was found 185 | * and the code successfully generated then returns 1, otherwise 0. 186 | * 187 | * tree is an unfixed pointer 188 | * reg - result should go into this register if table==regtab; 189 | * Additionally, the code generator should leave lower numbered registers alone, 190 | * and only use reg or higher numbered registers. 191 | */ 192 | int cexpr(int *tree, int *table, int reg) { 193 | int *p1, *fp1, *p2, *fp2, c, r, *p, *otable, *ctable, *origtree; 194 | char *string; 195 | 196 | origtree = tree; 197 | tree = fixp(tree); 198 | 199 | if ((c = *tree)==100) { /* function call, push params on stack */ 200 | p1 = tree[3]; 201 | p2 = tree[4]; 202 | fp2 = fixp(p2); 203 | r = 0; 204 | if(p2) { 205 | while (*fp2==9) { /* comma */ 206 | rcexpr(fp2[4], sptab, 0); 207 | r += rlength(fixp(p=fp2[4])[1]); 208 | p2 = fp2[3]; 209 | fp2 = fixp(p2); 210 | } 211 | rcexpr(p2, sptab, 0); 212 | r += rlength(fp2[1]); 213 | } 214 | *tree = 101; 215 | tree[2] = r; /* save arg length */ 216 | } 217 | if(c==90) { /* ? */ 218 | cbranch(tree[3], c=isn++, 0, reg); 219 | rcexpr(fixp(tree[4])[3], table, reg); 220 | branch(r=isn++, 0, 0); 221 | label(c); 222 | rcexpr(fixp(tree[4])[4], table, reg); 223 | label(r); 224 | return(1); 225 | } 226 | if ((string=match(origtree, table, nreg-reg))==0) /* find code template */ 227 | return(0); 228 | p1 = tree[3]; 229 | p2 = tree[4]; 230 | fp1 = fixp(p1); 231 | fp2 = fixp(p2); 232 | loop: 233 | switch(c = *string++) { 234 | 235 | case '\0': 236 | p = tree; 237 | if (*p==101 & p[2]>0) { /* if this was a function call, pop parameters from stack. */ 238 | popstk(p[2]); 239 | } 240 | return(1); 241 | 242 | /* A1 */ 243 | case 'A': 244 | p = fixp(tree[3]); 245 | goto adr; 246 | 247 | /* A2 */ 248 | case 'B': 249 | p = fixp(tree[4]); 250 | goto adr; 251 | 252 | /* A */ 253 | case 'O': 254 | p = tree; 255 | adr: 256 | pname(p); 257 | goto loop; 258 | 259 | /* I */ 260 | case 'M': 261 | if ((c = *string)=='\'') 262 | string++; else 263 | c = 0; 264 | prins(*tree, c); 265 | goto loop; 266 | 267 | /* B1 */ 268 | case 'C': 269 | p = fixp(tree[3]); 270 | goto pbyte; 271 | 272 | /* BF */ 273 | case 'P': 274 | p = tree; 275 | goto pb1; 276 | 277 | /* B2 */ 278 | case 'D': 279 | p = fixp(tree[4]); 280 | pbyte: 281 | if (p[1]==1) /* char type? */ 282 | putchar('b'); 283 | else 284 | putchar('l'); 285 | pb1: 286 | if (isfloat(p, 0)) 287 | putchar('f'); 288 | goto loop; 289 | 290 | /* BE */ 291 | case 'L': 292 | if (fixp(tree[3])[1]==1 | fixp(tree[4])[1]==1) 293 | putchar('b'); 294 | else 295 | putchar('l'); 296 | goto loop; 297 | 298 | /* C1 */ 299 | case 'E': 300 | p = fp1[3]; 301 | goto constl; 302 | 303 | /* C2 */ 304 | case 'F': 305 | p = fp2[3]; 306 | constl: 307 | printf("%o", p); 308 | goto loop; 309 | 310 | /* F */ 311 | case 'G': 312 | p = p1; 313 | goto subtre; 314 | 315 | /* S */ 316 | case 'K': 317 | p = p2; 318 | goto subtre; 319 | 320 | /* H */ 321 | case 'H': 322 | p = origtree; 323 | 324 | subtre: 325 | ctable = regtab; 326 | r = reg; 327 | c = *string++ - 'A'; 328 | if ((c&02)!=0) /* should it go to stack? */ 329 | ctable = sptab; 330 | if ((c&04)!=0) /* is it a conditional expression? */ 331 | ctable = cctab; 332 | if((c&010)!=0) /* F1, S1, H1 - using the next register */ 333 | r = reg+1; 334 | if((c&01)!=0) 335 | if(*fixp(p)==36) { /* if this has the shape *(x+c), print tree for x only */ 336 | p = fixp(p)[3]; 337 | if(collcon(fixp(p)) & (ctable!=sptab)) 338 | p = fixp(p)[3]; 339 | } 340 | rcexpr(p, ctable, r); 341 | goto loop; 342 | 343 | /* R */ 344 | case 'I': 345 | r = reg; 346 | goto preg; 347 | 348 | /* R1 */ 349 | case 'J': 350 | r = reg+1; 351 | preg: 352 | printreg(r); 353 | goto loop; 354 | 355 | /* RL */ 356 | case '#': 357 | p = fp1[3]; 358 | goto nmbr; 359 | 360 | case '"': 361 | p = fp2[3]; 362 | goto nmbr; 363 | case '~': 364 | p = tree[3]; 365 | 366 | nmbr: 367 | p = fixp(p); 368 | if(collcon(p)) { /* If this has the form *(x+const), print const */ 369 | c = *p; 370 | if(r = fixp(p=p[4])[3]) 371 | printf("%d", c==40?r:-r); /* + or - ? */ 372 | } 373 | goto loop; 374 | 375 | case '?': 376 | /* if current register<=r, eat this line */ 377 | r=*string++; 378 | r-='0'; 379 | if(reg <= r) { 380 | while(*string++ != '\n'); 381 | } 382 | goto loop; 383 | /* M */ 384 | case 'N': 385 | if ((c=isfloat(tree, &string))==fltmod) 386 | goto loop; 387 | printf((fltmod=c)==2?"setf\n":"setd\n"); 388 | goto loop; 389 | 390 | /* Z */ 391 | case 'Z': 392 | printf("%d", fp1[4]); 393 | goto loop; 394 | 395 | } 396 | putchar(c); 397 | fflush(stdout); 398 | goto loop; 399 | } 400 | 401 | /* Prints the value/label/location of a tree node. p is a fixed pointer */ 402 | void pname(int *p) { 403 | 404 | loop: 405 | switch(*p) { 406 | 407 | case 21: /* const */ 408 | printf("$%d", p[3]); 409 | return; 410 | 411 | case 22: /* string */ 412 | printf("$l%d", p[3]); 413 | return; 414 | 415 | case 20: /* name */ 416 | switch(p[3]) { 417 | 418 | case 5: /* auto, param */ 419 | printf("%d(%ebp)", p[4]); 420 | return; 421 | 422 | /* extern */ 423 | case 6: 424 | printf("%p", &p[4]); 425 | return; 426 | 427 | } 428 | printf("l%d", p[4]); /* static */ 429 | return; 430 | 431 | case 35: /* & */ // TODO this should be removed probably 432 | putchar('$'); 433 | p = fixp(p[3]); 434 | goto loop; 435 | 436 | // case 36: /* * */ 437 | // putchar('*'); 438 | // p = fixp(p[3]); 439 | // goto loop; 440 | } 441 | error("pname called illegally"); 442 | } 443 | 444 | /* 445 | * Difficulty level calculation. 446 | * p points to a fixed optable entry. 447 | * nreg - number of free registers. 448 | */ 449 | int dcalc(int *p, int nreg) { 450 | int op, t; 451 | 452 | if (p==0) 453 | return(0); 454 | op = *p; 455 | switch (op) { 456 | 457 | case 20: /* name */ 458 | case 22: /* string */ 459 | case 23: /* float */ 460 | case 24: /* double */ 461 | return(12); 462 | 463 | case 21: /* short constant */ 464 | return(p[3]==0? 4:8); 465 | 466 | case 35: /* & */ 467 | return(12); 468 | 469 | // case 36: /* * */ 470 | // if ((op=dcalc(fixp(p[3]), nreg))<16) /* if argument of pointer is constant/simple name, this is PDP-11 addressible */ 471 | // return(16); 472 | } 473 | 474 | def: 475 | return(p[2]<=nreg? 20: 24); /* can this tree be calculated using nreg registers? */ 476 | } 477 | 478 | /* 479 | * Checks if the two type: at and st are not compatible 480 | * at - type in the tree 481 | * st - type in the code template table 482 | * */ 483 | int notcompat(int at, int st) { 484 | 485 | if (st==0) /* word, byte */ 486 | return(at>1 & at<16); /* can store char or int only */ 487 | if (st==1) /* word */ 488 | return(at>0 & at<16); /* can store int only */ 489 | st -= 2; 490 | if (st==2 & at==3) 491 | at = 2; 492 | return(st != at); 493 | } 494 | 495 | /* 496 | * Prints the instruction belonging to this opcode. c decides whether 497 | * the first or the second subinstruction should be printed. 498 | */ 499 | void prins(int op, int c) { 500 | int *insp; 501 | char **insstrp; 502 | char *s; 503 | 504 | insp = instabcode; 505 | insstrp = instabstr; 506 | while(*insp) { 507 | if (*insp == op) { 508 | if ((s = insstrp[c!=0])==NULL) 509 | goto err; 510 | printf("%s", s); 511 | return; 512 | } else { 513 | insp = insp + 1; 514 | insstrp +=2; 515 | } 516 | } 517 | err: 518 | error1("No match for op %d", op); 519 | } 520 | 521 | /* Prints register n */ 522 | void printreg(int n) { 523 | if(n>=4) { 524 | error1("Too large register id: %d", n); 525 | } 526 | 527 | printf("%e"); 528 | putchar('a' + n); 529 | putchar('x'); 530 | } 531 | 532 | 533 | /* True if p is in 'x+const' form */ 534 | int collcon(int *p) { 535 | 536 | if(*p==40 | *p==41) 537 | if(*fixp(p[4])==21) 538 | return(1); 539 | return(0); 540 | } 541 | 542 | /* t - fixed pointer into ospace */ 543 | int isfloat(int *t, char *s[]) 544 | { 545 | int rt; 546 | 547 | if(s!= 0) { 548 | rt = **s - '0'; 549 | if (rt==2 | rt==4) { 550 | (*s)++; 551 | return(rt>2?3:2); 552 | } 553 | } 554 | if ((opdope[t[0]]&010)!=0) /* relational */ 555 | t = fixp(t[3]); 556 | if ((rt=t[1])>=2 && rt<=3) /* type is float or double */ 557 | return(rt); 558 | return(0); 559 | } 560 | 561 | int *baseptr=0; 562 | const int nreg = 4; /* number of available registers */ 563 | int isn = 10000; 564 | const int namsiz = 8; /* max length of a name */ 565 | FILE* fout; 566 | int line; 567 | int tmpfil; 568 | int nerror; 569 | int fltmod; 570 | 571 | -------------------------------------------------------------------------------- /src/c11.c: -------------------------------------------------------------------------------- 1 | #include "c1.h" 2 | 3 | /* 4 | * Tree is an unfixed pointer to the conditional expression. 5 | * lbl - label to jump to 6 | * cond - 0: jump if condition is false, 1: jump if condition is true 7 | */ 8 | void cbranch(int *tree, int lbl, int cond, int reg) { 9 | int l1, *origtree; 10 | 11 | if (tree==0) 12 | return; 13 | 14 | origtree=tree; 15 | tree=fixp(tree); 16 | switch(*tree) { 17 | 18 | /* & */ 19 | case 47: 20 | if (cond) { 21 | cbranch(tree[3], l1=isn++, 0, reg); 22 | cbranch(tree[4], lbl, 1, reg); 23 | label(l1); 24 | } else { 25 | cbranch(tree[3], lbl, 0, reg); 26 | cbranch(tree[4], lbl, 0, reg); 27 | } 28 | return; 29 | 30 | /* | */ 31 | case 48: 32 | if (cond) { 33 | cbranch(tree[3], lbl, 1, reg); 34 | cbranch(tree[4], lbl, 1, reg); 35 | } else { 36 | cbranch(tree[3], l1=isn++, 1, reg); 37 | cbranch(tree[4], lbl, 0, reg); 38 | label(l1); 39 | } 40 | return; 41 | 42 | /* ! */ 43 | case 34: 44 | cbranch(tree[3], lbl, !cond, reg); 45 | return; 46 | } 47 | rcexpr(origtree, cctab, reg); 48 | branch(lbl, *tree, !cond); 49 | } 50 | 51 | 52 | void branch(int lbl, int op, int c) { 53 | if(op) { 54 | if((opdope[op]&04)==0) /* conditional jump? */ 55 | op = 61; 56 | 57 | printf("j"); /* instruction code of conditional jumps is the condition mnemonic */ 58 | prins(op, c); 59 | } else 60 | printf("jmp"); 61 | printf("\tl%d\n", lbl); 62 | } 63 | 64 | void jump(int lab) { 65 | printf("jmp\tl%d\n", lab); 66 | } 67 | 68 | void label(int l) { 69 | printf("l%d:", l); 70 | } 71 | 72 | /* Decreases the stack size, moving sp the required amounts. */ 73 | void popstk(int a) { 74 | 75 | switch(a) { 76 | 77 | case 0: 78 | return; 79 | 80 | // case 2: 81 | // printf("tst (sp)+\n"); 82 | // return; 83 | // 84 | // case 4: 85 | // printf("cmp (sp)+,(sp)+\n"); 86 | // return; 87 | } 88 | printf("add $%d,%esp\n", a); 89 | } 90 | 91 | int *fixp(int *p) { 92 | return (void*)p-(void*)baseptr+(void*)ospace; 93 | } 94 | 95 | int length(int t) { 96 | 97 | if (t<0) 98 | t += 020; 99 | if (t>=020) 100 | return(4); 101 | switch(t) { 102 | 103 | case 0: 104 | return(4); 105 | 106 | case 1: 107 | return(1); 108 | 109 | case 2: 110 | return(4); 111 | 112 | case 3: 113 | return(8); 114 | 115 | case 4: 116 | return(4); 117 | 118 | } 119 | return(1024); 120 | } 121 | 122 | /* rounded length */ 123 | int rlength(int c) { 124 | int l; 125 | 126 | return((l=length(c))==1? 4: l); 127 | } 128 | 129 | /* Get a number from the input file */ 130 | int getwrd() { 131 | int i; 132 | char c; 133 | 134 | scanf("%d", &i); 135 | c = getchar(); 136 | if(c!=';') { 137 | error1("Unknown char id: %d", (int) c); 138 | } 139 | 140 | return i; 141 | } 142 | 143 | void printn(int n, int base) { 144 | int a; 145 | 146 | if(a= n / base) /* assignment, not test for equality */ 147 | printn(a, base); /* recursive */ 148 | putchar(n % base + '0'); 149 | } 150 | 151 | void cc_putchar(int c) 152 | { 153 | putc(c, fout); 154 | fflush(fout); 155 | } 156 | 157 | void cc_printf(char *fmt, ...) 158 | { 159 | static char *s; 160 | auto *adx, x, c, *i; 161 | va_list arguments; 162 | 163 | va_start ( arguments, fmt); 164 | loop: 165 | while((c = *fmt++) != '%') { 166 | if(c == '\0') { 167 | va_end(arguments); 168 | fflush(stdout); 169 | return; 170 | } 171 | putchar(c); 172 | } 173 | switch (c = *fmt++) { 174 | 175 | case 'd': /* decimal */ 176 | case 'o': /* octal */ 177 | x = va_arg(arguments, int); 178 | if(x < 0) { 179 | x = -x; 180 | if(x<0) { /* - infinity */ 181 | if(c=='o') 182 | printf("100000"); 183 | else 184 | printf("-32767"); 185 | goto loop; 186 | } 187 | putchar('-'); 188 | } 189 | printn(x, c=='o'?8:10); 190 | goto loop; 191 | 192 | case 's': /* string */ 193 | x = va_arg(arguments, int); 194 | s=x; 195 | while(c = *s++) { 196 | putchar(c); 197 | } 198 | goto loop; 199 | 200 | case 'p': 201 | s =va_arg(arguments, int*); 202 | #ifdef WIN32 203 | putchar('_'); 204 | #endif 205 | c = namsiz; 206 | while(c--) 207 | if(*s) 208 | putchar(*s++); 209 | goto loop; 210 | } 211 | putchar('%'); 212 | fmt--; 213 | goto loop; 214 | } 215 | 216 | void error(char *s) { 217 | error2(s, 0, 0); 218 | } 219 | 220 | void error1(char *s, int p1) { 221 | error2(s, p1, 0); 222 | } 223 | 224 | 225 | void error2(char *s, int p1, int p2) { 226 | FILE *f; 227 | nerror++; 228 | fflush(fout); 229 | f = fout; 230 | fout = stderr; 231 | printf("%d: ", line); 232 | printf(s, p1, p2); 233 | putchar('\n'); 234 | fout = f; 235 | } 236 | 237 | -------------------------------------------------------------------------------- /src/c1t.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by veges on 2021. 03. 19.. 3 | // 4 | #include "c1.h" 5 | 6 | int instabcode[]={ 7 | 40, 8 | 70, 9 | 41, 10 | 71, 11 | 30, 12 | 31, 13 | 32, 14 | 33, 15 | 16 | 45, 17 | 46, 18 | 75, 19 | 76, 20 | 43, 21 | 44, 22 | 73, 23 | 74, 24 | 25 | 47, 26 | 48, 27 | 78, 28 | 29 | 60, 30 | 61, 31 | 62, 32 | 63, 33 | 64, 34 | 65, 35 | 66, 36 | 67, 37 | 68, 38 | 69, 39 | 0, 40 | }; 41 | 42 | char *instabstr[]= { 43 | "add", "add", // 1 44 | "add", "add", 45 | "sub", "sub", // 2 sub 46 | "sub", "sub", 47 | "inc", "add", // 3:inc 48 | "dec", "sub", //4dec 49 | "inc", "add", 50 | "dec", "sub", 51 | 52 | "shr", NULL, // 5:ac 53 | "shl", NULL, //"6:mov, 7:r4 54 | "shr", NULL, 55 | "shl", NULL, 56 | "%eax", NULL, // div 57 | "%edx", NULL, // mod 58 | "%eax", NULL, 59 | "%edx", NULL, 60 | 61 | "and", NULL, // & 62 | "or", NULL, // | 63 | "or", NULL, // =| 64 | 65 | "e", "ne", // == 66 | "ne", "e", // != 67 | "le", "g", // <= 68 | "l", "ge", // < 69 | "ge", "l", // >= 70 | "g", "le", // > 71 | "be", "a", // p 74 | "a", "be" // >=p 75 | }; 76 | 77 | int opdope[] = { 78 | 000000, // EOF 79 | 000000, // ; 80 | 000000, // { 81 | 000000, // } 82 | 036000, // [ 83 | 002000, // ] 84 | 036000, // ( 85 | 002000, // ) 86 | 002000, // : 87 | 007001, // , 88 | 000000, // 10 89 | 000000, // 11 90 | 000000, // 12 91 | 000000, // 13 92 | 000000, // 14 93 | 000000, // 15 94 | 000000, // 16 95 | 000000, // 17 96 | 000000, // 18 97 | 000000, // 19 98 | 000000, // name 99 | 000000, // short constant 100 | 000000, // string 101 | 000000, // float 102 | 000000, // double 103 | 000000, // 25 104 | 000000, // 26 105 | 000000, // 27 106 | 000000, // 28 107 | 000000, // 29 108 | 034002, // ++pre 109 | 034002, // --pre 110 | 034002, // ++post 111 | 034002, // --post 112 | 034020, // !un 113 | 034002, // &un 114 | 034020, // *un 115 | 034000, // -un 116 | 034020, // ~un 117 | 000000, // 39 118 | 030101, // + 119 | 030001, // - 120 | 032101, // * 121 | 032001, // / 122 | 032001, // % 123 | 026061, // >> 124 | 026061, // << 125 | 020161, // & 126 | 016161, // | 127 | 016161, // ^ 128 | 000000, // 50 129 | 000000, // 51 130 | 000000, // 52 131 | 000000, // 53 132 | 000000, // 54 133 | 000000, // 55 134 | 000000, // 56 135 | 000000, // 57 136 | 000000, // 58 137 | 000000, // 59 138 | 022105, // == 139 | 022105, // != 140 | 024105, // <= 141 | 024105, // < 142 | 024105, // >= 143 | 024105, // > 144 | 024105, //

p 147 | 024105, // >=p 148 | 012013, // =+ 149 | 012013, // =- 150 | 012013, // =* 151 | 012013, // =/ 152 | 012013, // =% 153 | 012053, // =>> 154 | 012053, // =<< 155 | 012053, // =& 156 | 012053, // =| 157 | 012053, // =^ 158 | 012013, // = 159 | 000000, // 81 160 | 000000, // 82 161 | 000000, // 83 162 | 000000, // int -> float 163 | 000000, // int -> double 164 | 000000, // float -> int 165 | 000000, // float -> double 166 | 000000, // double -> int 167 | 000000, // double -> float 168 | 014001, // ? 169 | 000000, // 91 170 | 000000, // 92 171 | 000000, // 93 172 | 000000, // int -> float 173 | 000000, // int -> double 174 | 000000, // float -> double 175 | 000000, // int -> int[] 176 | 000000, // int -> float[] 177 | 000000, // int -> double[] 178 | 036001, // call 179 | 036001 // mcall - call without arguments 180 | }; -------------------------------------------------------------------------------- /src/cctab.s: -------------------------------------------------------------------------------- 1 | /* c code tables-- set condition codes */ 2 | 3 | .globl _cctab 4 | 5 | _cctab=.;.int .+4 6 | .int 30, rest 7 | .int 31, rest 8 | .int 37, rest 9 | .int 40, rest 10 | .int 41, rest 11 | .int 47, rest 12 | .int 48, rest 13 | .int 60, cc60 14 | .int 61, cc60 15 | .int 62, cc60 16 | .int 63, cc60 17 | .int 64, cc60 18 | .int 65, cc60 19 | .int 66, cc60 20 | .int 67, cc60 21 | .int 68, cc60 22 | .int 69, cc60 23 | .int 70, rest 24 | .int 71, rest 25 | .int 77, rest 26 | .int 78, rest 27 | .int 79, rest 28 | 29 | /* relationals */ 30 | cc60: 31 | /* this prevents using %aw,cw template, because x86 allows a single immediate only */ 32 | %c,c 33 | F 34 | cmp A2,R 35 | 36 | %aw,cw 37 | cmpl A2,A1 38 | 39 | %aw,a 40 | S 41 | cmp R,A1 42 | 43 | %nw*,aw 44 | F* 45 | cmpl A2,#1(R) 46 | 47 | %n,aw 48 | F 49 | cmp A2,R 50 | 51 | %nw*,e 52 | F* 53 | S1 54 | cmp R1,#1(R) 55 | 56 | %n,ew* 57 | F 58 | S1* 59 | cmp #2(R1),R 60 | 61 | %n,e 62 | F 63 | S1 64 | cmp R1,R 65 | 66 | %n,n 67 | FS 68 | S 69 | pop %edi 70 | cmp R,%edi 71 | 72 | /* these opcodes set the flags correctly, no need to call an extra test */ 73 | rest: 74 | %n,n 75 | H 76 | 77 | .data 78 | .balign 4 79 | .text 80 | 81 | -------------------------------------------------------------------------------- /src/config.h: -------------------------------------------------------------------------------- 1 | // Use V5 style ABI, instead of the original V2 one 2 | // the difference is how labels are pointing to functions 3 | #define UNIXV5_ABI -------------------------------------------------------------------------------- /src/cvopt.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define getc cc_getc 4 | getc(); 5 | flag(); 6 | 7 | peekc = 0; 8 | nofloat = 0; 9 | void main() { 10 | /* 11 | converts code generation template .s files by replacing % part using the rules below: 12 | A1 -> A 13 | A2 B 14 | A O 15 | B1 C 16 | B2 D 17 | BE L 18 | BF P 19 | C1 E 20 | C2 F 21 | F G 22 | H H 23 | R I 24 | R1 J 25 | RL Q 26 | S K 27 | I M 28 | M N 29 | 30 | * +1 31 | S +2 32 | C +4 33 | 1 +8 34 | 35 | z -> 4 36 | c 10 37 | a 14 38 | e 20 39 | n 63 40 | * +0100 41 | */ 42 | 43 | auto c,snlflg,nlflg,t,smode,m,ssmode,tempm; 44 | 45 | /* 46 | * ssmode: next non % should output a data segment header 47 | * tempm - in template mode: an upcoming '%' means a template definition and not a register 48 | */ 49 | 50 | smode = nlflg = snlflg = ssmode = 0; 51 | tempm = 1; 52 | loop: 53 | c = getc(); 54 | if(c!='%') tempm = 0; /* if newline, it will be set to 1 later anyway, otherwise leaving template mode */ 55 | if (c!='\n' & c!='\t') nlflg = 0; 56 | if (ssmode!=0 & c!='%') { 57 | ssmode = 0; 58 | printf(".data\n1: .ascii \""); 59 | } 60 | switch(c) { 61 | 62 | case '\0': 63 | printf(".text; .int 0\n"); 64 | fflush(stdout); 65 | return; 66 | 67 | case ':': 68 | if (!smode) /* convert into pointer */ 69 | printf("=.+4; .int 0"); else /* should be sizeof(int*) */ 70 | putchar(':'); 71 | goto loop; 72 | 73 | case 'A': 74 | if ((c=getc())=='1' | c=='2') { 75 | putchar(c+'A'-'1'); 76 | goto loop; 77 | } 78 | putchar('O'); 79 | peekc = c; 80 | goto loop; 81 | 82 | case 'B': 83 | switch (getc()) { 84 | 85 | case '1': 86 | putchar('C'); 87 | goto loop; 88 | 89 | case '2': 90 | putchar('D'); 91 | goto loop; 92 | 93 | case 'E': 94 | putchar('L'); 95 | goto loop; 96 | 97 | case 'F': 98 | putchar('P'); 99 | goto loop; 100 | } 101 | putchar('?'); 102 | goto loop; 103 | 104 | case 'C': 105 | putchar(getc()+'E'-'1'); 106 | goto loop; 107 | 108 | case 'F': 109 | putchar('G'); 110 | goto subtre; 111 | 112 | case 'R': 113 | c=getc(); 114 | if (c== '1') { 115 | putchar('J');} 116 | else if (c=='L'){ 117 | putchar('Q'); 118 | } else { 119 | putchar('I'); 120 | peekc = c; 121 | } 122 | goto loop; 123 | 124 | case 'H': 125 | putchar('H'); 126 | goto subtre; 127 | 128 | case 'I': 129 | putchar('M'); 130 | goto loop; 131 | 132 | case 'M': 133 | putchar('N'); 134 | snlflg++; 135 | goto loop; 136 | 137 | case 'S': 138 | putchar('K'); 139 | subtre: 140 | snlflg = 1; 141 | t = 'A'; 142 | l1: 143 | switch (c=getc()) { 144 | 145 | case '*': 146 | t++; 147 | goto l1; 148 | 149 | case 'S': 150 | t += 2; 151 | goto l1; 152 | 153 | case 'C': 154 | t += 4; 155 | goto l1; 156 | 157 | case '1': 158 | t += 8; 159 | goto l1; 160 | } 161 | peekc = c; 162 | putchar(t); 163 | goto loop; 164 | 165 | case '#': 166 | if(getc()=='1') 167 | putchar('#'); else 168 | printf("\\\""); 169 | goto loop; 170 | 171 | case '%': 172 | if(!tempm) { 173 | putchar(c); 174 | goto loop; 175 | } 176 | if (smode) 177 | printf(".text;"); 178 | loop1: 179 | switch (c=getc()) { 180 | 181 | case 'a': 182 | m = 16; 183 | t = flag(); 184 | goto pf; 185 | 186 | case ',': 187 | putchar(';'); 188 | goto loop1; 189 | 190 | case 'i': 191 | m = 12; 192 | t = flag(); 193 | goto pf; 194 | case 'z': 195 | m = 4; 196 | t = 0; 197 | goto pf; 198 | 199 | case 'c': 200 | t = flag(); 201 | m = 8; 202 | goto pf; 203 | 204 | case 'e': 205 | t = flag(); 206 | m = 20; 207 | goto pf; 208 | 209 | case 'n': 210 | t = flag(); 211 | m = 63; 212 | pf: 213 | if ((c=getc())=='*') 214 | m += 0100; else 215 | peekc = c; 216 | printf(".byte 0%o,0%o", m, t); 217 | goto loop1; 218 | 219 | case '\n': 220 | printf(";.int 1f\n"); 221 | ssmode = 1; 222 | nlflg = 1; 223 | smode = 1; 224 | tempm = 1; 225 | goto loop; 226 | } 227 | putchar(c); 228 | goto loop1; 229 | 230 | case '\t': 231 | if (nlflg) { 232 | nlflg = 0; 233 | goto loop; 234 | } 235 | putchar('\t'); 236 | goto loop; 237 | 238 | case '\n': 239 | tempm = 1; 240 | if (!smode) { /* outside optree definition just emit new line */ 241 | putchar('\n'); 242 | goto loop; 243 | } 244 | if (nlflg) { /* empty line, close off optree section */ 245 | nlflg = 0; 246 | printf("\\0\"\n.text\n"); 247 | smode = 0; 248 | goto loop; 249 | } 250 | if (!snlflg) 251 | printf("\\n"); 252 | snlflg = 0; 253 | printf("\"\n.ascii \""); 254 | nlflg = 1; 255 | goto loop; 256 | } 257 | putchar(c); 258 | goto loop; 259 | } 260 | 261 | /* Gets the next character, ignores blocks of codes inside { } */ 262 | getc() { 263 | auto t, ifcnt; 264 | 265 | ifcnt = 0; 266 | gc: 267 | if (peekc) { 268 | t = peekc; 269 | peekc = 0; 270 | } else 271 | t = getchar(); 272 | if (t==0 | t==EOF) 273 | return(0); 274 | if (t=='{') { 275 | ifcnt++; 276 | t = getchar(); 277 | } 278 | if (t=='}') { 279 | t = getc(); 280 | if (--ifcnt==0) 281 | if (t=='\n') 282 | t = getc(); 283 | } 284 | if (ifcnt & nofloat) 285 | goto gc; 286 | return(t); 287 | } 288 | 289 | flag() { 290 | auto c, f; 291 | 292 | f = 0; 293 | l1: 294 | switch(c=getc()) { 295 | 296 | case 'w': /* word */ 297 | f = 1; 298 | goto l1; 299 | 300 | case 'i': 301 | f = 2; 302 | goto l1; 303 | 304 | case 'b': /* byte */ 305 | f = 3; 306 | goto l1; 307 | 308 | case 'f': /* float */ 309 | f = 4; 310 | goto l1; 311 | 312 | case 'd': /* double */ 313 | f = 5; 314 | goto l1; 315 | 316 | case 'p': /* pointer? */ 317 | f += 16; 318 | goto l1; 319 | } 320 | peekc = c; 321 | return(f); 322 | } 323 | 324 | -------------------------------------------------------------------------------- /src/efftab.s: -------------------------------------------------------------------------------- 1 | /* c code tables */ 2 | 3 | .globl _efftab 4 | 5 | _efftab=.;.int .+4 6 | .int 30, ci30 7 | .int 31, ci30 8 | .int 32, ci30 /* same as 30 */ 9 | .int 33, ci30 /* same as 31 */ 10 | .int 80, ci80 11 | .int 70, cr70 12 | .int 71, cr70 13 | .int 77, cr70 14 | .int 78, cr70 15 | .int 0 16 | 17 | /* ++ prefix */ 18 | ci30: 19 | %ai,n 20 | %abp,n 21 | %ab,n 22 | IB1 A1 23 | 24 | %aip,n 25 | I'l $4,A1 26 | 27 | %nbp*,n 28 | %ni*,n 29 | %nb*,n 30 | F* 31 | IB1 #1(R) 32 | 33 | %nip*,n 34 | F* 35 | I'l $4,#1(R) 36 | 37 | /* = */ 38 | ci80: 39 | %a,c 40 | c72_mov B1, A2,A1 41 | 42 | %a,n 43 | S 44 | c72_mov B1, R,A1 45 | 46 | %n*,c 47 | F* 48 | c72_mov B1, A2,#1(R) 49 | 50 | %n*,e 51 | F* 52 | S1 53 | c72_mov B1, R1,#1(R) 54 | 55 | %n*,n 56 | FS* 57 | S 58 | pop %edi 59 | c72_mov B1, R,(%edi) 60 | 61 | /* =+, =-, =|, =& */ 62 | cr70: 63 | %aw,cw 64 | Il A2,A1 65 | 66 | %aw,n 67 | S 68 | I R,A1 69 | 70 | %a,n 71 | S 72 | c72_mov B1, A1, R1 73 | I R, R1 74 | c72_mov B1, R1, A1 75 | 76 | %ew*,cw 77 | F* 78 | Il A2,#1(R) 79 | 80 | %ew*,n 81 | S 82 | F1* 83 | I R,#1(R1) 84 | 85 | %n*,aw 86 | F* 87 | c72_mov B1,#1(R),R1 88 | I A2,R1 89 | c72_mov B1,R1,#1(R) 90 | 91 | %nw*,n 92 | SS 93 | F* 94 | pop %edi 95 | I %edi,#1(R) 96 | 97 | %n*,n 98 | SS 99 | F* 100 | pop %edi 101 | c72_mov B1,#1(R),R1 102 | I %edi,R1 103 | c72_mov B1,R1,#1(R) 104 | 105 | .data 106 | .balign 4 107 | 108 | -------------------------------------------------------------------------------- /src/pdp11_mov.s: -------------------------------------------------------------------------------- 1 | /* Macros that generate PDP-11 like movb instruction */ 2 | 3 | .macro __isreg name ind 4 | .set _reg\ind, 0 5 | .ifeqs "\name", "%eax" 6 | .set _reg\ind, 1 7 | .endif 8 | 9 | .ifeqs "\name", "%ebx" 10 | .set _reg\ind, 1 11 | .endif 12 | 13 | .ifeqs "\name", "%ecx" 14 | .set _reg\ind, 1 15 | .endif 16 | 17 | .ifeqs "\name", "%edx" 18 | .set _reg\ind, 1 19 | .endif 20 | 21 | .ifeqs "\name", "%esi" 22 | .set _reg\ind, 1 23 | .endif 24 | 25 | .ifeqs "\name", "%edi" 26 | .set _reg\ind, 1 27 | .endif 28 | .endm 29 | 30 | .macro __prinst instr, arg1, arg2 31 | .ifeqs "\arg1", "%eax" 32 | \instr %al, \arg2 33 | .else 34 | .ifeqs "\arg1", "%ebx" 35 | \instr %bl, \arg2 36 | .else 37 | .ifeqs "\arg1", "%ecx" 38 | \instr %cl, \arg2 39 | .else 40 | .ifeqs "\arg1", "%edx" 41 | \instr %dl, \arg2 42 | .else 43 | \instr \arg1, \arg2 44 | .endif 45 | .endif 46 | .endif 47 | .endif 48 | .endm 49 | 50 | .macro c72_mov size=l, from, to 51 | .ifeqs "\size", "l" 52 | .ifnes "\from","\to" 53 | movl \from, \to 54 | .endif 55 | .else 56 | 57 | __isreg \to, 2 58 | 59 | .if _reg2 60 | __prinst movsbl, \from, \to 61 | .else 62 | __prinst movb, \from, \to 63 | .endif 64 | 65 | .endif 66 | .endm 67 | 68 | /* 69 | Code to look up entries in a switch table. 70 | %eax contains the value we want to switch on, %ebx has the switch table address 71 | */ 72 | 1: 73 | addl $8, %ebx 74 | bswitch: 75 | 2: cmp (%ebx),%eax /* if first column matches, check second col */ 76 | je 1f 77 | testl $-1, 4(%ebx) 78 | jnz 1b 79 | 2: 80 | jmp *(%ebx) 81 | 1: 82 | testl $-1, 4(%ebx) 83 | jz 2b 84 | jmp *4(%ebx) 85 | -------------------------------------------------------------------------------- /src/regtab.s: -------------------------------------------------------------------------------- 1 | /* c code tables-- compile to register */ 2 | 3 | fp = 1 /* enable floating-point */ 4 | 5 | .globl _regtab 6 | 7 | _regtab=.;.int .+4 8 | .int 20, cr20 9 | .int 21, cr20 10 | .int 22, cr20 11 | .int 30, cr30 12 | .int 31, cr30 13 | .int 32, cr32 14 | .int 33, cr32 15 | .int 34, cr34 16 | .int 35, cr35 17 | .int 29, cr29 18 | .int 36, cr36 19 | .int 37, cr37 20 | .int 38, cr38 21 | .int 101, cr100 22 | .int 80, cr80 23 | .int 40, cr40 24 | .int 41, cr40 /* - like + */ 25 | .int 42, cr42 26 | .int 43, cr43 27 | .int 44, cr43 28 | .int 45, cr45 29 | .int 46, cr45 30 | .int 47, cr48 31 | .int 48, cr48 32 | .int 60, cr60 33 | .int 61, cr60 34 | .int 62, cr60 35 | .int 63, cr60 36 | .int 64, cr60 37 | .int 65, cr60 38 | .int 66, cr60 39 | .int 67, cr60 40 | .int 68, cr60 41 | .int 69, cr60 42 | .int 70, cr70 43 | .int 71, cr70 44 | .int 72, cr72 45 | .int 73, cr73 46 | .int 74, cr73 47 | .int 75, cr75 48 | .int 76, cr75 49 | .int 77, cr70 50 | .int 78, cr70 51 | .int 102, cr102 52 | .int 97, cr97 53 | .int 0 54 | 55 | /* goto */ 56 | cr102: 57 | %i,n 58 | jmp *A1 59 | 60 | %n*,n 61 | F* 62 | jmp *#1(R) 63 | 64 | %n,n 65 | F 66 | jmp *R 67 | 68 | /* call */ 69 | cr100: 70 | %n*,n 71 | F* 72 | call #1(R) 73 | 74 | %a,n 75 | call A1 76 | 77 | %n,n 78 | F 79 | call R 80 | 81 | 82 | /* name, constant 83 | if arg1 is constant, its type is int (constant are always ints at this point) 84 | otherwise the argument is addressible, which is mem in x86 => we can use movsbl 85 | */ 86 | cr20: 87 | %z,n 88 | xor R,R 89 | 90 | %aw,n 91 | mov A,R 92 | 93 | %ab,n 94 | movsbl A,R 95 | 96 | /*++,-- prefix */ 97 | cr30: 98 | %ai,n 99 | %abp,n 100 | %ab,n 101 | IB1 A1 102 | c72_mov B1, A1,R 103 | 104 | %a,n 105 | I' $4,A1 106 | mov A1,R 107 | 108 | %nbp*,n 109 | %ni*,n 110 | %nb*,n 111 | F* 112 | IB1 #1(R) 113 | c72_mov B1, #1(R),R 114 | 115 | %n*,n 116 | F* 117 | I' $4,#1(R) 118 | mov #1(R),R 119 | 120 | /* ++,-- postfix */ 121 | cr32: 122 | %ai,n 123 | %abp,n 124 | %ab,n 125 | c72_mov B1, A1,R 126 | IB1 A1 127 | 128 | %a,n 129 | c72_mov B1,A1,R 130 | I'B1 $4,A1 131 | 132 | %nb*,n 133 | F* 134 | push #1(R) 135 | Ib #1(R) 136 | pop R 137 | c72_mov b,R,R 138 | 139 | %ni*,n 140 | %nbp*,n 141 | F* 142 | push #1(R) 143 | IB1 #1(R) 144 | pop R 145 | 146 | %n*,n 147 | F* 148 | push #1(R) 149 | I' $4,#1(R) 150 | pop R 151 | 152 | /* ! 153 | dl is the last register, so it is safe to modify it 154 | */ 155 | cr34: 156 | %n,n 157 | FC 158 | setz %dl 159 | movzbl %dl,R 160 | 161 | /* &unary */ 162 | cr35: 163 | %a,n 164 | mov $A1,R 165 | 166 | /* & unary of auto */ 167 | cr29: 168 | %e,n 169 | lea Z(%ebp),R 170 | 171 | /* *unary */ 172 | cr36: 173 | %nbp,n 174 | H* 175 | movsbl ~(R),R 176 | 177 | %n,n 178 | H* 179 | mov ~(R),R 180 | 181 | /* - unary */ 182 | cr37: 183 | %n,n 184 | F 185 | neg R 186 | 187 | /* ~ (unimplemented) */ 188 | cr38: 189 | %n,n 190 | F 191 | not R 192 | 193 | /* = */ 194 | cr80: 195 | %a,n 196 | S 197 | c72_mov B1, R,A1 198 | 199 | %n*,c 200 | F* 201 | c72_mov B1, A2,#1(R) 202 | c72_mov B1, #1(R),R 203 | 204 | %n*,e 205 | F* 206 | S1 207 | c72_mov B1, R1,#1(R) 208 | mov R1,R 209 | 210 | %n*,n 211 | FS* 212 | S 213 | pop %edi 214 | c72_mov B1, R,(%edi) 215 | 216 | /* | and & */ 217 | cr48: 218 | %n,aw 219 | F 220 | I A2,R 221 | 222 | %n,ew* 223 | F 224 | S1* 225 | I #2(R1),R 226 | 227 | %n,e 228 | F 229 | S1 230 | I R1,R 231 | 232 | %n,n 233 | FS 234 | S 235 | pop %edi 236 | I %edi,R 237 | 238 | /* relationals */ 239 | cr60: 240 | %n,n 241 | HC 242 | setI %dl 243 | movzbl %dl, R 244 | 245 | /* >>, << */ 246 | cr45: 247 | %n,c 248 | F 249 | I A2,R 250 | c72_mov B1, R, R 251 | 252 | %n,n 253 | ?2push %cl 254 | FS 255 | S 256 | c72_mov b, R, %cl 257 | Il %cl, (%esp) 258 | pop R 259 | c72_mov B1, R, R 260 | ?2pop %cl 261 | 262 | /* +, - */ 263 | cr40: 264 | %n,aw 265 | F 266 | I A2,R 267 | 268 | %n,ew* 269 | F 270 | S1* 271 | I #2(R1),R 272 | 273 | %n,e 274 | F 275 | S1 276 | I R1,R 277 | 278 | %n,nw* 279 | SS* 280 | F 281 | pop %edi 282 | I (%edi),R 283 | 284 | %n,n 285 | SS 286 | F 287 | pop %edi 288 | I %edi,R 289 | 290 | /* * */ 291 | cr42: 292 | %aw,a 293 | c72_mov B2, A2,R 294 | imul A1,R 295 | 296 | %n,aw 297 | F 298 | imul A2,R 299 | 300 | %n,e 301 | F 302 | S1 303 | imul R1,R 304 | 305 | %n,n 306 | FS 307 | S 308 | pop %edi 309 | imul %edi,R 310 | 311 | /* /; mod 312 | The second argument is calculated first then moved to edi. 313 | This is needed because eax and edx are used for the dividend. 314 | Only eax has to be saved, it is safe to destroy edx as it is the last register. 315 | */ 316 | cr43: 317 | %a,c 318 | %a,ab 319 | c72_mov B2, A2, %edi 320 | ?0push %eax 321 | c72_mov B1, A1, %eax 322 | cdq 323 | idiv %edi 324 | mov I,R 325 | ?0pop %eax 326 | 327 | %a,aw 328 | ?0push %eax 329 | c72_mov B1, A1, %eax 330 | cdq 331 | idivl A2 332 | mov I,R 333 | ?0pop %eax 334 | 335 | %a,n 336 | S 337 | mov R, %edi 338 | ?0push %eax 339 | c72_mov B1, A1, %eax 340 | cdq 341 | idiv %edi 342 | mov I,R 343 | ?0pop %eax 344 | 345 | %n,c 346 | %n,ab 347 | ?0push %eax 348 | F 349 | ?0mov R, %eax 350 | cdq 351 | c72_mov B2, A2, %edi 352 | idiv %edi 353 | mov I,R 354 | ?0pop %eax 355 | 356 | %n,aw 357 | ?0push %eax 358 | F 359 | ?0mov R, %eax 360 | cdq 361 | idiv A2 362 | mov I,R 363 | ?0pop %eax 364 | 365 | %n,n 366 | ?0push %eax 367 | SS 368 | F 369 | ?0mov R, %eax 370 | cdq 371 | pop %edi 372 | idiv %edi 373 | mov I,R 374 | ?0pop %eax 375 | 376 | /* =* */ 377 | cr72: 378 | %aw,cw 379 | imul A2,A1,R 380 | movl R, A1 381 | 382 | %aw,n 383 | S 384 | imul A1,R 385 | movl R, A1 386 | 387 | %a,n 388 | S 389 | c72_mov B1, A1, %edi 390 | imul %edi,R 391 | c72_mov B1, R, A1 392 | c72_mov B1, R, R 393 | 394 | %ew*,n 395 | S 396 | F1* 397 | imul #1(R1),R 398 | mov R, #1(R1) 399 | 400 | /* only active for byte arg1 */ 401 | %e*,n 402 | S 403 | F1* 404 | c72_mov B1, #1(R1), %edi 405 | imul %edi,R 406 | c72_mov B1, R, #1(R1) 407 | c72_mov B1, R, R 408 | 409 | %n*,n 410 | FS* 411 | S 412 | pop %edi 413 | c72_mov B1, (%edi),%esi 414 | imul %esi,R 415 | c72_mov B1,R,(%edi) 416 | c72_mov B1, R, R 417 | 418 | /* =mod, =/ */ 419 | cr73: 420 | %a,c 421 | %a,ab 422 | c72_mov B2, A2, %edi 423 | ?0push %eax 424 | c72_mov B1, A1, %eax 425 | cdq 426 | idiv %edi 427 | c72_mov B1,I,A1 428 | c72_mov B1,I,R 429 | ?0pop %eax 430 | 431 | %a,aw 432 | ?0push %eax 433 | c72_mov B1, A1, %eax 434 | cdq 435 | idivl A2 436 | c72_mov B1,I,A1 437 | c72_mov B1,I,R 438 | ?0pop %eax 439 | 440 | %a,n 441 | S 442 | mov R, %edi 443 | ?0push %eax 444 | c72_mov B1, A1, %eax 445 | cdq 446 | idiv %edi 447 | c72_mov B1,I,A1 448 | c72_mov B1,I,R 449 | ?0pop %eax 450 | 451 | %n*,c 452 | %n*,ab 453 | ?0push %eax 454 | F* 455 | mov R, %esi 456 | c72_mov B1,#1(%esi), %eax 457 | cdq 458 | c72_mov B2, A2, %edi 459 | idiv %edi 460 | c72_mov B1,I,#1(%esi) 461 | c72_mov B1,I,R 462 | ?0pop %eax 463 | 464 | %n*,aw 465 | ?0push %eax 466 | F* 467 | mov R, %esi 468 | c72_mov B1,#1(%esi), %eax 469 | cdq 470 | idiv A2 471 | c72_mov B1,I,#1(%esi) 472 | c72_mov B1,I,R 473 | ?0pop %eax 474 | 475 | %n*,n 476 | ?0push %eax 477 | SS 478 | F* 479 | mov R, %esi 480 | c72_mov B1,#1(%esi), %eax 481 | cdq 482 | pop %edi 483 | idiv %edi 484 | c72_mov B1,I,#1(%esi) 485 | c72_mov B1,I,R 486 | ?0pop %eax 487 | 488 | 489 | /* =>>, =<< */ 490 | cr75: 491 | %a,c 492 | F 493 | I A2,R 494 | c72_mov B1, R, A1 495 | c72_mov B1, R, R 496 | 497 | %a,n 498 | ?2push %cl 499 | FS 500 | S 501 | c72_mov b, R, %cl 502 | Il %cl, (%esp) 503 | pop R 504 | c72_mov B1, R, A1 505 | c72_mov B1, R, R 506 | ?2pop %cl 507 | 508 | %n*,c 509 | F* 510 | c72_mov B1, #1(R), R1 511 | I A2, R1 512 | c72_mov B1, R1, #1(R) 513 | c72_mov B1, R1, R 514 | 515 | %n*,n 516 | ?2push %cl 517 | FS* 518 | S 519 | c72_mov b, R, %cl 520 | pop %edi 521 | c72_mov B1, (%edi), R 522 | I %cl, R 523 | c72_mov B1, R, (%edi) 524 | c72_mov B1, R, R 525 | ?2pop %cl 526 | 527 | /* =+, =-, =|, =& */ 528 | cr70: 529 | %aw,cw 530 | Il A2,A1 531 | mov A1,R 532 | 533 | %aw,n 534 | S 535 | I R,A1 536 | mov A1,R 537 | 538 | %a,n 539 | S 540 | c72_mov B1, A1, R1 541 | I R, R1 542 | c72_mov B1, R1, A1 543 | c72_mov B1, R1, R 544 | 545 | %ew*,cw 546 | F* 547 | Il A2,#1(R) 548 | mov #1(R),R 549 | 550 | %ew*,n 551 | S 552 | F1* 553 | I R,#1(R1) 554 | mov #1(R1),R 555 | 556 | %n*,aw 557 | F* 558 | c72_mov B1,#1(R),R1 559 | I A2,R1 560 | c72_mov B1,R1,#1(R) 561 | c72_mov B1,R1, R 562 | 563 | %nw*,n 564 | SS 565 | F* 566 | pop %edi 567 | I %edi,#1(R) 568 | mov #1(R),R 569 | 570 | %n*,n 571 | SS 572 | F* 573 | pop %edi 574 | c72_mov B1,#1(R),R1 575 | I %edi,R1 576 | c72_mov B1,R1,#1(R) 577 | c72_mov B1,R1, R 578 | 579 | /* int -> int[] */ 580 | cr97: 581 | %n,n 582 | F 583 | shr $2, R 584 | 585 | .data 586 | .balign 4 587 | .text 588 | 589 | -------------------------------------------------------------------------------- /src/sptab.s: -------------------------------------------------------------------------------- 1 | /* c code tables-- expression to -(sp) */ 2 | 3 | .globl _sptab 4 | 5 | _sptab=.;.int .+4 6 | .int 20, cs20 7 | .int 21, cs21 8 | .int 22, cs21 9 | .int 30, cs30 10 | .int 31, cs30 11 | .int 32, cs32 12 | .int 33, cs32 13 | .int 35, cs35 14 | .int 36, cs36 15 | .int 40, cs40 16 | .int 41, cs40 17 | .int 47, cs40 18 | .int 48, cs40 19 | .int 0 20 | 21 | 22 | /* name */ 23 | cs20: 24 | %aw,n 25 | push A 26 | 27 | /* constant */ 28 | cs21: 29 | %aw,n 30 | push A 31 | 32 | /* ++,-- prefix */ 33 | cs30: 34 | %ai,n 35 | %abp,n 36 | Il A1 37 | push A1 38 | 39 | %aw,n 40 | I'l $4,A1 41 | push A1 42 | 43 | %nbp*,n 44 | %ni*,n 45 | F* 46 | Il #1(R) 47 | push #1(R) 48 | 49 | %nip*,n 50 | F* 51 | I'l $4,#1(R) 52 | push #1(R) 53 | /* TODO check this, originally push was first then inc */ 54 | 55 | /* ++,-- postfix; 56 | only handles int and pointers, byte falls back to regtab 57 | */ 58 | cs32: 59 | %ai,n 60 | %abp,n 61 | push A1 62 | Il A1 63 | 64 | %aip,n 65 | push A1 66 | I'l $4,A1 67 | 68 | %nbp*,n 69 | %ni*,n 70 | F* 71 | push #1(R) 72 | Il #1(R) 73 | 74 | %nip*,n 75 | F* 76 | push #1(R) 77 | I'l $4,#1(R) 78 | 79 | /* & unary of extern */ 80 | cs35: 81 | %i,n 82 | push $A1 83 | 84 | /* * unary */ 85 | cs36: 86 | %nbp,n 87 | H* 88 | movsbl ~(R),R 89 | push R 90 | 91 | %n,n 92 | H* 93 | push ~(R) 94 | 95 | /* + */ 96 | cs40: 97 | %n,cw 98 | FS 99 | Il A2,(%esp) 100 | 101 | %n,n 102 | FS 103 | S 104 | Il R,(%esp) 105 | 106 | 107 | .data 108 | .balign 4 109 | .text 110 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # Usage: 5 | # ./test.sh [test_name] 6 | # Executes the given test. Tests are in the 'test' directory 7 | # If no test_name is provided all tests are executed. 8 | 9 | 10 | execute_test() { 11 | echo Running c0 12 | ./c0 test/$1.c tmp.txt 13 | echo Running c1 14 | ./c1 tmp.txt tmp.s 15 | gcc -m32 tmp.s -o runtest 16 | 17 | echo 18 | ./runtest | tee result.txt 19 | echo 20 | 21 | diff -sZ test/$1_expected.txt result.txt 22 | } 23 | 24 | make 25 | if [[ "$1" == "" ]]; then 26 | for TEST_NAME in test/*.c; do 27 | TEST_NAME=$(basename $TEST_NAME) 28 | TEST_NAME=${TEST_NAME%.c} 29 | 30 | if execute_test $TEST_NAME > /dev/null; then 31 | echo $TEST_NAME: ok 32 | else 33 | echo $TEST_NAME: fail 34 | fi 35 | done 36 | 37 | else 38 | execute_test $1 39 | fi -------------------------------------------------------------------------------- /test/addition.c: -------------------------------------------------------------------------------- 1 | main() { 2 | extern iarr; 3 | int iarr[]; 4 | int a,b, tmp; 5 | char c1, c2, carr[4]; 6 | 7 | iarr[2] = -10; 8 | carr[0] = 10; 9 | carr[1] = -10; 10 | carr[2] = 127; 11 | carr[3] = 0; 12 | 13 | a=1; 14 | b=205; 15 | tmp = 3+4; printf("3+4 = %d\n", tmp); 16 | tmp = a+4; printf("a+4 = %d\n", tmp); 17 | tmp = a+b; printf("a+b = %d\n", tmp); 18 | 19 | tmp = 5+*iarr; printf("5+*iarr = %d\n", tmp); 20 | tmp = 5+iarr[1]; printf("5+iarr[1] = %d\n", tmp); 21 | tmp = 5+iarr[2]; printf("5+iarr[2] = %d\n", tmp); 22 | tmp = 5+iarr[3]; printf("5+iarr[3] = %d\n", tmp); 23 | 24 | c1=1; 25 | c2=127; 26 | tmp = c1+4; printf("c1+4 = %d\n", tmp); 27 | tmp = c2+4; printf("c2+4 = %d\n", tmp); 28 | tmp = a+c1; printf("a+c1 = %d\n", tmp); 29 | 30 | tmp = 5+*carr; printf("5+*carr = %d\n", tmp); 31 | tmp = 5+carr[1]; printf("5+carr[1] = %d\n", tmp); 32 | tmp = 5+carr[2]; printf("5+carr[2] = %d\n", tmp); 33 | tmp = 5+carr[3]; printf("5+carr[3] = %d\n", tmp); 34 | } 35 | 36 | iarr[] 0, 5, 10, 128; 37 | 38 | -------------------------------------------------------------------------------- /test/addition_expected.txt: -------------------------------------------------------------------------------- 1 | 3+4 = 7 2 | a+4 = 5 3 | a+b = 206 4 | 5+*iarr = 5 5 | 5+iarr[1] = 10 6 | 5+iarr[2] = -5 7 | 5+iarr[3] = 133 8 | c1+4 = 5 9 | c2+4 = 131 10 | a+c1 = 2 11 | 5+*carr = 15 12 | 5+carr[1] = -5 13 | 5+carr[2] = 132 14 | 5+carr[3] = 5 15 | -------------------------------------------------------------------------------- /test/addition_stack.c: -------------------------------------------------------------------------------- 1 | main() { 2 | extern iarr; 3 | int iarr[]; 4 | int a,b; 5 | char c1, c2, carr[4]; 6 | 7 | iarr[2] = -10; 8 | carr[0] = 10; 9 | carr[1] = -10; 10 | carr[2] = 127; 11 | 12 | a=1; 13 | b=205; 14 | printf("3+4 = %d\n", 3+4); 15 | printf("a+4 = %d\n", a+4); 16 | printf("a+b = %d\n", a+b); 17 | 18 | printf("5+*iarr = %d\n", 5+*iarr); 19 | printf("5+iarr[1] = %d\n", 5+iarr[1]); 20 | printf("5+iarr[2] = %d\n", 5+iarr[2]); 21 | printf("5+iarr[3] = %d\n", 5+iarr[3]); 22 | 23 | c1=1; 24 | c2=127; 25 | printf("c1+4 = %d\n", c1+4); 26 | printf("c2+4 = %d\n", c2+4); 27 | printf("a+c1 = %d\n", a+c1); 28 | 29 | printf("5+*carr = %d\n", 5+*carr); 30 | printf("5+carr[1] = %d\n", 5+carr[1]); 31 | printf("5+carr[2] = %d\n", 5+carr[2]); 32 | printf("5+carr[3] = %d\n", 5+carr[3]); 33 | } 34 | 35 | iarr[] 0, 5, 10, 128; 36 | 37 | -------------------------------------------------------------------------------- /test/addition_stack_expected.txt: -------------------------------------------------------------------------------- 1 | 3+4 = 7 2 | a+4 = 5 3 | a+b = 206 4 | 5+*iarr = 5 5 | 5+iarr[1] = 10 6 | 5+iarr[2] = -5 7 | 5+iarr[3] = 133 8 | c1+4 = 5 9 | c2+4 = 131 10 | a+c1 = 2 11 | 5+*carr = 15 12 | 5+carr[1] = -5 13 | 5+carr[2] = 132 14 | 5+carr[3] = 5 15 | -------------------------------------------------------------------------------- /test/assign_div.c: -------------------------------------------------------------------------------- 1 | destr() { 2 | 3/3; /* destroys %edi */ 3 | return (2); 4 | } 5 | 6 | piarr () { 7 | extern iarr; 8 | 3/3; /* destroys %edi */ 9 | return (iarr); 10 | } 11 | 12 | main() { 13 | extern iarr, destr, piarr; 14 | int iarr[], piarr[]; 15 | int a,b; 16 | char c, d, carr[4]; 17 | 18 | a = 5; 19 | printf("a / 2 = %d\n", a =/ 2); 20 | printf("a = %d\n", a); 21 | 22 | a = 5; 23 | printf("a / (2-4) = %d\n", a =/ (2-4)); 24 | printf("a = %d\n", a); 25 | 26 | a = 128; 27 | printf("a / 3 = %d\n", a =/ 3); 28 | printf("a = %d\n", a); 29 | 30 | a = 24; b =3; 31 | printf("a / b = %d\n", a =/ b); 32 | printf("a = %d\n", a); 33 | printf("b = %d\n\n", b); 34 | 35 | printf("iarr[0] / 3 = %d\n", *iarr =/ 3); 36 | printf("iarr[0] = %d\n", iarr[0]); 37 | printf("iarr[1] = %d\n", iarr[1]); 38 | 39 | iarr[0] = 1; 40 | printf("iarr[1] / 3 = %d\n", iarr[1] =/ 3); 41 | printf("iarr[0] = %d\n", iarr[0]); 42 | printf("iarr[1] = %d\n\n", iarr[1]); 43 | 44 | c = 5; 45 | printf("c / 2 = %d\n", c =/ 2); 46 | printf("c = %d\n", c); 47 | c = -128; 48 | printf("c / 3 = %d\n", c =/ 3); 49 | printf("c = %d\n", c); 50 | 51 | c = 5; d = 2; 52 | printf("c / d = %d\n", c =/ d); 53 | printf("c = %d\n", c); 54 | 55 | c = -128; d = 2; 56 | printf("c / d = %d\n", c =/ d); 57 | printf("c = %d\n\n", c); 58 | 59 | c = -128; d = -2; 60 | printf("c / d = %d\n", c =/ d); 61 | printf("c = %d\n\n", c); 62 | 63 | carr[0] = 5; 64 | carr[1] = -10; 65 | 66 | printf("carr[0] / d = %d\n", *carr =/ d); 67 | printf("carr[0] = %d\n", carr[0]); 68 | printf("carr[1] = %d\n", carr[1]); 69 | 70 | carr[0] = 5; 71 | printf("carr[0] / 2 = %d\n", *carr =/ 2); 72 | printf("carr[0] = %d\n", carr[0]); 73 | printf("carr[1] = %d\n", carr[1]); 74 | 75 | carr[0] = 5; 76 | d=2; 77 | printf("carr[1] / d = %d\n", carr[1] =/ d); 78 | printf("carr[0] = %d\n", carr[0]); 79 | printf("carr[1] = %d\n", carr[1]); 80 | 81 | /* where first register is taken */ 82 | a = 6; 83 | printf("4-(a=/2) = %d\n", 4-(a=/2)); 84 | printf("a = %d\n", a); 85 | 86 | iarr[0] = 6; 87 | (*piarr())=/destr(); 88 | printf("6/2 = %d\n", iarr[0]); 89 | } 90 | 91 | iarr[] 1, 8, 10, 128; 92 | 93 | -------------------------------------------------------------------------------- /test/assign_div_expected.txt: -------------------------------------------------------------------------------- 1 | a / 2 = 2 2 | a = 2 3 | a / (2-4) = -2 4 | a = -2 5 | a / 3 = 42 6 | a = 42 7 | a / b = 8 8 | a = 8 9 | b = 3 10 | 11 | iarr[0] / 3 = 0 12 | iarr[0] = 0 13 | iarr[1] = 8 14 | iarr[1] / 3 = 2 15 | iarr[0] = 1 16 | iarr[1] = 2 17 | 18 | c / 2 = 2 19 | c = 2 20 | c / 3 = -42 21 | c = -42 22 | c / d = 2 23 | c = 2 24 | c / d = -64 25 | c = -64 26 | 27 | c / d = 64 28 | c = 64 29 | 30 | carr[0] / d = -2 31 | carr[0] = -2 32 | carr[1] = -10 33 | carr[0] / 2 = 2 34 | carr[0] = 2 35 | carr[1] = -10 36 | carr[1] / d = -5 37 | carr[0] = 5 38 | carr[1] = -5 39 | 4-(a=/2) = 1 40 | a = 3 41 | 6/2 = 3 42 | -------------------------------------------------------------------------------- /test/assign_eff.c: -------------------------------------------------------------------------------- 1 | main() { 2 | extern iarr; 3 | int iarr[]; 4 | int a,b; 5 | char c, d, carr[4]; 6 | 7 | a = 4; 8 | printf("test1: %d\n", a); 9 | 10 | c = 15; 11 | printf("test2: %d\n", c); 12 | 13 | c = -128; 14 | printf("test3: %d\n", c); 15 | 16 | iarr[2] = 12345; 17 | printf("test4: %d %d %d\n", iarr[1], iarr[2], iarr[3]); 18 | 19 | carr[0] = 3; 20 | printf("test5: %d\n", carr[0]); 21 | } 22 | 23 | iarr[] 1, 8, 10, 128; 24 | 25 | -------------------------------------------------------------------------------- /test/assign_eff_expected.txt: -------------------------------------------------------------------------------- 1 | test1: 4 2 | test2: 15 3 | test3: -128 4 | test4: 8 12345 128 5 | test5: 3 6 | -------------------------------------------------------------------------------- /test/assign_mul.c: -------------------------------------------------------------------------------- 1 | main() { 2 | extern iarr; 3 | int iarr[]; 4 | int a,b; 5 | char c, d, carr[4]; 6 | 7 | a = 5; 8 | printf("a * 3 = %d\n", a =* 3); 9 | printf("a = %d\n", a); 10 | 11 | a = 5; b =3; 12 | printf("a * b = %d\n", a =* b); 13 | printf("a = %d\n", a); 14 | 15 | printf("iarr[0] * b = %d\n", *iarr =* b); 16 | printf("iarr[0] = %d\n", iarr[0]); 17 | 18 | printf("iarr[1] * b = %d\n", iarr[1] =* b); 19 | printf("iarr[1] = %d\n", iarr[1]); 20 | 21 | c = 5; 22 | printf("c * 3 = %d\n", c =* 3); 23 | printf("c = %d\n", c); 24 | 25 | c = -5; 26 | printf("c * 3 = %d\n", c =* 3); 27 | printf("c = %d\n", c); 28 | 29 | c = 5; d =3; 30 | printf("c * d = %d\n", c =* d); 31 | printf("c = %d\n", c); 32 | 33 | carr[0] = 5; 34 | carr[1] = -10; 35 | 36 | printf("carr[0] * d = %d\n", *carr =* d); 37 | printf("carr[0] = %d\n", carr[0]); 38 | 39 | carr[0] = 5; 40 | printf("carr[0] * 128 = %d\n", *carr =* 128); 41 | printf("carr[0] = %d\n", carr[0]); 42 | printf("carr[1] = %d\n", carr[1]); 43 | 44 | printf("carr[1] * d = %d\n", carr[1] =* d); 45 | printf("carr[1] = %d\n", carr[1]); 46 | } 47 | 48 | iarr[] 0, 5, 10, 128; 49 | 50 | -------------------------------------------------------------------------------- /test/assign_mul_expected.txt: -------------------------------------------------------------------------------- 1 | a * 3 = 15 2 | a = 15 3 | a * b = 15 4 | a = 15 5 | iarr[0] * b = 0 6 | iarr[0] = 0 7 | iarr[1] * b = 15 8 | iarr[1] = 15 9 | c * 3 = 15 10 | c = 15 11 | c * 3 = -15 12 | c = -15 13 | c * d = 15 14 | c = 15 15 | carr[0] * d = 15 16 | carr[0] = 15 17 | carr[0] * 128 = -128 18 | carr[0] = -128 19 | carr[1] = -10 20 | carr[1] * d = -30 21 | carr[1] = -30 22 | -------------------------------------------------------------------------------- /test/assign_op_eff.c: -------------------------------------------------------------------------------- 1 | main() { 2 | extern iarr; 3 | int iarr[]; 4 | int p[]; 5 | int a,b; 6 | char c, d, carr[4], cp[]; 7 | 8 | a = 4; 9 | a =+ 1; 10 | printf("test1: %d\n", a); 11 | 12 | a =- 1; 13 | printf("test2: %d\n", a); 14 | 15 | c = 15; c=+ 5; 16 | printf("test3: %d\n", c); 17 | 18 | c = -128; c=+ 100; 19 | printf("test4: %d\n", c); 20 | 21 | iarr[2] =| 3; 22 | printf("test5: %d %d %d\n", iarr[1], iarr[2], iarr[3]); 23 | 24 | /* BUG: p =+ n; n is not scaled with word size 25 | p = iarr+2; 26 | p =+ 1; // is this buggy in original as well? 27 | printf("test6: %d\n", *p); */ 28 | 29 | carr[0] = 3; carr[1] = 10; carr[2] = -128; 30 | carr[0] =+ 3; 31 | printf("test7: %d %d\n", carr[0], carr[1]); 32 | 33 | cp = carr+1; 34 | cp =- 1; 35 | printf("test8: %d\n", *cp); 36 | } 37 | 38 | iarr[] 1, 8, 10, 128; 39 | 40 | -------------------------------------------------------------------------------- /test/assign_op_eff_expected.txt: -------------------------------------------------------------------------------- 1 | test1: 5 2 | test2: 4 3 | test3: 20 4 | test4: -28 5 | test5: 8 11 128 6 | test7: 6 10 7 | test8: 6 8 | -------------------------------------------------------------------------------- /test/assign_or.c: -------------------------------------------------------------------------------- 1 | main() { 2 | extern iarr; 3 | int iarr[]; 4 | int a,b; 5 | char c, d, carr[4]; 6 | 7 | a = 5; 8 | printf("a | 3 = %d\n", a =| 3); 9 | printf("a = %d\n", a); 10 | 11 | a = 5; b =3; 12 | printf("a | b = %d\n", a =| b); 13 | printf("a = %d\n", a); 14 | 15 | printf("iarr[0] | b = %d\n", *iarr =| b); 16 | printf("iarr[0] = %d\n", iarr[0]); 17 | 18 | printf("iarr[1] | b = %d\n", iarr[1] =| b); 19 | printf("iarr[1] = %d\n", iarr[1]); 20 | 21 | c = 5; 22 | printf("c | 3 = %d\n", c =| 3); 23 | printf("c = %d\n", c); 24 | 25 | c = 5; d =3; 26 | printf("c | d = %d\n", c =| b); 27 | printf("c = %d\n", c); 28 | 29 | carr[0] = 5; 30 | carr[1] = -10; 31 | 32 | printf("carr[0] | d = %d\n", *carr =| d); 33 | printf("carr[0] = %d\n", carr[0]); 34 | 35 | printf("carr[0] | 128 = %d\n", *carr =| 128); 36 | printf("carr[0] = %d\n", carr[0]); 37 | printf("carr[1] = %d\n", carr[1]); 38 | 39 | printf("carr[1] | d = %d\n", carr[1] =| d); 40 | printf("carr[1] = %d\n", carr[1]); 41 | } 42 | 43 | iarr[] 0, 5, 10, 128; 44 | 45 | -------------------------------------------------------------------------------- /test/assign_or_expected.txt: -------------------------------------------------------------------------------- 1 | a | 3 = 7 2 | a = 7 3 | a | b = 7 4 | a = 7 5 | iarr[0] | b = 3 6 | iarr[0] = 3 7 | iarr[1] | b = 7 8 | iarr[1] = 7 9 | c | 3 = 7 10 | c = 7 11 | c | d = 7 12 | c = 7 13 | carr[0] | d = 7 14 | carr[0] = 7 15 | carr[0] | 128 = -121 16 | carr[0] = -121 17 | carr[1] = -10 18 | carr[1] | d = -9 19 | carr[1] = -9 20 | -------------------------------------------------------------------------------- /test/assign_shr.c: -------------------------------------------------------------------------------- 1 | destr() { 2 | 3/3; /* destroys %edi */ 3 | return (2); 4 | } 5 | 6 | piarr () { 7 | extern iarr; 8 | 3/3; /* destroys %edi */ 9 | return (iarr); 10 | } 11 | 12 | main() { 13 | extern iarr, piarr; 14 | int iarr[], piarr[]; 15 | int a,b; 16 | char c, d, carr[4]; 17 | 18 | a = 5; 19 | printf("a >> 2 = %d\n", a =>> 2); 20 | printf("a = %d\n", a); 21 | 22 | a = 128; 23 | printf("a >> 3 = %d\n", a =>> 3); 24 | printf("a = %d\n", a); 25 | 26 | a = 24; b =3; 27 | printf("a >> b = %d\n", a =>> b); 28 | printf("a = %d\n", a); 29 | printf("b = %d\n\n", b); 30 | 31 | printf("iarr[0] >> 3 = %d\n", *iarr =>> 3); 32 | printf("iarr[0] = %d\n", iarr[0]); 33 | printf("iarr[1] = %d\n", iarr[1]); 34 | 35 | iarr[0] = 1; 36 | printf("iarr[1] >> 3 = %d\n", iarr[1] =>> 3); 37 | printf("iarr[0] = %d\n", iarr[0]); 38 | printf("iarr[1] = %d\n\n", iarr[1]); 39 | 40 | c = 5; 41 | printf("c >> 2 = %d\n", c =>> 2); 42 | printf("c = %d\n", c); 43 | c = -128; 44 | printf("c >> 3 = %d\n", c =>> 3); 45 | printf("c = %d\n", c); 46 | 47 | c = 5; d =2; 48 | printf("c >> d = %d\n", c =>> d); 49 | printf("c = %d\n", c); 50 | 51 | c = -128; d =2; 52 | printf("c >> d = %d\n", c =>> d); 53 | printf("c = %d\n\n", c); 54 | 55 | carr[0] = 5; 56 | carr[1] = -10; 57 | 58 | printf("carr[0] >> d = %d\n", *carr =>> d); 59 | printf("carr[0] = %d\n", carr[0]); 60 | printf("carr[1] = %d\n", carr[1]); 61 | 62 | carr[0] = 5; 63 | printf("carr[0] >> 2 = %d\n", *carr =>> 2); 64 | printf("carr[0] = %d\n", carr[0]); 65 | printf("carr[1] = %d\n", carr[1]); 66 | 67 | carr[0] = 5; 68 | printf("carr[1] >> d = %d\n", carr[1] =>> d); 69 | printf("carr[0] = %d\n", carr[0]); 70 | printf("carr[1] = %d\n", carr[1]); 71 | 72 | iarr[0] = 1; 73 | (*piarr())=<> 2 = 1 2 | a = 1 3 | a >> 3 = 16 4 | a = 16 5 | a >> b = 3 6 | a = 3 7 | b = 3 8 | 9 | iarr[0] >> 3 = 0 10 | iarr[0] = 0 11 | iarr[1] = 8 12 | iarr[1] >> 3 = 1 13 | iarr[0] = 1 14 | iarr[1] = 1 15 | 16 | c >> 2 = 1 17 | c = 1 18 | c >> 3 = -16 19 | c = -16 20 | c >> d = 1 21 | c = 1 22 | c >> d = -32 23 | c = -32 24 | 25 | carr[0] >> d = 1 26 | carr[0] = 1 27 | carr[1] = -10 28 | carr[0] >> 2 = 1 29 | carr[0] = 1 30 | carr[1] = -10 31 | carr[1] >> d = -3 32 | carr[0] = 5 33 | carr[1] = -3 34 | 1<<2 = 4 35 | -------------------------------------------------------------------------------- /test/goto.c: -------------------------------------------------------------------------------- 1 | main () { 2 | int a[1]; 3 | 4 | goto skip1; 5 | printf("test1 - fail\n"); 6 | skip1: 7 | printf("test1 - ok\n"); 8 | 9 | goto (1 ? skip2 : 0); 10 | printf("test2 - fail\n"); 11 | skip2: 12 | printf("test2 - ok\n"); 13 | 14 | a[0] = skip3; 15 | goto a[0]; 16 | printf("test3 - fail\n"); 17 | skip3: 18 | printf("test3 - ok\n"); 19 | } -------------------------------------------------------------------------------- /test/goto_expected.txt: -------------------------------------------------------------------------------- 1 | test1 - ok 2 | test2 - ok 3 | test3 - ok 4 | -------------------------------------------------------------------------------- /test/if.c: -------------------------------------------------------------------------------- 1 | main() { 2 | int a, b; 3 | a = 1; 4 | if(a) { 5 | printf("test1 - a is nonzero\n"); 6 | } 7 | 8 | a = 0; 9 | if(a) { 10 | printf("test2 - a is nonzero\n"); 11 | } 12 | 13 | a = 0; 14 | if(!a) { 15 | printf("test3 - a is zero\n"); 16 | } 17 | 18 | a = 0; 19 | if(a) { 20 | printf("test4 - if called\n"); 21 | } else { 22 | printf("test4 - else called\n"); 23 | } 24 | 25 | a = 0; 26 | b = 1; 27 | if(a | b) { 28 | printf("test5 - a | b\n"); 29 | } 30 | 31 | a = 0; 32 | b = 0; 33 | if(a | b) { 34 | printf("test6 - a | b\n"); 35 | } 36 | 37 | a = 1; 38 | b = 1; 39 | if(a & b) { 40 | printf("test7 - a | b\n"); 41 | } 42 | 43 | a=6; 44 | b=5; 45 | if (a - b) { 46 | printf("test8 - ok\n"); 47 | } 48 | 49 | b=6; 50 | if (a - b) { 51 | printf("test9 - fail\n"); 52 | } else { 53 | printf("test9 - ok\n"); 54 | } 55 | 56 | a=6; 57 | b=5; 58 | if (a % b) { 59 | printf("test10 - ok\n"); 60 | } 61 | 62 | b=3; 63 | if (a % b) { 64 | printf("test11 - fail\n"); 65 | } else { 66 | printf("test11 - ok\n"); 67 | } 68 | } 69 | 70 | iarr[] 1, 8, 10, 128; 71 | 72 | -------------------------------------------------------------------------------- /test/if_expected.txt: -------------------------------------------------------------------------------- 1 | test1 - a is nonzero 2 | test3 - a is zero 3 | test4 - else called 4 | test5 - a | b 5 | test7 - a | b 6 | test8 - ok 7 | test9 - ok 8 | test10 - ok 9 | test11 - ok 10 | -------------------------------------------------------------------------------- /test/incdec_eff.c: -------------------------------------------------------------------------------- 1 | main() { 2 | extern iarr; 3 | int iarr[]; 4 | int p[]; 5 | int a,b; 6 | char c, d, carr[4], cp[]; 7 | 8 | a = 4; 9 | a++; 10 | printf("test1: %d\n", a); 11 | 12 | --a; 13 | printf("test2: %d\n", a); 14 | 15 | c = 15; c++; 16 | printf("test3: %d\n", c); 17 | 18 | c = -128; ++c; 19 | printf("test4: %d\n", c); 20 | 21 | iarr[2]++; 22 | printf("test5: %d %d %d\n", iarr[1], iarr[2], iarr[3]); 23 | 24 | p = iarr; 25 | p++; 26 | printf("test6: %d\n", *p); 27 | 28 | carr[0] = 3; carr[1] = 10; carr[2] = -128; 29 | carr[0]++; 30 | printf("test7: %d %d\n", carr[0], carr[1]); 31 | 32 | cp = carr+1; 33 | cp++; 34 | printf("test8: %d\n", *cp); 35 | } 36 | 37 | iarr[] 1, 8, 10, 128; 38 | 39 | -------------------------------------------------------------------------------- /test/incdec_eff_expected.txt: -------------------------------------------------------------------------------- 1 | test1: 5 2 | test2: 4 3 | test3: 16 4 | test4: -127 5 | test5: 8 11 128 6 | test6: 8 7 | test7: 4 10 8 | test8: -128 9 | -------------------------------------------------------------------------------- /test/incdec_post_stack.c: -------------------------------------------------------------------------------- 1 | destr() { 2 | 3/3; 3 | return (6); 4 | } 5 | 6 | deref(testid, p) 7 | int testid; 8 | char p[]; { 9 | printf("test%d: %d\n", testid, *p); 10 | }; 11 | 12 | main() { 13 | extern iarr, deref; 14 | int iarr[]; 15 | int p[]; 16 | int a,b; 17 | char c, d, carr[4], cp[]; 18 | 19 | a = 4; 20 | printf("test1: %d\n", a++); 21 | printf("test1: %d\n", a); 22 | 23 | printf("test2: %d\n", a--); 24 | printf("test2: %d\n", a); 25 | 26 | c = 15; 27 | printf("test3: %d\n", c++); 28 | printf("test3: %d\n", c); 29 | 30 | c = -128; 31 | printf("test4: %d\n", c++); 32 | printf("test4: %d\n", c); 33 | 34 | printf("test5: %d\n", iarr[2]++); 35 | printf("test5: %d %d %d\n", iarr[1], iarr[2], iarr[3]); 36 | 37 | p = iarr; 38 | deref(6, p++); 39 | printf("test6: %d\n", *p); 40 | 41 | carr[0] = 3; carr[1] = 10; carr[2] = -128; 42 | printf("test7: %d\n", carr[0]++); 43 | printf("test7: %d %d\n", carr[0], carr[1]); 44 | 45 | cp = carr; 46 | deref(8, cp++); 47 | printf("test8: %d\n", *cp); 48 | } 49 | 50 | iarr[] 1, 8, 10, 128; 51 | 52 | -------------------------------------------------------------------------------- /test/incdec_post_stack_expected.txt: -------------------------------------------------------------------------------- 1 | test1: 4 2 | test1: 5 3 | test2: 5 4 | test2: 4 5 | test3: 15 6 | test3: 16 7 | test4: -128 8 | test4: -127 9 | test5: 10 10 | test5: 8 11 128 11 | test6: 1 12 | test6: 8 13 | test7: 3 14 | test7: 4 10 15 | test8: 4 16 | test8: 10 17 | -------------------------------------------------------------------------------- /test/incdec_pre_stack.c: -------------------------------------------------------------------------------- 1 | destr() { 2 | 3/3; 3 | return (6); 4 | } 5 | 6 | deref(testid, p) 7 | int testid; 8 | char p[]; { 9 | printf("test%d: %d\n", testid, *p); 10 | }; 11 | 12 | main() { 13 | extern iarr, deref; 14 | int iarr[]; 15 | int p[]; 16 | int a,b; 17 | char c, d, carr[4], cp[]; 18 | 19 | a = 4; 20 | printf("test1: %d\n", ++a); 21 | printf("test1: %d\n", a); 22 | 23 | printf("test2: %d\n", --a); 24 | printf("test2: %d\n", a); 25 | 26 | c = 15; 27 | printf("test3: %d\n", ++c); 28 | printf("test3: %d\n", c); 29 | 30 | c = -128; 31 | printf("test4: %d\n", ++c); 32 | printf("test4: %d\n", c); 33 | 34 | printf("test5: %d\n", ++iarr[2]); 35 | printf("test5: %d %d %d\n", iarr[1], iarr[2], iarr[3]); 36 | 37 | p = iarr; 38 | deref(6, ++p); 39 | printf("test6: %d\n", *p); 40 | 41 | carr[0] = 3; carr[1] = 10; carr[2] = -128; 42 | printf("test7: %d\n", ++carr[0]); 43 | printf("test7: %d %d\n", carr[0], carr[1]); 44 | 45 | cp = carr; 46 | deref(8, ++cp); 47 | printf("test8: %d\n", *cp); 48 | } 49 | 50 | iarr[] 1, 8, 10, 128; 51 | 52 | -------------------------------------------------------------------------------- /test/incdec_pre_stack_expected.txt: -------------------------------------------------------------------------------- 1 | test1: 5 2 | test1: 5 3 | test2: 4 4 | test2: 4 5 | test3: 16 6 | test3: 16 7 | test4: -127 8 | test4: -127 9 | test5: 11 10 | test5: 8 11 128 11 | test6: 8 12 | test6: 8 13 | test7: 4 14 | test7: 4 10 15 | test8: 10 16 | test8: 10 17 | -------------------------------------------------------------------------------- /test/relational.c: -------------------------------------------------------------------------------- 1 | main() { 2 | extern iarr[]; 3 | int a, b; 4 | char c ,d, carr[4]; 5 | 6 | if(2>1) { 7 | printf("test1 - ok\n"); 8 | } 9 | 10 | a = 3; 11 | if(a>1) { 12 | printf("test2 - ok\n"); 13 | } 14 | 15 | a = 3; 16 | b = -4; 17 | if(a>b) { 18 | printf("test3 - ok\n"); 19 | } 20 | 21 | if(iarr[1]>1) { 22 | printf("test4 - ok\n"); 23 | } 24 | 25 | if(iarr[1]>2+2) { 26 | printf("test5 - ok\n"); 27 | } 28 | 29 | c = 6; 30 | d = -7; 31 | if(c>1) { 32 | printf("test6 - ok\n"); 33 | } 34 | 35 | if(c>d) { 36 | printf("test7 - ok\n"); 37 | } 38 | 39 | carr[0] = 2; 40 | carr[1] = -128; 41 | if(d>carr[1]) { 42 | printf("test8 - ok\n"); 43 | } 44 | 45 | printf("eval - rel1: %d\n", a>=3); 46 | printf("eval - rel2: %d\n", a>=9); 47 | } 48 | 49 | 50 | iarr[] 1, 8, 10, 128; 51 | 52 | -------------------------------------------------------------------------------- /test/relational_expected.txt: -------------------------------------------------------------------------------- 1 | test1 - ok 2 | test2 - ok 3 | test3 - ok 4 | test4 - ok 5 | test5 - ok 6 | test6 - ok 7 | test7 - ok 8 | test8 - ok 9 | eval - rel1: 1 10 | eval - rel2: 0 11 | -------------------------------------------------------------------------------- /test/switch.c: -------------------------------------------------------------------------------- 1 | main () { 2 | int a; 3 | a=0; 4 | switch(a) { 5 | case 0: 6 | printf("test1 - 0\n"); 7 | case 1: 8 | printf("test1 - 1\n"); 9 | default: 10 | printf("test1 - default\n"); 11 | } 12 | 13 | a=1; 14 | switch(a) { 15 | case 0: 16 | printf("test2 - 0\n"); 17 | break; 18 | case 1: 19 | printf("test2 - 1\n"); 20 | break; 21 | default: 22 | printf("test2 - default\n"); 23 | break; 24 | } 25 | 26 | a=5; 27 | switch(a) { 28 | case 0: 29 | printf("test3 - 0\n"); 30 | case 1: 31 | printf("test3 - 1\n"); 32 | default: 33 | printf("test3 - default\n"); 34 | } 35 | 36 | printf("end of program\n"); 37 | } -------------------------------------------------------------------------------- /test/switch_expected.txt: -------------------------------------------------------------------------------- 1 | test1 - 0 2 | test1 - 1 3 | test1 - default 4 | test2 - 1 5 | test3 - default 6 | end of program 7 | --------------------------------------------------------------------------------