├── .gitignore ├── Caldera-license.pdf ├── Makefile ├── README.md ├── cc ├── emulator ├── cpfile ├── emucat └── emucc ├── examples ├── fizzbuzz.c └── helloworld.c ├── fix_tab.sh └── src ├── c0.h ├── c00.c ├── c01.c ├── c02.c ├── c03.c ├── c0t.c ├── c0t.s ├── c1.h ├── c10.c ├── c11.c ├── c1t.c ├── c1t.s ├── cctab.s ├── config.h ├── cvopt.c ├── efftab.s ├── regtab.s └── sptab.s /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.tmp 3 | docs 4 | *.exe 5 | src/*_fixed.s 6 | -------------------------------------------------------------------------------- /Caldera-license.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vegesm/first-cc-gcc/4b3d6c461f18b36ee65d31b8edd1ff121e5a0436/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_fixed = $(c1_tabs:%tab.s=%tab_fixed.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_fixed) src/c1.h 16 | $(CC) $(CFLAGS) -o c1 $(c1_src) $(c1_tabs_fixed) 17 | 18 | cvopt: src/cvopt.c 19 | $(CC) $(CFLAGS) -o cvopt src/cvopt.c 20 | 21 | %tab_fixed.s: %tab.s cvopt 22 | ./fix_tab.sh $< > $@ 23 | 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # first-cc-gcc 2 | A port of the [earliest C compiler](https://www.bell-labs.com/usr/dmr/www/primevalC.html) to modern GCC. The compiler outputs PDP-11 assembly code that can be compiled and run on a PDP-11 emulator (check out [c72](https://github.com/vegesm/c72) if you want x86 code that runs on current Linux). The compiler runs only in 32 bit mode as the original code assumes that the pointer size and word size are the same. 3 | 4 | ## Usage 5 | To compile the compiler and run it simply do: 6 | ```shell 7 | make 8 | ./cc examples/fizzbuzz.c > fizzbuzz.s 9 | ``` 10 | Note: if you get errors on missing "bits/libc-header-start.h" headers make sure you have the 32bit libc installed. 11 | 12 | ### Emulator 13 | The hard part is to set up an emulator, transfer the file to it(!) and run the assembler. A very [early UNIX implementation](https://github.com/qrush/unix) based on SIMH is available. For Windows, there is also a [pre-built binary](http://sourceforge.net/project/downloading.php?group_id=204974&filename=Research-unixv1-0.3.exe&a=25520957) 14 | 15 | I could not get the tape emulators working so ended up with a hacky solution to transfer files. The simulator lets you to log in via telnet, so the files are copied by starting up a text editor on the simulator and streaming the characters into it and then saving and closing the file. 16 | 17 | Also, if you close the connection the session is lost, so it is important to keep the connection to the 18 | simulator alive with a hack using ncat. 19 | ```shell 20 | # Start emulator 21 | pdp11 simh.cfg 22 | # Open a pipe to the simulator 23 | # If you use the prebuilt Windows simulator, use port 12323 24 | ncat -lk -p 5556 | ncat localhost 5555 25 | 26 | # send login username to emulator 27 | echo root | emulator/emucat 28 | # copy file over by typing it into ed 29 | emulator/cpfile fizzbuzz.s /fizzbz.s 30 | # call assembler and linker 31 | emulator/emucc /fizzbz.s 32 | # execute the compiled program 33 | echo a.out | emulator/emucat 34 | ``` 35 | 36 | Note that the file is called `fizzbz.s` on the emulator. This is because the UNIX used here handles 8 character long filenames only! 37 | 38 | ## Old C features 39 | 40 | This version of C is from around 1972. While the general syntax is pretty much the same as today, 41 | there are tons of missing features: 42 | - no preprocessor, no for loops 43 | - 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 44 | - the type system is very weak: pointers, chars, ints can be freely converted into one another 45 | - types of the function parameters are not checked, anything can be passed to any function 46 | - compound assignment operators are reversed, they are `=+`, `=*` 47 | - only integer global variables can be defined, and the syntax is strange (see helloworld example) 48 | - 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 49 | 50 | 51 | Interestingly, some features that were already existing in this early version: 52 | - function pointers 53 | - the ABI is nearly the same as today's 32 bit ABI 54 | - `a[b]` is implemented as `*(a+b)` 55 | 56 | -------------------------------------------------------------------------------- /cc: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | BUILD_FOLDER=. 4 | $BUILD_FOLDER/c0 $1 $1.tmp 5 | $BUILD_FOLDER/c1 $1.tmp | tr -d '\r' -------------------------------------------------------------------------------- /emulator/cpfile: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo rm $2 | emulator/emucat 4 | echo ed $2 | emulator/emucat 5 | echo a | emulator/emucat 6 | # slow down transfer to prevent dropping characters 7 | cat $1 | (lines=0; while read line; do echo $line; if [ $((++lines % 5)) -eq 0 ]; then sleep 1; fi; done) | emulator/emucat 8 | echo | emulator/emucat 9 | echo . | emulator/emucat 10 | echo w | emulator/emucat 11 | echo q | emulator/emucat -------------------------------------------------------------------------------- /emulator/emucat: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ncat localhost 5556 -------------------------------------------------------------------------------- /emulator/emucc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo as -u $1 | emulator/emucat 4 | NAME=`basename $1 .s` 5 | echo mv a.out $NAME.o | emulator/emucat 6 | echo ld /usr/lib/crt0.o $NAME.o -lc -l | emulator/emucat -------------------------------------------------------------------------------- /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 | printf("%d\n", 4); 5 | } 6 | 7 | globint 4; 8 | globarr[] 1, 2, 3; -------------------------------------------------------------------------------- /fix_tab.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | UNDERSCORE=_ 4 | if [ "$(expr substr $(uname -s) 1 5)" = "Linux" ]; then 5 | UNDERSCORE= 6 | fi 7 | 8 | # convert original asm listing and remove comments 9 | cat $1 | ./cvopt | sed 's|/.*||g' | \ 10 | # convert the lookup table at the start to use .int directives 11 | sed -r 's/([0-9]+)\.;[[:blank:]]+([A-Za-z0-9]+)/.int \1, \2/g' | \ 12 | # replace .even directive with .balign, replace first row of the lookup table 13 | sed 's/\.even/.balign 4/g' | sed -r 's/_(eff|reg|sp|cc)tab=\.;[[:blank:]]*\.\+2/_\1tab:.int .,.+4/g' | \ 14 | # replace single `0` characters with .int directive 15 | sed -r 's/^([[:blank:]]+)0$/\1.int 0/g' | \ 16 | # remove leading underscore on linux 17 | sed -r 's/_(eff|reg|sp|cc)tab/'$UNDERSCORE'\1tab/' 18 | -------------------------------------------------------------------------------- /src/c0.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include "config.h" 3 | //#define DEBUG 4 | 5 | /* c00.c */ 6 | setup(); 7 | init(char[], int); 8 | int *lookup(); 9 | symbol(); 10 | subseq(int,int,int); 11 | getstr(); 12 | getcc(); 13 | mapch(int); 14 | tree(); 15 | void declare(int); 16 | 17 | /* c01.c */ 18 | void build(int); 19 | int *convert(int[], int, int, int); 20 | chkw(int[]); 21 | lintyp(int); 22 | error(char[]); 23 | error1(char[],int); 24 | error2(char[],int,int); 25 | int *block(int, ...); 26 | chklval(int[]); 27 | notcompat(int, int); 28 | max(int, int); 29 | 30 | /* c02.c */ 31 | function(char[]); 32 | void extdef(); 33 | void statement(); 34 | pexpr(); 35 | pswitch(); 36 | blkhed(); 37 | blkend(); 38 | errflush(int); 39 | declist(); 40 | easystmt(); 41 | branch(int); 42 | 43 | /* c03.c */ 44 | jumpc(int[], int, int); 45 | rcexpr(int[], int); 46 | jump(int); 47 | label(int); 48 | retseq(); 49 | slabel(); 50 | void setstk(int); 51 | defvec(); 52 | defstat(int[]); 53 | 54 | length(int); 55 | rlength(int); 56 | putwrd(int); 57 | printn(int,int); 58 | void cc_printf(char[], ...); 59 | cc_putchar(int); 60 | 61 | /* globals */ 62 | extern ossiz; 63 | extern ospace[]; 64 | extern regtab; 65 | extern efftab; 66 | extern cctab; 67 | extern sptab; 68 | extern symbuf[]; 69 | extern pssiz; 70 | extern namsiz; 71 | extern nwps; 72 | extern hshused; 73 | extern hshsiz; 74 | extern hshlen; 75 | extern hshtab[]; 76 | extern *space; 77 | extern *cp; 78 | extern cmsiz; 79 | extern cmst[]; 80 | extern ctyp; 81 | extern isn; 82 | extern swsiz; 83 | extern swtab[]; 84 | extern *swp; 85 | extern contlab; 86 | extern brklab; 87 | extern deflab; 88 | extern nreg; 89 | extern maprel[]; 90 | extern nauto; 91 | extern stack; 92 | extern peeksym; 93 | extern peekc; 94 | extern eof; 95 | extern line; 96 | extern int *csym; 97 | extern cval; 98 | extern ncpw; 99 | extern nerror; 100 | extern FILE *fout; 101 | extern int *paraml; 102 | extern int *parame; 103 | extern tmpfil; 104 | 105 | /* code tables */ 106 | extern char ctab[]; 107 | extern int opdope[]; 108 | extern int cvtab[]; 109 | #define printf cc_printf 110 | #define putchar cc_putchar 111 | -------------------------------------------------------------------------------- /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 | init(s, t) 17 | char s[]; { 18 | char *sp; 19 | int *np, i; 20 | 21 | /* copy s to symbuf */ 22 | i = namsiz; 23 | sp = symbuf; 24 | while(i--) 25 | if ((*sp++ = *s++)=='\0') --s; 26 | np = lookup(); 27 | *np++ = 1; 28 | *np = t; 29 | } 30 | 31 | /* 32 | * First pass of the C compiler. It parses the input and generates an intermediate(?) output, 33 | * containing parsed expression trees with some additional assembly code. 34 | * 35 | * Short overview: the compiler parses global elements, which can be either functions or 36 | * global variable declarations. In functions, each expression is parsed into a tree, which is stored 37 | * in ospace. Interestingly, the next pass of the compiler is expected to be loaded at the same location as this pass. 38 | * So, the child node pointers in the tree are simply saved directly in the output and are expected to be loaded 39 | * back at the same memory location. 40 | * 41 | * The tree parser also does a rough estimation of how many registers are needed for calculating a tree 42 | * using the Sethi-Ullman algorithm. Additionally, sides of a binary operation can be flipped such that 43 | * the more difficult subtree comes first. See the C compiler tour in the UNIX manual. 44 | */ 45 | main(argc, argv) 46 | char *argv[]; { 47 | if(argc<3) { 48 | error("Arg count"); 49 | exit(1); 50 | } 51 | if(freopen(argv[1], "r", stdin)==NULL) { 52 | error1("Can't find %s", argv[1]); 53 | exit(1); 54 | } 55 | if((fout=fopen(argv[2], "wb"))==NULL) { 56 | error1("Can't create %s", argv[2]); 57 | exit(1); 58 | } 59 | 60 | init("int", 0); 61 | init("char", 1); 62 | init("float", 2); 63 | init("double", 3); 64 | /* init("long", 4); */ 65 | init("auto", 5); 66 | init("extern", 6); 67 | init("static", 7); 68 | init("goto", 10); 69 | init("return", 11); 70 | init("if", 12); 71 | init("while", 13); 72 | init("else", 14); 73 | init("switch", 15); 74 | init("case", 16); 75 | init("break", 17); 76 | init("continue", 18); 77 | init("do", 19); 78 | init("default", 20); 79 | while(!eof) { 80 | extdef(); 81 | blkend(); 82 | } 83 | fflush(stdout); 84 | 85 | exit(nerror!=0); 86 | } 87 | 88 | /* 89 | * Looks up an element in the hash table. The key is in symbuf. 90 | * Returns a pointer to the 4 word long data section. 91 | * Following these 4 words, another 4 words contain the key. 92 | */ 93 | int *lookup() { 94 | auto i, j, *np, *sp, *rp; 95 | 96 | i = 0; 97 | sp = symbuf; 98 | j = nwps; 99 | while(j--) 100 | i += *sp++; 101 | if (i<0) i = -i; 102 | i %= hshsiz; /* the hash of symbuf */ 103 | 104 | i *= pssiz; 105 | while(*(np = &hshtab[i+4])) { 106 | sp = symbuf; 107 | j = nwps; 108 | while(j--) 109 | if (*np++ != *sp++) goto no; /* key does not match, go to next one */ 110 | return(&hshtab[i]); 111 | no: if ((i += pssiz) >= hshlen) i = 0; 112 | } 113 | 114 | /* not found, add new element */ 115 | if(hshused++ > hshsiz) { 116 | error("Symbol table overflow"); 117 | exit(1); 118 | } 119 | rp = np = &hshtab[i]; 120 | sp = symbuf; 121 | j = 4; 122 | while(j--) /* clear out data */ 123 | *np++ = 0; 124 | j = nwps; 125 | while(j--) /* copy key into &hshtab[i+4] */ 126 | *np++ = *sp++; 127 | return(rp); 128 | } 129 | 130 | /* 131 | * The lexer, returns the opcode of the next symbol. If the caller does not want to use the symbol, 132 | * it can "push it back" using the peeksym global variable. 133 | * 134 | * The return value is the opcode of the current symbol. See c0t.c for the mapping between 135 | * the symbols and numbers. 136 | * If the current symbol is a number/character literal, the cval variable is set to the numeric value. 137 | * If the current symbol is a string, cval contains its label. 138 | * If the current symbol is a keyword, cval contains its id. 139 | * If the current symbol is a name, csym will point to the corresponding entry in the hashtable. 140 | * See csym comments at the bottom for its contents. 141 | */ 142 | symbol() { 143 | auto b, c; 144 | char *sp; 145 | 146 | if (peeksym>=0) { /* if we have a peeked symbol, return that */ 147 | c = peeksym; 148 | peeksym = -1; 149 | return(c); 150 | } 151 | if (peekc) { /* use peeked character, if has one */ 152 | c = peekc; 153 | peekc = 0; 154 | } else 155 | if (eof) 156 | return(0); else 157 | c = getchar(); 158 | loop: 159 | switch(ctab[c]) { 160 | 161 | case 125: /* newline */ 162 | line++; 163 | 164 | case 126: /* white space */ 165 | c = getchar(); 166 | goto loop; 167 | 168 | case 0: /* EOF */ 169 | eof++; 170 | return(0); 171 | 172 | case 40: /* + */ 173 | return(subseq(c,40,30)); 174 | 175 | case 41: /* - */ 176 | return(subseq(c,41,31)); 177 | 178 | case 80: /* = */ 179 | if (subseq(' ',0,1)) return(80); 180 | c = symbol(); 181 | if (c>=40 & c<=49) /* c is binary operator */ 182 | return(c+30); 183 | if (c==80) /* = */ 184 | return(60); 185 | peeksym = c; 186 | return(80); 187 | 188 | case 63: /* < */ 189 | if (subseq(c,0,1)) return(46); 190 | return(subseq('=',63,62)); 191 | 192 | case 65: /* > */ 193 | if (subseq(c,0,1)) return(45); 194 | return(subseq('=',65,64)); 195 | 196 | case 34: /* ! */ 197 | return(subseq('=',34,61)); 198 | 199 | case 43: /* / */ 200 | if (subseq('*',1,0)) 201 | return(43); 202 | com: 203 | /* inside a comment */ 204 | c = getchar(); 205 | com1: 206 | if (c=='\0') { 207 | eof++; 208 | error("Nonterminated comment"); 209 | return(0); 210 | } 211 | if (c=='\n') 212 | line++; 213 | if (c!='*') 214 | goto com; 215 | c = getchar(); 216 | if (c!='/') 217 | goto com1; 218 | c = getchar(); 219 | goto loop; 220 | 221 | case 124: /* number */ 222 | cval = 0; 223 | if (c=='0') 224 | b = 8; else 225 | b = 10; 226 | while(ctab[c]==124) { 227 | cval = cval*b + c -'0'; 228 | c = getchar(); 229 | } 230 | peekc = c; 231 | return(21); 232 | 233 | case 122: /* " */ 234 | return(getstr()); 235 | 236 | case 121: /* ' */ 237 | return(getcc()); 238 | 239 | case 123: /* letter */ 240 | sp = symbuf; 241 | while(ctab[c]==123 | ctab[c]==124) { /* while c is alphanumeric */ 242 | if (sp<((char *)symbuf)+namsiz) *sp++ = c; 243 | c = getchar(); 244 | } 245 | while(sp<((char *)symbuf)+namsiz) 246 | *sp++ = '\0'; 247 | peekc = c; 248 | csym = lookup(); /* find in hashtable */ 249 | if (csym[0]==1) { /* keyword */ 250 | cval = csym[1]; 251 | return(19); 252 | } 253 | return(20); 254 | 255 | case 127: /* unknown */ 256 | error("Unknown character"); 257 | c = getchar(); 258 | goto loop; 259 | 260 | } 261 | return(ctab[c]); 262 | } 263 | 264 | /* 265 | * Peeks at the next char and if it is c then eats it and returns b, otherwise returns a. 266 | * Useful for two character symbols, e.g. distinguish between ! and = 267 | * call subseq('=', note_equal_code, logical_not_code). 268 | */ 269 | subseq(c,a,b) { 270 | if (!peekc) 271 | peekc = getchar(); 272 | if (peekc != c) 273 | return(a); 274 | peekc = 0; 275 | return(b); 276 | } 277 | 278 | /* 279 | * Gets a string. It assumes the opening quotation mark has been already processed. 280 | */ 281 | getstr() { 282 | auto c; 283 | 284 | printf(".data;l%d:.byte ", cval=isn++); 285 | while((c=mapch('"')) >= 0) 286 | printf("%o,", c); 287 | printf("0;.even;.text\n"); 288 | return(22); 289 | } 290 | 291 | /* 292 | * Reads a character literal. Assumes opening ' has been read already. 293 | */ 294 | getcc() 295 | { 296 | auto c, cc; 297 | char *cp; 298 | 299 | cval = 0; 300 | cp = &cval; 301 | cc = 0; 302 | while((c=mapch('\'')) >= 0) 303 | if(cc++ < ncpw) 304 | *cp++ = c; 305 | if(cc>ncpw) 306 | error("Long character constant"); 307 | return(21); 308 | } 309 | 310 | 311 | /* 312 | * Processes a character from a string/character literal. c contains the delimiter char. 313 | * This function handles mapping of escape sequences. 314 | */ 315 | mapch(c) 316 | { 317 | auto a; 318 | 319 | if((a=getchar())==c) 320 | return(-1); 321 | switch(a) { 322 | 323 | case '\n': 324 | case 0: 325 | error("Nonterminated string"); 326 | peekc = a; 327 | return(-1); 328 | 329 | case '\\': 330 | switch (a=getchar()) { 331 | 332 | case 't': 333 | return('\t'); 334 | 335 | case 'n': 336 | return('\n'); 337 | 338 | case '0': 339 | return('\0'); 340 | 341 | case 'r': 342 | return('\r'); 343 | 344 | case '\n': 345 | line++; 346 | return('\n'); 347 | } 348 | 349 | } 350 | return(a); 351 | } 352 | 353 | /* 354 | * Builds an expression tree. The outline of the algorithm: 355 | * There are three stacks: 356 | * cmst - tree node stack, contains the partially built parts of the expression tree. 357 | * opst - operator stack, contains the ids of the operators. The bottom element is the EOF operator 358 | * prst - precedence stack, contains the precedences of operators. Note that the precedence stack only contains 359 | * element, if the precedence has increased, so it is not in one-to-one correspondence with opst. 360 | * 361 | * The algorithm goes over the operator produced by the symbol function. Leaf nodes (numbers, 362 | * string/char literals, names) are placed on the node stack. If an operator is encountered, 363 | * it is placed on the operator stack if its precedence is higher than the current precedence. 364 | * Otherwise, the operator and tree node stack is unwinded by building partial subtrees, 365 | * until the top of the prst is smaller than current operator's precedence. 366 | */ 367 | tree() { 368 | auto *op, opst[20], *pp, prst[20], andflg, o, 369 | p, ps, os; 370 | 371 | space = ospace; 372 | op = opst; /* top of operator stack */ 373 | pp = prst; /* top of precedence stack */ 374 | cp = cmst; /* top of tree node stack */ 375 | *op = 200; /* stack EOF */ 376 | *pp = 06; 377 | andflg = 0; 378 | 379 | advanc: 380 | switch (o=symbol()) { 381 | 382 | /* name */ 383 | case 20: 384 | if (*csym==0) /* storage not yet decided */ 385 | if((peeksym=symbol())==6) /* (, mark function calls as extern */ 386 | *csym = 6; /* extern */ 387 | else { 388 | if(csym[2]==0) /* unseen so far */ 389 | csym[2] = isn++; 390 | } 391 | if(*csym==6) /* extern */ 392 | *cp++ = block(5,20,csym[1],0,*csym, 393 | csym[4],csym[5],csym[6],csym[7]); 394 | else 395 | *cp++ = block(2,20,csym[1],0,*csym,csym[2]); 396 | goto tand; 397 | 398 | /* short constant */ 399 | case 21: 400 | case21: 401 | *cp++ = block(1,21,ctyp,0,cval); /* ctyp is always 0 */ 402 | goto tand; 403 | 404 | /* string constant */ 405 | case 22: 406 | *cp++ = block(1,22,17,0,cval); /* 17 is char[] */ 407 | 408 | tand: 409 | if(cp>=cmst+cmsiz) { 410 | error("Expression overflow"); 411 | exit(1); 412 | } 413 | if (andflg) 414 | goto syntax; 415 | andflg = 1; 416 | goto advanc; 417 | 418 | /* ++, -- */ 419 | case 30: 420 | case 31: 421 | if (andflg) /* convert to postfix */ 422 | o += 2; 423 | goto oponst; 424 | 425 | /* ! */ 426 | case 34: 427 | if (andflg) 428 | goto syntax; 429 | goto oponst; 430 | 431 | /* - */ 432 | case 41: 433 | if (!andflg) { 434 | peeksym = symbol(); 435 | if (peeksym==21) { /* negative literal */ 436 | peeksym = -1; 437 | cval = -cval; 438 | goto case21; 439 | } 440 | o = 37; 441 | } 442 | andflg = 0; 443 | goto oponst; 444 | 445 | /* & */ 446 | /* * */ 447 | case 47: 448 | case 42: 449 | if (andflg) 450 | andflg = 0; else 451 | if(o==47) 452 | o = 35; 453 | else 454 | o = 36; 455 | goto oponst; 456 | 457 | /* ( */ 458 | case 6: 459 | if (andflg) { 460 | /* this is a function call */ 461 | o = symbol(); 462 | if (o==7) /* ) */ 463 | o = 101; else { /* 101 - call without args */ 464 | peeksym = o; 465 | o = 100; 466 | andflg = 0; 467 | } 468 | } 469 | goto oponst; 470 | 471 | /* ) */ 472 | /* ] */ 473 | case 5: 474 | case 7: 475 | if (!andflg) 476 | goto syntax; 477 | goto oponst; 478 | } 479 | 480 | /* binary operators */ 481 | if (!andflg) 482 | goto syntax; 483 | andflg = 0; 484 | 485 | oponst: /* place operator on stack */ 486 | p = (opdope[o]>>9) & 077; /* extract operator precedence */ 487 | opon1: 488 | ps = *pp; /* currently highest precedence */ 489 | if (p>ps | p==ps & (opdope[o]&0200)!=0) { /* right-assoc */ 490 | putin: 491 | switch (o) { 492 | 493 | case 6: /* ( */ 494 | case 4: /* [ */ 495 | case 100: /* call */ 496 | p = 04; 497 | } 498 | if(op>=opst+20) { /* 20 is the size of opstack */ 499 | error("expression overflow"); 500 | exit(1); 501 | } 502 | *++op = o; 503 | *++pp = p; 504 | goto advanc; 505 | } 506 | --pp; /* pop precedence stack */ 507 | switch (os = *op--) { 508 | 509 | /* EOF */ 510 | case 200: 511 | peeksym = o; 512 | return(*--cp); 513 | 514 | /* call */ 515 | case 100: 516 | if (o!=7) /* unmatching parenthesis */ 517 | goto syntax; 518 | build(os); 519 | goto advanc; 520 | 521 | /* mcall */ 522 | case 101: 523 | *cp++ = 0; /* 0 arg call */ 524 | os = 100; 525 | goto fbuild; 526 | 527 | /* ( */ 528 | case 6: 529 | if (o!=7) /* unmatching parenthesis */ 530 | goto syntax; 531 | goto advanc; 532 | 533 | /* [ */ 534 | case 4: 535 | if (o!=5) 536 | goto syntax; 537 | build(4); 538 | goto advanc; 539 | } 540 | fbuild: 541 | build(os); 542 | goto opon1; /* unwinds precedence stack till at the same level as o */ 543 | 544 | syntax: 545 | error("Expression syntax"); 546 | errflush(o); 547 | return(0); 548 | } 549 | 550 | /* 551 | * Processes a variable declaration, the preceding type/storage keyword has been processed already. 552 | * kw - the id of the preceding type/storage keyword, 8 for function parameter list. 553 | */ 554 | void declare(kw) { 555 | int o; 556 | 557 | while((o=symbol())==20) { /* name */ 558 | if(kw>=5) { /* type or storage location keyword? */ 559 | if(*csym>0) 560 | error1("%p redeclared", &csym[4]); /* storage area redeclared */ 561 | *csym = kw; 562 | } else { 563 | if ((csym[1]&017)!=0) /* type already defined, adding pointer behavior is allowed */ 564 | error1("%p redeclared", &csym[4]); 565 | csym[1] |= csym[1]&0760 | kw; // set kw to lower 4 bits 566 | if (*csym==0) 567 | *csym = -2; 568 | } 569 | /* add pointer indirection */ 570 | while((o=symbol())==4) { /* [ */ 571 | if((o=symbol())==21) { /* const */ 572 | if(csym[1]>=020) 573 | error("Bad vector"); 574 | csym[3] = cval; 575 | o = symbol(); 576 | } 577 | if (o!=5) /* ] */ 578 | goto syntax; 579 | csym[1] += 020; 580 | } 581 | if(kw==8) { /* parameter */ 582 | *csym = -1; 583 | if (paraml==0) /* paraml points to the first element in the parameter list */ 584 | paraml = csym; 585 | else 586 | *parame = csym; /* set previous parameter's first word to point to the current parameter */ 587 | parame = csym; 588 | } 589 | if (o!=9) /* , */ 590 | break; 591 | } 592 | if(o==1 & kw!=8 | o==7 & kw==8) /* not parameter list and ; or parameter list and ) */ 593 | return; 594 | syntax: 595 | error("Declaration syntax"); 596 | errflush(o); 597 | } 598 | 599 | /* constants for code generator tables */ 600 | regtab = 0; 601 | efftab = 1; 602 | cctab = 2; 603 | sptab = 3; 604 | 605 | /* hash table */ 606 | symbuf[2]; /* buffer for the key to look up in has table. 8 byte long, should be 8/sizeof(int); original value was 4 */ 607 | pssiz = 8; /* size of an entry in the hashtable, should be 4 + nwps */ 608 | namsiz = 8; /* maximum length of the key in bytes */ 609 | nwps = 2; /* number of words per symbuf - originally 4 */ 610 | hshused = 0; /* number of elements in the hash table */ 611 | hshsiz= 100; /* maximum number of elements in the table */ 612 | hshlen =800; /* size of the table in word, equals to pssiz*hshsiz */ 613 | hshtab[800]; /* The hash table for symbols. For eahc entry, the first 4 bytes are the data, the next 4 bytes are the key. */ 614 | 615 | int *space= 0; 616 | int *cp= 0; /* top of the cmst stack */ 617 | cmsiz= 40; /* size of the cmst stack */ 618 | cmst[40]; /* the tree node stack, contains pointers to the nodes*/ 619 | ctyp = 0; /* id of the int type, constant */ 620 | isn = 1; /* current label number */ 621 | swsiz = 120; 622 | swtab[120]; 623 | int *swp = 0; 624 | contlab = 0; /* label for a continue statement in the current loop */ 625 | brklab = 0; /* label for a break statement in the current loop */ 626 | deflab = 0; /* label for a deafult statement in the current switch */ 627 | nreg = 4; /* number of general registers available */ 628 | maprel[]={ 60,61,64,65,62,63,68,69,66,67}; /* maps binary relations to the their flipped pairs */ 629 | nauto = 0; 630 | stack = 0; 631 | peeksym = -1; /* peeked symbol */ 632 | peekc= 0; /* peeked character */ 633 | eof = 0; /* true if reached end of file */ 634 | line = 1; /* current line */ 635 | int *csym = 0; /* current symbol see meaning below */ 636 | cval = 0; // contains the currently read character literal 637 | ncpw = 2; /* number of characters per word */ 638 | nerror = 0; /* number of errors during parsing */ 639 | FILE *fout; /* putchar prints characters to this file */ 640 | int *paraml; /* head of the parameter list */ 641 | int *parame; /* last element in the parameter list */ 642 | 643 | 644 | /* 645 | * csym - current symbol description, points to the corresponding element in the hash table. 646 | * Meaning of the 4 words 647 | * 0 - if 1 then keyword, otherwise storage scope (keyword ID), 8 for function parameters 648 | * -1 (temporary) for function parameters csym[0] forms a linked list, -1 marks the end 649 | * -2 default storage scope (auto) 650 | * 1 - keyword 651 | * 2 - label 652 | * 5 - auto 653 | * 6 - extern 654 | * 7 - static 655 | * 10 - function parameter (set by blkhed) 656 | * 1 - type description 657 | * lower 4 bits contain raw type (char/double/int) 658 | * then 020 is added for every indirection 659 | * e.g. 020 refers to int[] 660 | * 2 - location/label 661 | * in case of parameters/auto the offset from the stack frame 662 | * in case of statics, the label of the variable 663 | * 3 - the length in case of arrays, 0 otherwise 664 | * 4 - the name of the symbol 665 | * 666 | * cval - value in the current symbol 667 | * if number literal - the number 668 | * if char literal - character ascii code 669 | * if keyword - the keyword ID 670 | * if string - the label in the assembly output 671 | */ 672 | -------------------------------------------------------------------------------- /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(op) { 10 | auto *p1, t1, d1, *p2, t2, d2, t; 11 | auto 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; 82 | cvn &= 07; 83 | } else { 84 | t = (cvn&0100)!=0? t2:t1; /* who gets the result */ 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; 94 | if (lr) { /* left argument determines the target type */ 95 | t2 = t; 96 | d2 = (p2=convert(p2, t, d2, cvn))[2]; 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 operation, 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 | /* Creates a node for type conversion */ 127 | int *convert(p, t, d, cvn) 128 | int p[]; 129 | { 130 | auto c; 131 | if (*p==21) { /* constant */ 132 | c = p[3]; 133 | switch(cvn) { 134 | 135 | case 99: /* c18 */ 136 | c <<= 1; 137 | 138 | case 98: /* c14 */ 139 | c <<= 1; 140 | 141 | case 97: /* c12 */ 142 | c <<= 1; 143 | 144 | p[3] = c; 145 | return(p); 146 | } 147 | } 148 | return(block(1, cvn, t, max(1,d), p)); 149 | } 150 | 151 | /* check if p is a word type */ 152 | chkw(p) 153 | int p[]; { 154 | auto t; 155 | 156 | if ((t=p[1])>1 & t<16) 157 | error("Integer operand required"); 158 | } 159 | 160 | /* Compresses type id to one used in cvtable */ 161 | lintyp(t) { 162 | return(t<16? t:(t<32? t-12: 8)); 163 | } 164 | 165 | 166 | error(s) 167 | char s[];{ 168 | error2(s, 0, 0); 169 | } 170 | 171 | error1(s, p1) 172 | char s[];{ 173 | error2(s, p1, 0); 174 | } 175 | 176 | error2(s, p1, p2) 177 | char s[];{ 178 | FILE *f; 179 | 180 | nerror++; 181 | fflush(fout); 182 | f = fout; 183 | fout = stderr; 184 | printf("%d: ", line); 185 | printf(s, p1, p2); 186 | putchar('\n'); 187 | fflush(stderr); 188 | fout = f; 189 | } 190 | 191 | /* 192 | * Creates a new node and appends it to the end of *ospace. The parameters of the node 193 | * are passed after the argument n, which contains the number of optional parameters. 194 | * Each node has 3 mandatory parameters and any number of optional ones. The mandatory parameters: 195 | * op - operator id 196 | * t - type 197 | * d - difficulty, number of registers to calculate the node, or statement difficulty level in c1 198 | * These are followed by the (op dependent) optional parameters, which usually are the subtrees. 199 | */ 200 | int *block(int n, ...) 201 | { 202 | auto *p; 203 | va_list arguments; 204 | 205 | #ifdef DEBUG 206 | va_list dbg_args; 207 | va_start(dbg_args, n); 208 | int op = va_arg(dbg_args, int); 209 | int type = va_arg(dbg_args, int); 210 | int regcnt = va_arg(dbg_args, int); 211 | printf("loc %d: %d t=%d d=%d nump=%d ", space-ospace, op, type, regcnt, n); 212 | for (int i = 0; i < n; ++i) { 213 | int d = va_arg(dbg_args, int); 214 | printf("%d (%d) ", d, (int*)d-ospace); 215 | } 216 | printf("\n"); 217 | va_end(dbg_args); 218 | #endif 219 | 220 | p = space; 221 | va_start(arguments, n); 222 | n += 3; 223 | if(space+n >= ospace+ossiz) { 224 | error("Expression overflow"); 225 | exit(1); 226 | } 227 | while(n--) 228 | *space++ = va_arg(arguments, int); 229 | 230 | va_end(arguments); 231 | return(p); 232 | } 233 | 234 | /* check if p is an lvalue (name or pointer) */ 235 | chklval(p) 236 | int p[]; { 237 | if (*p!=20) 238 | if (*p!=36) 239 | error("Lvalue required"); 240 | } 241 | 242 | max(a, b) 243 | { 244 | if (a>b) 245 | return(a); 246 | return(b); 247 | } 248 | 249 | -------------------------------------------------------------------------------- /src/c02.c: -------------------------------------------------------------------------------- 1 | #include "c0.h" 2 | 3 | /* P 4 | * arses 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 | function(name) 8 | char name[]; { 9 | #ifdef UNIXV5_ABI 10 | printf( ".text; %p:\n", name); 11 | #else 12 | printf( ".data; %p:1f\n.text; 1:", name); 13 | #endif 14 | printf("mov r5,-(sp); mov sp,r5\n"); /* set up stack frame */ 15 | declare(8); /* read parameter list */ 16 | declist(); /* type declarations of parameters */ 17 | 18 | statement(1); 19 | retseq(); 20 | } 21 | 22 | /* Parses the next function/global variable definition. */ 23 | void extdef() { 24 | auto o, c, *cs; 25 | char *s; 26 | 27 | if(((o=symbol())==0) || o==1) /* EOF */ 28 | return; 29 | if(o!=20) /* not a name -> syntax error */ 30 | goto syntax; 31 | csym[0] = 6; 32 | cs = &csym[4]; // name of the symbol 33 | printf(".globl %p\n", cs); 34 | s = ".data; %p:1f\n"; 35 | switch(o=symbol()) { 36 | 37 | case 6: /* ( - function definition*/ 38 | function(cs); 39 | return; 40 | 41 | case 21: /* const - variable has default value*/ 42 | printf(".data; %p: %o\n", cs, cval); 43 | if((o=symbol())!=1) /* ; */ 44 | goto syntax; 45 | return; 46 | 47 | case 1: /* ; */ 48 | printf(".bss; %p: .=.+2\n", cs); /* unitialized variable */ 49 | return; 50 | 51 | case 4: /* [ */ 52 | c = 0; 53 | if((o=symbol())==21) { /* const */ 54 | c = cval<<1; /* multiply by two (number of bytes per word), should be changed for 32bit systems */ 55 | o = symbol(); 56 | } 57 | if(o!=5) /* ] */ 58 | goto syntax; 59 | printf(s, cs); 60 | if((o=symbol())==1) { /* ; */ 61 | printf(".bss; 1:.=.+%o\n", c); 62 | return; 63 | } 64 | /* symbol list, e.g.: 65 | arrname[] 23, 43 ,5; */ 66 | printf("1:"); 67 | while(o==21) { /* const */ 68 | printf("%o\n", cval); 69 | c -= 2; 70 | if((o=symbol())==1) /* ; */ 71 | goto done; 72 | if(o!=9) /* , */ 73 | goto syntax; 74 | else 75 | o = symbol(); 76 | } 77 | goto syntax; 78 | done: 79 | if(c>0) 80 | printf(".=.+%o\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(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 funciton */ 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 | (easystmt()?branch:jump)(o2); /* branch can only jump to a close location */ 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 | (o3?branch: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 | pexpr() 289 | { 290 | auto 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 | pswitch() { 306 | int *sswp, dl, cv, swlab; /* ?, default label, current ?, switch label */ 307 | 308 | sswp = swp; /* save swp */ 309 | if (swp==0) 310 | swp = swtab; 311 | swlab = isn++; 312 | printf("jsr pc,bswitch; l%d\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("%o; l%d\n", cv, *--swp); 325 | } 326 | printf("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 | blkhed() 335 | { 336 | int o, al, pl, *cs, hl; 337 | 338 | declist(); 339 | stack = al = -2; 340 | pl = 4; 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 */ 362 | setstk(al); 363 | defvec(al); 364 | } 365 | cs[2] = al; 366 | al -= rlength(cs[1]); 367 | goto loop; 368 | 369 | /* parameter */ 370 | case 10: 371 | cs[0] = 5; 372 | goto loop; 373 | 374 | /* static */ 375 | case 7: 376 | cs[2] = isn++; 377 | defstat(cs); 378 | goto loop; 379 | 380 | loop:; 381 | } 382 | cs = cs+pssiz; 383 | } 384 | setstk(al); 385 | } 386 | 387 | /* 388 | * Clears all elements from the symbol table, 389 | * except keywords. 390 | */ 391 | blkend() { 392 | auto i, hl; 393 | 394 | i = 0; 395 | hl = hshsiz; 396 | while(hl--) { 397 | if(hshtab[i+4]) 398 | if (hshtab[i]==0) 399 | error1("%p undefined", &hshtab[i+4]); 400 | if(hshtab[i]!=1) { /* not keyword */ 401 | hshused--; 402 | hshtab[i+4] = 0; 403 | } 404 | i += pssiz; 405 | } 406 | } 407 | 408 | /* Throw away symbols until end of statement. */ 409 | errflush(o) { 410 | while(o>3) /* ; { } */ 411 | o = symbol(); 412 | peeksym = o; 413 | } 414 | 415 | /* 416 | * Variable declarations. Either function parameter type declaration 417 | * or function local variable declarations. 418 | */ 419 | declist() 420 | { 421 | auto o; 422 | 423 | while((o=symbol())==19 & cval<10) /* cval<10 means it is a type/storage area definition (int/char/extern/static) */ 424 | declare(cval); 425 | peeksym = o; 426 | } 427 | 428 | /* 429 | * Detects whether the next statement is expected to be small - i.e. not a compound statement 430 | * This usually means it is a single statement or conditional. 431 | * e.g. goto, break, or not a label or block */ 432 | easystmt() 433 | { 434 | if((peeksym=symbol())==20) /* name */ 435 | return(peekc!=':'); /* not label */ 436 | if (peeksym==19) { /* keyword */ 437 | switch(cval) 438 | 439 | case 10: /* goto */ 440 | case 11: /* return */ 441 | case 17: /* break */ 442 | case 18: /* continue */ 443 | return(1); 444 | return(0); 445 | } 446 | return(peeksym!=2); /* { */ 447 | } 448 | 449 | /* Emits a branch instruction */ 450 | branch(lab) 451 | { 452 | printf("br L%d\n", lab); 453 | } 454 | 455 | -------------------------------------------------------------------------------- /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 | jumpc(tree, lbl, cond) 12 | int tree[]; 13 | { 14 | rcexpr(block(1,easystmt()+103,tree,lbl,cond),cctab); 15 | } 16 | 17 | /* 18 | * Prints the binary representation of the tree. 19 | * table - the expression translation table used in the next pass. 20 | */ 21 | rcexpr(tree, table) 22 | int tree[], table; // table: the code generation table 23 | { 24 | int c, *sp; 25 | 26 | putchar('#'); 27 | c = space-ospace; 28 | sp = ospace; 29 | 30 | putwrd(ospace); /* save start of array location (original code expects it to be loaded at the same place */ 31 | putwrd(c); 32 | putwrd(tree); 33 | putwrd(table); 34 | putwrd(line); 35 | while(c--) 36 | putwrd(*sp++); 37 | #ifdef DEBUG 38 | printf("\n"); 39 | #endif 40 | } 41 | 42 | jump(lab) { 43 | printf("jmp\tl%d\n", lab); 44 | } 45 | 46 | label(l) { 47 | printf("l%d:", l); 48 | } 49 | 50 | /* Generates code for a return statement. */ 51 | retseq() { 52 | #ifdef UNIXV5_ABI 53 | printf("mov\tr5,sp\nmov\t(sp)+,r5\nrts\tpc\n"); 54 | #else 55 | printf("jmp\tretrn\n"); 56 | #endif 57 | } 58 | 59 | /* Label for a static variable */ 60 | slabel() { 61 | printf(".data; l%d: 1f; .text; 1:\n", csym[2]); 62 | } 63 | 64 | /* 65 | * Reserves space on the stack. 66 | * a - amount of bytes to add to the stack 67 | */ 68 | void setstk(a) { 69 | auto ts; 70 | 71 | ts = a-stack; /* relative distance */ 72 | stack = a; 73 | switch(ts) { 74 | 75 | case 0: 76 | return; 77 | 78 | case -2: /* -2 */ 79 | printf("tst -(sp)\n"); 80 | return; 81 | 82 | case -4: /* -4 */ 83 | printf("cmp -(sp),-(sp)\n"); 84 | return; 85 | } 86 | printf("add $%o,sp\n", ts); 87 | } 88 | 89 | /* define array on stack, simply saves the pointer to the top of the stack */ 90 | int defvec() { 91 | printf("mov\tsp,r0\nmov\tr0,-(sp)\n"); 92 | stack -= 2; 93 | } 94 | 95 | /* 96 | * Define static variable. 97 | * s - pointer to symbol table entry 98 | */ 99 | defstat(s) 100 | int s[]; { 101 | int len; 102 | 103 | len = length(s[1]); 104 | if (s[3]) /* array */ 105 | printf(".data; l%d:1f; .bss; 1:.=.+%o; .even; .text\n", s[2], 106 | s[3]*len); 107 | else /* scalar */ 108 | printf(".bss; l%d:.=.+%o; .even; .text\n", s[2], len); 109 | } 110 | 111 | /* 112 | * Length of the datatype, t is the type descriptor. 113 | * The id of the type is the id of the keyword + 020 for every indirection 114 | */ 115 | length(t) { 116 | 117 | if (t<0) 118 | t += 020; 119 | if (t>=020) /* array/pointer */ 120 | return(2); 121 | switch(t) { 122 | 123 | case 0: 124 | return(2); 125 | 126 | case 1: 127 | return(1); 128 | 129 | case 2: 130 | return(4); 131 | 132 | case 3: 133 | return(8); 134 | 135 | case 4: 136 | return(4); 137 | 138 | } 139 | return(1024); 140 | } 141 | 142 | /* rounded length */ 143 | rlength(c) { 144 | auto l; 145 | 146 | return((l=length(c))==1? 2: l); 147 | } 148 | 149 | 150 | /* prints the number n in base b */ 151 | printn(n,b) { 152 | auto a; 153 | 154 | if(a=n/b) /* assignment, not test for equality */ 155 | printn(a, b); /* recursive */ 156 | putchar(n%b + '0'); 157 | } 158 | 159 | putwrd(a) { 160 | printf("%d;", a); 161 | } 162 | 163 | cc_putchar(int c) 164 | { 165 | putc(c, fout); 166 | } 167 | 168 | void cc_printf(char *fmt, ...) 169 | { 170 | static char *s; 171 | auto *adx, x, c, *i; 172 | va_list arguments; 173 | 174 | va_start ( arguments, fmt); 175 | loop: 176 | while((c = *fmt++) != '%') { 177 | if(c == '\0') { 178 | va_end(arguments); 179 | return; 180 | } 181 | putchar(c); 182 | } 183 | switch (c = *fmt++) { 184 | 185 | case 'd': /* decimal */ 186 | case 'o': /* octal */ 187 | x = va_arg(arguments, int); 188 | if(x < 0) { 189 | x = -x; 190 | if(x<0) { /* - infinity */ 191 | if(c=='o') 192 | printf("100000"); 193 | else 194 | printf("-32767"); 195 | goto loop; 196 | } 197 | putchar('-'); 198 | } 199 | printn(x, c=='o'?8:10); 200 | goto loop; 201 | 202 | case 's': /* string */ 203 | x = va_arg(arguments, int); 204 | s=x; 205 | while(c = *s++) { 206 | putchar(c); 207 | } 208 | goto loop; 209 | 210 | case 'p': 211 | s =va_arg(arguments, int*); 212 | putchar('_'); 213 | c = namsiz; 214 | while(c--) 215 | if(*s) 216 | putchar(*s++); 217 | goto loop; 218 | } 219 | putchar('%'); 220 | fmt--; 221 | goto loop; 222 | } 223 | 224 | -------------------------------------------------------------------------------- /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, 127, 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 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 | int cvtab[] ={ 129 | 0000, // i:i 130 | 0000, // i:c 131 | 0113, // i:f 132 | 0125, // i:d 133 | 0140, // i:i[] 134 | 0100, // i:c[] 135 | 0150, // i:f[] 136 | 0160, // i:d[] 137 | 0140, // i:[][] 138 | 139 | 0100, // c:i 140 | 0100, // c:c 141 | 0113, // c:f 142 | 0125, // c:d 143 | 0140, // c:i[] 144 | 0100, // c:c[] 145 | 0150, // c:f[] 146 | 0160, // c:d[] 147 | 0140, // c[][] 148 | 149 | 0211, // f:i 150 | 0211, // f:c 151 | 0000, // f:f 152 | 0136, // f:d 153 | 0211, // f:i[] 154 | 0211, // f:c[] 155 | 0211, // f:f[] 156 | 0211, // f:d[] 157 | 0211, // f:[][] 158 | 159 | 0222, // d:i 160 | 0222, // d:c 161 | 0234, // d:f 162 | 0000, // d:d 163 | 0222, // d:i[] 164 | 0222, // d:c[] 165 | 0222, // d:f[] 166 | 0222, // d:d[] 167 | 0222, // d:[][] 168 | 169 | 0240, // i[]:i 170 | 0240, // i[]:c 171 | 0113, // i[]:f 172 | 0125, // i[]:d 173 | 0000, // i[]:i[] 174 | 0000, // i[]:c[] 175 | 0100, // i[]:f[] 176 | 0100, // i[]:d[] 177 | 0100, // i[]:[][] 178 | 179 | 0000, // c[]:i 180 | 0000, // c[]:c 181 | 0113, // c[]:f 182 | 0125, // c[]:d 183 | 0200, // c[]:i[] 184 | 0000, // c[]:c[] 185 | 0200, // c[]:f[] 186 | 0200, // c[]:d[] 187 | 0200, // c[]:[][] 188 | 189 | 0250, // f[]:i 190 | 0250, // f[]:c 191 | 0113, // f[]:f 192 | 0125, // f[]:d 193 | 0000, // f[]:i[] 194 | 0000, // f[]:c[] 195 | 0000, // f[]:f[] 196 | 0100, // f[]:d[] 197 | 0000, // f[]:[][] 198 | 199 | 0260, // d[]:i 200 | 0260, // d[]:c 201 | 0113, // d[]:f 202 | 0125, // d[]:d 203 | 0000, // d[]:i[] 204 | 0000, // d[]:c[] 205 | 0000, // d[]:f[] 206 | 0000, // d[]:d[] 207 | 0000, // d[]:[][] 208 | 209 | 0240, // [][]:i 210 | 0240, // [][]:c 211 | 0113, // [][]:f 212 | 0125, // [][]:d 213 | 0000, // [][]:i[] 214 | 0000, // [][]:c[] 215 | 0100, // [][]:f[] 216 | 0100, // [][]:d[] 217 | 0000, // [][]:[][] 218 | }; -------------------------------------------------------------------------------- /src/c0t.s: -------------------------------------------------------------------------------- 1 | / word I/O 2 | 3 | .globl _putwrd 4 | 5 | .globl _tmpfil 6 | .globl putw 7 | .globl fcreat 8 | .globl flush 9 | 10 | .data 11 | _putwrd: 1f 12 | .text 13 | 1: 14 | tst buf / if tmp file not open 15 | bne 1f 16 | mov _tmpfil,r0 17 | jsr r5,fcreat; buf / open tmpfile 18 | bec 1f 19 | mov $1,r0 / if couldn't open file, print error message 20 | sys write; botch; ebotch-botch 21 | sys exit 22 | 1: 23 | mov 2(sp),r0 24 | jsr r5,putw; buf 25 | rts pc 26 | .globl _flshw 27 | .data 28 | _flshw: 1f 29 | .text 30 | 1: 31 | jsr r5,flush; buf 32 | rts pc 33 | 34 | botch: ; ebotch: 35 | .even 36 | 37 | .bss 38 | buf: .=.+518. 39 | .text 40 | 41 | / C operator and conversion tables 42 | 43 | .globl _opdope 44 | .globl _cvtab 45 | 46 | _opdope:.+2 47 | 00000 / EOF 48 | 00000 / ; 49 | 00000 / { 50 | 00000 / } 51 | 36000 / [ 52 | 02000 / ] 53 | 36000 / ( 54 | 02000 / ) 55 | 14201 / : 56 | 07001 / , 57 | 00000 / 10 58 | 00000 / 11 59 | 00000 / 12 60 | 00000 / 13 61 | 00000 / 14 62 | 00000 / 15 63 | 00000 / 16 64 | 00000 / 17 65 | 00000 / 18 66 | 00000 / 19 67 | 00000 / name 68 | 00000 / short constant 69 | 00000 / string 70 | 00000 / float 71 | 00000 / double 72 | 00000 / 25 73 | 00000 / 26 74 | 00000 / 27 75 | 00000 / 28 76 | 00000 / 29 77 | 34202 / ++pre 78 | 34202 / --pre 79 | 34202 / ++post 80 | 34202 / --post 81 | 34220 / !un 82 | 34202 / &un 83 | 34220 / *un 84 | 34200 / -un 85 | 34220 / ~un 86 | 00000 / 39 87 | 30101 / + 88 | 30001 / - 89 | 32101 / * 90 | 32001 / / 91 | 32001 / % 92 | 26061 / >> 93 | 26061 / << 94 | 20161 / & 95 | 16161 / | 96 | 16161 / ^ 97 | 00000 / 50 98 | 00000 / 51 99 | 00000 / 52 100 | 00000 / 53 101 | 00000 / 54 102 | 00000 / 55 103 | 00000 / 56 104 | 00000 / 57 105 | 00000 / 58 106 | 00000 / 59 107 | 22105 / == 108 | 22105 / != 109 | 24105 / <= 110 | 24105 / < 111 | 24105 / >= 112 | 24105 / > 113 | 24105 /

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

p 139 | 024105, // >=p 140 | 012013, // =+ 141 | 012013, // =- 142 | 012013, // =* 143 | 012013, // =// 144 | 012013, // =% 145 | 012053, // =>> 146 | 012053, // =<< 147 | 012053, // =& 148 | 012053, // =| 149 | 012053, // =^ 150 | 012013, // = 151 | 000000, // 81 152 | 000000, // 82 153 | 000000, // 83 154 | 000000, // int -> float 155 | 000000, // int -> double 156 | 000000, // float -> int 157 | 000000, // float -> double 158 | 000000, // double -> int 159 | 000000, // double -> float 160 | 014001, // ? 161 | 000000, // 91 162 | 000000, // 92 163 | 000000, // 93 164 | 000000, // int -> float 165 | 000000, // int -> double 166 | 000000, // float -> double 167 | 000000, // int -> int[] 168 | 000000, // int -> float[] 169 | 000000, // int -> double[] 170 | 036001, // call 171 | 036001 // mcall 172 | }; -------------------------------------------------------------------------------- /src/c1t.s: -------------------------------------------------------------------------------- 1 | / C operator tables 2 | 3 | .globl _getwrd 4 | 5 | .globl getw 6 | .globl fopen 7 | .globl _tmpfil 8 | 9 | .data 10 | _getwrd: 1f 11 | .text 12 | 1: 13 | tst buf 14 | bne 1f 15 | mov _tmpfil,r0 16 | jsr r5,fopen; buf 17 | bes botchp 18 | 1: 19 | jsr r5,getw; buf 20 | bes botchp 21 | rts pc 22 | botchp: 23 | mov $1,r0 24 | sys write; botch; ebotch-botch 25 | sys exit 26 | botch: 27 | ; ebotch: 28 | .even 29 | .bss 30 | buf: .=.+518. 31 | .text 32 | .globl _opdope 33 | .globl _instab 34 | 35 | _instab:.+2 36 | 40.; 1f; 1f; .data; 1:; .text 37 | 70.; 1b; 1b 38 | 41.; 2f; 2f; .data; 2:; .text 39 | 71.; 2b; 2b 40 | 30.; 3f; 1b; .data; 3:; .text 41 | 31.; 4f; 2b; .data; 4:; .text 42 | 32.; 3b; 1b 43 | 33.; 4b; 2b 44 | 45 | 45.; 2b; 5f; .data; 5:; .text 46 | 46.; 6f; 7f; .data; 6:; 7:<(r4)\0>; .text 47 | 75.; 2b; 5b 48 | 76.; 6b; 7b 49 | 43.; 7b; 1f; .data; 1:; .text 50 | 44.; 5b; 0 51 | 73.; 7b; 1b 52 | 74.; 5b; 0 53 | 54 | 60.; 0f; 1f; .data; 0:; 1:; .text 55 | 61.; 1b; 0b 56 | 62.; 2f; 5f; .data; 2:; 5:; .text 57 | 63.; 3f; 4f; .data; 3:; 4:; .text 58 | 64.; 4b; 3b 59 | 65.; 5b; 2b 60 | 66.; 6f; 9f; .data; 6:; 9:; .text 61 | 67.; 7f; 8f; .data; 7:; 8:; .text 62 | 68.; 8b; 7b 63 | 69.; 9b; 6b 64 | 0 65 | .data 66 | .even 67 | .text 68 | 69 | _opdope:.+2 70 | 00000 / EOF 71 | 00000 / ; 72 | 00000 / { 73 | 00000 / } 74 | 36000 / [ 75 | 02000 / ] 76 | 36000 / ( 77 | 02000 / ) 78 | 02000 / : 79 | 07001 / , 80 | 00000 / 10 81 | 00000 / 11 82 | 00000 / 12 83 | 00000 / 13 84 | 00000 / 14 85 | 00000 / 15 86 | 00000 / 16 87 | 00000 / 17 88 | 00000 / 18 89 | 00000 / 19 90 | 00000 / name 91 | 00000 / short constant 92 | 00000 / string 93 | 00000 / float 94 | 00000 / double 95 | 00000 / 25 96 | 00000 / 26 97 | 00000 / 27 98 | 00000 / 28 99 | 00000 / 29 100 | 34002 / ++pre 101 | 34002 / --pre 102 | 34002 / ++post 103 | 34002 / --post 104 | 34020 / !un 105 | 34002 / &un 106 | 34020 / *un 107 | 34000 / -un 108 | 34020 / ~un 109 | 00000 / 39 110 | 30101 / + 111 | 30001 / - 112 | 32101 / * 113 | 32001 / / 114 | 32001 / % 115 | 26061 / >> 116 | 26061 / << 117 | 20161 / & 118 | 16161 / | 119 | 16161 / ^ 120 | 00000 / 50 121 | 00000 / 51 122 | 00000 / 52 123 | 00000 / 53 124 | 00000 / 54 125 | 00000 / 55 126 | 00000 / 56 127 | 00000 / 57 128 | 00000 / 58 129 | 00000 / 59 130 | 22105 / == 131 | 22105 / != 132 | 24105 / <= 133 | 24105 / < 134 | 24105 / >= 135 | 24105 / > 136 | 24105 /

p 139 | 24105 / >=p 140 | 12013 / =+ 141 | 12013 / =- 142 | 12013 / =* 143 | 12013 / =/ 144 | 12013 / =% 145 | 12053 / =>> 146 | 12053 / =<< 147 | 12053 / =& 148 | 12053 / =| 149 | 12053 / =^ 150 | 12013 / = 151 | 00000 / 81 152 | 00000 / 82 153 | 00000 / 83 154 | 00000 / int -> float 155 | 00000 / int -> double 156 | 00000 / float -> int 157 | 00000 / float -> double 158 | 00000 / double -> int 159 | 00000 / double -> float 160 | 14001 / ? 161 | 00000 / 91 162 | 00000 / 92 163 | 00000 / 93 164 | 00000 / int -> float 165 | 00000 / int -> double 166 | 00000 / float -> double 167 | 00000 / int -> int[] 168 | 00000 / int -> float[] 169 | 00000 / int -> double[] 170 | 36001 / call 171 | 36001 / mcall 172 | -------------------------------------------------------------------------------- /src/cctab.s: -------------------------------------------------------------------------------- 1 | / c code tables-- set condition codes 2 | 3 | .globl _cctab 4 | 5 | _cctab=.;.+2 6 | 20.; rest 7 | 21.; rest 8 | 22.; rest 9 | 30.; rest 10 | 31.; rest 11 | 34.; rest 12 | 35.; rest 13 | 36.; rest 14 | 37.; rest 15 | 40.; rest 16 | 41.; rest 17 | 42.; rest 18 | 43.; rest 19 | 44.; rest 20 | 45.; rest 21 | 46.; rest 22 | 47.; rest 23 | 48.; rest 24 | 60.; cc60 25 | 61.; cc60 26 | 62.; cc60 27 | 63.; cc60 28 | 64.; cc60 29 | 65.; cc60 30 | 66.; cc60 31 | 67.; cc60 32 | 68.; cc60 33 | 69.; cc60 34 | 70.; rest 35 | 71.; rest 36 | 72.; rest 37 | 73.; rest 38 | 74.; rest 39 | 75.; rest 40 | 76.; rest 41 | 77.; rest 42 | 78.; rest 43 | 79.; rest 44 | 80.; rest 45 | 46 | / relationals 47 | cc60: 48 | %a,z 49 | tstB1 A1 50 | 51 | %n*,z 52 | F* 53 | tstB1 #1(R) 54 | 55 | %n,z 56 | F 57 | tst R 58 | 59 | %a,a 60 | cmpBE A1,A2 61 | 62 | %n*,a 63 | F* 64 | cmpBE #1(R),A2 65 | 66 | %n,a 67 | F 68 | cmpB2 R,A2 69 | 70 | %n*,e* 71 | F* 72 | S1* 73 | cmpBE #1(R),#2(R1) 74 | 75 | %n*,e 76 | F* 77 | S1 78 | cmpB1 #1(R),R1 79 | 80 | %n,e* 81 | F 82 | S1* 83 | cmpB2 R,#2(R1) 84 | 85 | %n,e 86 | F 87 | S1 88 | cmp R,R1 89 | 90 | %n*,n* 91 | FS* 92 | S* 93 | cmpBE (sp)+,#2(R) 94 | 95 | %n*,n 96 | FS* 97 | S 98 | cmpB1 *(sp)+,R 99 | 100 | %n,n* 101 | FS 102 | S* 103 | cmpB2 (sp)+,#2(R) 104 | 105 | %n,n 106 | FS 107 | S 108 | cmp (sp)+,R 109 | 110 | / set codes right 111 | rest: 112 | %n,n 113 | H 114 | 115 | .data 116 | .even 117 | .text 118 | 119 | -------------------------------------------------------------------------------- /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 | S K 26 | I M 27 | M N 28 | 29 | * +1 30 | S +2 31 | C +4 32 | 1 +8 33 | 34 | z -> 4 35 | c 10 36 | a 14 37 | e 20 38 | n 63 39 | * +0100 40 | */ 41 | 42 | auto c,snlflg,nlflg,t,smode,m,ssmode; 43 | 44 | /* 45 | * ssmode: next non % should output a data segment header 46 | */ 47 | 48 | smode = nlflg = snlflg = ssmode = 0; 49 | loop: 50 | c = getc(); 51 | if (c!='\n' & c!='\t') nlflg = 0; 52 | if (ssmode!=0 & c!='%') { 53 | ssmode = 0; 54 | printf(".data\n1: .ascii \""); 55 | } 56 | switch(c) { 57 | 58 | case '\0': 59 | printf(".text; .int 0\n"); 60 | fflush(stdout); 61 | return; 62 | 63 | case ':': 64 | if (!smode) /* convert into pointer */ 65 | printf("=.+4; .int 0"); else /* should be sizeof(int*) */ 66 | putchar(':'); 67 | goto loop; 68 | 69 | case 'A': 70 | if ((c=getc())=='1' | c=='2') { 71 | putchar(c+'A'-'1'); 72 | goto loop; 73 | } 74 | putchar('O'); 75 | peekc = c; 76 | goto loop; 77 | 78 | case 'B': 79 | switch (getc()) { 80 | 81 | case '1': 82 | putchar('C'); 83 | goto loop; 84 | 85 | case '2': 86 | putchar('D'); 87 | goto loop; 88 | 89 | case 'E': 90 | putchar('L'); 91 | goto loop; 92 | 93 | case 'F': 94 | putchar('P'); 95 | goto loop; 96 | } 97 | putchar('?'); 98 | goto loop; 99 | 100 | case 'C': 101 | putchar(getc()+'E'-'1'); 102 | goto loop; 103 | 104 | case 'F': 105 | putchar('G'); 106 | goto subtre; 107 | 108 | case 'R': 109 | if ((c=getc()) == '1') 110 | putchar('J'); else { 111 | putchar('I'); 112 | peekc = c; 113 | } 114 | goto loop; 115 | 116 | case 'H': 117 | putchar('H'); 118 | goto subtre; 119 | 120 | case 'I': 121 | putchar('M'); 122 | goto loop; 123 | 124 | case 'M': 125 | putchar('N'); 126 | snlflg++; 127 | goto loop; 128 | 129 | case 'S': 130 | putchar('K'); 131 | subtre: 132 | snlflg = 1; 133 | t = 'A'; 134 | l1: 135 | switch (c=getc()) { 136 | 137 | case '*': 138 | t++; 139 | goto l1; 140 | 141 | case 'S': 142 | t += 2; 143 | goto l1; 144 | 145 | case 'C': 146 | t += 4; 147 | goto l1; 148 | 149 | case '1': 150 | t += 8; 151 | goto l1; 152 | } 153 | peekc = c; 154 | putchar(t); 155 | goto loop; 156 | 157 | case '#': 158 | if(getc()=='1') 159 | putchar('#'); else 160 | printf("\\\""); 161 | goto loop; 162 | 163 | case '%': 164 | if (smode) 165 | printf(".text;"); 166 | loop1: 167 | switch (c=getc()) { 168 | 169 | case 'a': 170 | m = 16; 171 | t = flag(); 172 | goto pf; 173 | 174 | case ',': 175 | putchar(';'); 176 | goto loop1; 177 | 178 | case 'i': 179 | m = 12; 180 | t = flag(); 181 | goto pf; 182 | case 'z': 183 | m = 4; 184 | t = 0; 185 | goto pf; 186 | 187 | case 'c': 188 | t = 0; 189 | m = 8; 190 | goto pf; 191 | 192 | case 'e': 193 | t = flag(); 194 | m = 20; 195 | goto pf; 196 | 197 | case 'n': 198 | t = flag(); 199 | m = 63; 200 | pf: 201 | if ((c=getc())=='*') 202 | m += 0100; else 203 | peekc = c; 204 | printf(".byte 0%o,0%o", m, t); 205 | goto loop1; 206 | 207 | case '\n': 208 | printf(";.int 1f\n"); 209 | ssmode = 1; 210 | nlflg = 1; 211 | smode = 1; 212 | goto loop; 213 | } 214 | putchar(c); 215 | goto loop1; 216 | 217 | case '\t': 218 | if (nlflg) { 219 | nlflg = 0; 220 | goto loop; 221 | } 222 | putchar('\t'); 223 | goto loop; 224 | 225 | case '\n': 226 | if (!smode) { /* outside optree definition just emit new line */ 227 | putchar('\n'); 228 | goto loop; 229 | } 230 | if (nlflg) { /* empty line, close off optree section */ 231 | nlflg = 0; 232 | printf("\\0\"\n.text\n"); 233 | smode = 0; 234 | goto loop; 235 | } 236 | if (!snlflg) 237 | printf("\\n"); 238 | snlflg = 0; 239 | printf("\"\n.ascii \""); 240 | nlflg = 1; 241 | goto loop; 242 | } 243 | putchar(c); 244 | goto loop; 245 | } 246 | 247 | /* Gets the next character, ignores blocks of codes inside { } */ 248 | getc() { 249 | auto t, ifcnt; 250 | 251 | ifcnt = 0; 252 | gc: 253 | if (peekc) { 254 | t = peekc; 255 | peekc = 0; 256 | } else 257 | t = getchar(); 258 | if (t==0 | t==EOF) 259 | return(0); 260 | if (t=='{') { 261 | ifcnt++; 262 | t = getchar(); 263 | } 264 | if (t=='}') { 265 | t = getc(); 266 | if (--ifcnt==0) 267 | if (t=='\n') 268 | t = getc(); 269 | } 270 | if (ifcnt & nofloat) 271 | goto gc; 272 | return(t); 273 | } 274 | 275 | flag() { 276 | auto c, f; 277 | 278 | f = 0; 279 | l1: 280 | switch(c=getc()) { 281 | 282 | case 'w': /* word */ 283 | f = 1; 284 | goto l1; 285 | 286 | case 'i': 287 | f = 2; 288 | goto l1; 289 | 290 | case 'b': /* byte */ 291 | f = 3; 292 | goto l1; 293 | 294 | case 'f': /* float */ 295 | f = 4; 296 | goto l1; 297 | 298 | case 'd': /* double */ 299 | f = 5; 300 | goto l1; 301 | 302 | case 'p': /* pointer? */ 303 | f += 16; 304 | goto l1; 305 | } 306 | peekc = c; 307 | return(f); 308 | } 309 | 310 | -------------------------------------------------------------------------------- /src/efftab.s: -------------------------------------------------------------------------------- 1 | / c code tables 2 | 3 | .globl _efftab 4 | 5 | _efftab=.;.+2 6 | 30.; ci30 7 | 31.; ci30 8 | 32.; ci30 / same as 30 9 | 33.; ci30 / same as 31 10 | 80.; ci80 11 | 70.; ci70 12 | 71.; ci70 / - like + 13 | 77.; ci77 14 | 78.; ci78 15 | 0 16 | 17 | / ++ prefix 18 | ci30: 19 | %ai,n 20 | %abp,n 21 | %ab,n 22 | IB1 A1 23 | 24 | %aip,n 25 | I' $2,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' $2,#1(R) 36 | 37 | / = 38 | ci80: 39 | %a,z 40 | clrB1 A1 41 | 42 | %n*,z 43 | F* 44 | clrB1 #1(R) 45 | 46 | %a,aw 47 | movB1 A2,A1 48 | 49 | %a,nw* 50 | S* 51 | movB1 #2(R),A1 52 | 53 | %a,n 54 | S 55 | movB1 R,A1 56 | 57 | %n*,aw 58 | F* 59 | movB1 A2,#1(R) 60 | 61 | %n*,ew* 62 | F* 63 | S1* 64 | movB1 #2(R1),#1(R) 65 | 66 | %n*,e 67 | F* 68 | S1 69 | movB1 R1,#1(R) 70 | 71 | %e*,nw* 72 | S* 73 | F1* 74 | movB1 #2(R),#1(R1) 75 | 76 | %e*,n 77 | S 78 | F1* 79 | movB1 R,#1(R1) 80 | 81 | %n*,nw* 82 | FS* 83 | S* 84 | movB1 #2(R),*(sp)+ 85 | 86 | %n*,n 87 | FS* 88 | S 89 | movB1 R,*(sp)+ 90 | 91 | / =| i 92 | ci78: 93 | %a,a 94 | bisBE A2,A1 95 | 96 | %a,n 97 | S 98 | bisB1 R,A1 99 | 100 | %n*,a 101 | F* 102 | bisBE A2,#1(R) 103 | 104 | %e*,n* 105 | S* 106 | F1* 107 | bisBE #2(R),#1(R1) 108 | 109 | %e*,n 110 | S 111 | F1* 112 | bisBE R,#1(R1) 113 | 114 | %n*,e* 115 | F* 116 | S1* 117 | bisBE #2(R1),#1(R) 118 | 119 | %n*,e 120 | F* 121 | S1 122 | bisBE R1,#1(R) 123 | 124 | %n*,n* 125 | FS* 126 | S* 127 | bisBE #2(R),*(sp)+ 128 | 129 | %n*,n 130 | FS* 131 | S 132 | bisBE R,*(sp)+ 133 | 134 | / =& i 135 | ci77: 136 | %a,c 137 | bicB1 $!C2,A1 138 | 139 | %a,n 140 | S 141 | com R 142 | bicB1 R,A1 143 | 144 | %e*,n 145 | S 146 | F1* 147 | com R 148 | bicB1 R,#1(R1) 149 | 150 | %n*,c 151 | F* 152 | bicB1 $!C2,#1(R) 153 | 154 | %n*,e 155 | F* 156 | S1 157 | com R1 158 | bicB1 R1,#1(R) 159 | 160 | %n*,n 161 | FS* 162 | S 163 | com R 164 | bicB1 R,*(sp)+ 165 | 166 | / =+ 167 | ci70: 168 | %aw,aw 169 | I A2,A1 170 | 171 | %aw,nw* 172 | S* 173 | I #2(R),A1 174 | 175 | %aw,n 176 | S 177 | I R,A1 178 | 179 | %ew*,nw* 180 | S* 181 | F1* 182 | I #2(R),#1(R1) 183 | 184 | %a,nw* 185 | S* 186 | movB1 A1,R1 187 | I #2(R),R1 188 | movB1 R1,#2(R) 189 | 190 | %a,n 191 | S 192 | movB1 A1,R1 193 | I R1,R 194 | movB1 R,A1 195 | 196 | %ew*,n 197 | S 198 | F1* 199 | I R,#1(R1) 200 | 201 | %nw*,n 202 | SS 203 | F* 204 | I (sp)+,#1(R) 205 | 206 | %n*,n 207 | SS 208 | F* 209 | movB1 #1(R),R1 210 | I (sp)+,R1 211 | movB1 R1,#1(R) 212 | 213 | .data 214 | .even 215 | 216 | -------------------------------------------------------------------------------- /src/regtab.s: -------------------------------------------------------------------------------- 1 | / c code tables-- compile to register 2 | 3 | fp = 1 / enable floating-point 4 | unixv5 = 0 / unix v5 style abi, extra instructions 5 | 6 | .globl _regtab 7 | 8 | _regtab=.; .+2 9 | 20.; cr20 10 | 21.; cr20 11 | 22.; cr20 12 | 30.; cr30 13 | 31.; cr30 14 | 32.; cr32 15 | 33.; cr32 16 | 34.; cr34 17 | 35.; cr35 18 | 29.; cr29 19 | 36.; cr36 20 | 37.; cr37 21 | 38.; cr38 22 | 101.; cr100 23 | 80.; cr80 24 | 40.; cr40 25 | 41.; cr40 / - like + 26 | 42.; cr42 27 | 43.; cr43 28 | 44.; cr43 29 | 45.; cr45 30 | 46.; cr45 31 | 47.; cr47 32 | 48.; cr48 33 | 60.; cr60 34 | 61.; cr60 35 | 62.; cr60 36 | 63.; cr60 37 | 64.; cr60 38 | 65.; cr60 39 | 66.; cr60 40 | 67.; cr60 41 | 68.; cr60 42 | 69.; cr60 43 | 70.; cr70 44 | 71.; cr70 45 | 72.; cr72 46 | 73.; cr73 47 | 74.; cr73 48 | 75.; cr75 49 | 76.; cr75 50 | 77.; cr77 51 | 78.; cr78 52 | 102.; cr102 53 | 97.; cr97 54 | 0 55 | 56 | / goto 57 | cr102: 58 | %i,n 59 | jmp *A1 60 | 61 | %n*,n 62 | F* 63 | jmp *#1(R) 64 | 65 | %n,n 66 | F 67 | jmp (R) 68 | 69 | / call 70 | .if unixv5 71 | cr100: 72 | %n*,n 73 | F* 74 | jsr pc,#1(R) 75 | 76 | %a,n 77 | jsr pc,A1 78 | 79 | %n,n 80 | F 81 | jsr pc,R 82 | 83 | .else 84 | cr100: 85 | %n*,n 86 | F* 87 | jsr pc,*#1(R) 88 | 89 | %a,n 90 | jsr pc,*A1 91 | 92 | %n,n 93 | F 94 | jsr pc,(R) 95 | 96 | .endif 97 | 98 | / name, constant 99 | cr20: 100 | %z,n 101 | clr R 102 | 103 | %aw,n 104 | mov A,R 105 | 106 | %ab,n 107 | movb A,R 108 | 109 | .if fp 110 | %af,n 111 | M 112 | movf A,R 113 | 114 | .endif 115 | 116 | /++,-- prefix 117 | cr30: 118 | %ai,n 119 | %abp,n 120 | %ab,n 121 | IB1 A1 122 | movB1 A1,R 123 | 124 | %a,n 125 | I' $2,A1 126 | mov A1,R 127 | 128 | %nbp*,n 129 | %ni*,n 130 | %nb*,n 131 | F* 132 | IB1 #1(R) 133 | movB1 #1(R),R 134 | 135 | %n*,n 136 | F* 137 | I' $2,#1(R) 138 | mov #1(R),R 139 | 140 | / ++,-- postfix 141 | cr32: 142 | %ai,n 143 | %abp,n 144 | %ab,n 145 | movB1 A1,R 146 | IB1 A1 147 | 148 | %a,n 149 | mov A1,R 150 | I' $2,A1 151 | 152 | %nbp*,n 153 | %nb*,n 154 | %ni*,n 155 | F* 156 | movB1 #1(R),-(sp) 157 | IB1 #1(R) 158 | movB1 (sp)+,R 159 | 160 | %n*,n 161 | F* 162 | mov #1(R),-(sp) 163 | I' $2,#1(R) 164 | mov (sp)+,R 165 | 166 | / ! 167 | cr34: 168 | %n,n 169 | FC 170 | beq 1f 171 | clr R 172 | br 2f 173 | 1: mov $1,R 174 | 2: 175 | 176 | / &unary 177 | cr35: 178 | %a,n 179 | mov $A1,R 180 | 181 | / & unary of auto 182 | cr29: 183 | %e,n 184 | mov r5,R 185 | add Z,R 186 | 187 | / *unary 188 | cr36: 189 | %abp*,n 190 | F 191 | movb (R),R 192 | 193 | %a*,n 194 | F 195 | mov (R),R 196 | 197 | %abp,n 198 | movb *A1,R 199 | 200 | %a,n 201 | mov *A1,R 202 | 203 | %nbp*,n 204 | F* 205 | movb *#1(R),R 206 | 207 | %n*,n 208 | F* 209 | mov *#1(R),R 210 | 211 | %nbp,n 212 | H* 213 | movb ~(R),R 214 | 215 | %n,n 216 | H* 217 | mov ~(R),R 218 | 219 | / - unary 220 | cr37: 221 | %n,n 222 | F 223 | neg R 224 | 225 | / ~ 226 | cr38: 227 | %n,n 228 | F 229 | com R 230 | 231 | / = 232 | cr80: 233 | %a,n 234 | S 235 | movB1 R,A1 236 | 237 | %n*,a 238 | F* 239 | movB1 A2,#1(R) 240 | movB1 #1(R),R 241 | 242 | %n*,e 243 | F* 244 | S1 245 | movB1 R1,#1(R) 246 | mov R1,R 247 | 248 | %n*,n 249 | FS* 250 | S 251 | movB1 R,*(sp)+ 252 | 253 | / | 254 | cr48: 255 | %n,a 256 | F 257 | bisB2 A2,R 258 | 259 | %n,e* 260 | F 261 | S1* 262 | bisB2 #2(R1),R 263 | 264 | %n,e 265 | F 266 | S1 267 | bis R1,R 268 | 269 | %n,n 270 | FS 271 | S 272 | bis (sp)+,R 273 | 274 | / & 275 | cr47: 276 | %n,c 277 | F 278 | bic $!C2,R 279 | 280 | %n,e 281 | F 282 | S1 283 | com R1 284 | bic R1,R 285 | 286 | %n,n 287 | FS 288 | S 289 | com (sp) 290 | bic (sp)+,R 291 | 292 | / relationals 293 | cr60: 294 | %n,n 295 | HC 296 | I 2f 297 | clr R 298 | br 1f 299 | 2: mov $1,R 300 | 1: 301 | 302 | / >>, << 303 | cr45: 304 | %a,aw 305 | movB1 A1,I' 306 | I A2,lsh 307 | movB1 I',R 308 | 309 | %n*,aw 310 | F* 311 | movB1 #1(R),I' 312 | I A2,lsh 313 | movB1 I',R 314 | 315 | %n,aw 316 | F 317 | mov R,I' 318 | I A2,lsh 319 | mov I',R 320 | 321 | %a,nw* 322 | S* 323 | movB1 A1,(r4) 324 | I #2(R),lsh 325 | mov (r4),R 326 | 327 | %a,n 328 | S 329 | movB1 A1,I' 330 | I R,lsh 331 | mov I',R 332 | 333 | %n,n 334 | FS 335 | S 336 | mov (sp)+,I' 337 | I R,lsh 338 | mov I',R 339 | 340 | / +, - 341 | cr40: 342 | %n,aw 343 | F 344 | I A2,R 345 | 346 | %n,ew* 347 | F 348 | S1* 349 | I #2(R1),R 350 | 351 | %n,e 352 | F 353 | S1 354 | I R1,R 355 | 356 | %n,nw* 357 | SS* 358 | F 359 | I *(sp)+,R 360 | 361 | %n,n 362 | SS 363 | F 364 | I (sp)+,R 365 | 366 | / * 367 | cr42: 368 | %aw,a 369 | mov A1,(r4)+ 370 | movB2 A2,(r4) 371 | mov -(r4),R 372 | 373 | %n,a 374 | F 375 | mov R,(r4)+ 376 | movB2 A2,(r4) 377 | mov -(r4),R 378 | 379 | %n,e 380 | F 381 | S1 382 | mov R,(r4)+ 383 | mov R1,(r4) 384 | mov -(r4),R 385 | 386 | %n,n 387 | FS 388 | S 389 | mov (sp)+,(r4)+ 390 | mov R,(r4) 391 | mov -(r4),R 392 | 393 | / /; mod 394 | cr43: 395 | .if unixv5 396 | %a,a 397 | mov r5, -(sp) 398 | movB1 A1,r5 399 | mov $0, r4 400 | div A2,r4 401 | mov r5, R 402 | mov (sp)+,r5 403 | 404 | %n,n 405 | FS 406 | S 407 | mov r5, -(sp) 408 | mov $0, r4 409 | mov 2(sp), r5 410 | div R, r4 411 | mov r5, R 412 | mov (sp)+,r5 413 | tst (sp)+ 414 | 415 | .else 416 | %a,a 417 | movB1 A1,(r4) 418 | movB2 A2,div 419 | mov I,R 420 | 421 | %a,n 422 | S 423 | movB1 A1,(r4) 424 | mov R,div 425 | mov I,R 426 | 427 | %n,a 428 | F 429 | mov R,(r4) 430 | movB2 A2,div 431 | mov I,R 432 | 433 | %n,e 434 | F 435 | S1 436 | mov R,(r4) 437 | mov R1,div 438 | mov I,R 439 | 440 | %e,n 441 | S 442 | F1 443 | mov R1,(r4) 444 | mov R,div 445 | mov I,R 446 | 447 | %n,n 448 | FS 449 | S 450 | mov (sp)+,(r4) 451 | mov R,div 452 | mov I,R 453 | 454 | .endif 455 | 456 | / =* 457 | cr72: 458 | %a,a 459 | movB1 A1,(r4) 460 | movB2 A2,mul 461 | movB1 (r4),A1 462 | mov (r4),R 463 | 464 | %a,n 465 | S 466 | mov R,(r4)+ 467 | movB1 A1,(r4) 468 | mov -(r4),R 469 | movB1 R,A1 470 | 471 | %n*,a 472 | F* 473 | movB1 #1(R),(r4) 474 | movB2 A2,mul 475 | movB1 (r4),#1(R) 476 | mov (r4),R 477 | 478 | %n*,e 479 | F* 480 | S1 481 | movB1 #1(R),(r4) 482 | mov R1,mul 483 | movB1 (r4),#1(R) 484 | mov (r4),R 485 | 486 | %e*,n 487 | S 488 | F1* 489 | movB1 #1(R1),(r4) 490 | mov R,mul 491 | movB1 (r4),#1(R1) 492 | mov (r4),R 493 | 494 | %n*,n 495 | FS* 496 | S 497 | movB1 *(sp),(r4) 498 | mov R,mul 499 | movB1 (r4),*(sp)+ 500 | mov (r4),R 501 | 502 | / =mod, =/ 503 | cr73: 504 | %a,a 505 | movB1 A1,(r4) 506 | movB2 A2,div 507 | movB1 I,A1 508 | mov I,R 509 | 510 | %a,n 511 | S 512 | movB1 A1,(r4) 513 | mov R,div 514 | mov I,R 515 | movB1 R,A1 516 | 517 | %n*,a 518 | F* 519 | movB1 #1(R),(r4) 520 | movB2 A2,div 521 | movB1 I,#1(R) 522 | mov I,R 523 | 524 | %n*,e 525 | F* 526 | S1 527 | movB1 #1(R),(r4) 528 | mov R1,div 529 | movB1 I,#1(R) 530 | mov I,R 531 | 532 | %e*,n 533 | S 534 | F1* 535 | movB1 #1(R1),(r4) 536 | mov R,div 537 | movB1 I,#1(R1) 538 | mov I,R 539 | 540 | %n*,n 541 | FS* 542 | S 543 | movB1 *(sp),(r4) 544 | mov R,div 545 | movB1 I,*(sp)+ 546 | mov I,R 547 | 548 | / =| 549 | cr78: 550 | %a,a 551 | bisBE A2,A1 552 | movB1 A1,R 553 | 554 | %a,n 555 | S 556 | bisB1 R,A1 557 | movB1 A1,R 558 | 559 | %n*,a 560 | F* 561 | bisBE A2,#1(R) 562 | movB1 #1(R),R 563 | 564 | %e*,n* 565 | S* 566 | F1* 567 | bisBE #1(R1),#2(R) 568 | movB1 #2(R),R 569 | 570 | %e*,n 571 | S 572 | F1* 573 | bisBE R,#1(R1) 574 | movB1 #1(R1),R 575 | 576 | %n*,e* 577 | F* 578 | S1* 579 | bisBE #2(R1),#1(R) 580 | movB1 #1(R),R 581 | 582 | %n*,e 583 | F* 584 | S1 585 | bisBE R1,#1(R) 586 | movB2 #1(R),R 587 | 588 | %n*,n* 589 | FS* 590 | S* 591 | bisBE #2(R),*(sp) 592 | movB2 *(sp)+,R 593 | 594 | %n*,n 595 | FS* 596 | S 597 | bisBE R,*(sp) 598 | mov *(sp)+,R 599 | 600 | / =& 601 | cr77: 602 | %a,c 603 | bicB1 $!C2,A1 604 | movB2 A1,R 605 | 606 | %a,n 607 | S 608 | com R 609 | bicB1 R,A1 610 | movB1 A1,R 611 | 612 | %e*,n 613 | S 614 | F1* 615 | com R 616 | bicB1 R,#1(R1) 617 | movB1 #1(R1),R 618 | 619 | %n*,e 620 | F* 621 | S1 622 | com R1 623 | bicB1 R1,#1(R) 624 | movB1 #1(R),R 625 | 626 | %n*,n 627 | FS* 628 | S 629 | com R 630 | bicB1 R,*(sp) 631 | movB1 *(sp)+,R 632 | 633 | / =>>, =<< 634 | cr75: 635 | %a,aw 636 | movB1 A1,I' 637 | I A2,lsh 638 | movB1 I',A1 639 | movB1 I',R 640 | 641 | %a,n 642 | S 643 | movB1 A1,I' 644 | I R,lsh 645 | movB1 I',A1 646 | movB1 I',R 647 | 648 | %n*,e 649 | F* 650 | S1 651 | movB1 #1(R),I' 652 | I R1,lsh 653 | movB1 I',#1(R) 654 | movB1 I',R 655 | 656 | %e*,n 657 | S 658 | F1* 659 | movB1 #1(R1),I' 660 | I R,lsh 661 | movB I',#1(R1) 662 | movB1 I',R 663 | 664 | %n*,n 665 | FS* 666 | S 667 | movB1 *(sp),I' 668 | I R,lsh 669 | movB1 I',*(sp)+ 670 | movB1 I',R 671 | 672 | / =+ 673 | cr70: 674 | %aw,aw 675 | I A2,A1 676 | mov A1,R 677 | 678 | %aw,nw* 679 | S* 680 | I #2(R),A1 681 | mov A1,R 682 | 683 | %aw,n 684 | S 685 | I R,A1 686 | mov A1,R 687 | 688 | %ew*,nw* 689 | S* 690 | F1* 691 | I #2(R),#1(R1) 692 | mov #1(R1),R 693 | 694 | %a,nw* 695 | S* 696 | movB1 A1,R1 697 | I #2(R),R1 698 | movB1 R1,#2(R) 699 | mov R1,R 700 | 701 | %a,n 702 | S 703 | movB1 A1,R1 704 | I R1,R 705 | movB1 R,A1 706 | 707 | %ew*,n 708 | S 709 | F1* 710 | I R,#1(R1) 711 | mov #1(R1),R 712 | 713 | %nw*,n 714 | SS 715 | F* 716 | I (sp)+,#1(R) 717 | mov #1(R),R 718 | 719 | %n*,n 720 | SS 721 | F* 722 | movB1 #1(R),R1 723 | I (sp)+,R1 724 | movB1 R1,#1(R) 725 | mov R1,R 726 | 727 | / int -> int[] 728 | cr97: 729 | %n,n 730 | F 731 | asl R 732 | 733 | .data 734 | .even 735 | .text 736 | 737 | -------------------------------------------------------------------------------- /src/sptab.s: -------------------------------------------------------------------------------- 1 | / c code tables-- expression to -(sp) 2 | 3 | .globl _sptab 4 | 5 | _sptab=.;.+2 6 | 20.; cs20 7 | 21.; cs21 8 | 22.; cs21 9 | 30.; cs30 10 | 31.; cs30 11 | 32.; cs32 12 | 33.; cs32 13 | 35.; cs35 14 | 36.; cs36 15 | 40.; cs40 16 | 41.; cs40 17 | 42.; cs42 18 | 47.; cs47 19 | 48.; cs48 20 | 0 21 | 22 | 23 | / name 24 | cs20: 25 | %aw,n 26 | mov A,-(sp) 27 | 28 | / constant 29 | cs21: 30 | %z,n 31 | clr -(sp) 32 | 33 | %a,n 34 | mov A,-(sp) 35 | 36 | / ++,-- prefix 37 | cs30: 38 | %ai,n 39 | %abp,n 40 | I A1 41 | mov A1,-(sp) 42 | 43 | %aw,n 44 | I' $2,A1 45 | mov A1,-(sp) 46 | 47 | %nbp*,n 48 | %ni*,n 49 | F* 50 | I #1(R) 51 | mov #1(R),-(sp) 52 | 53 | %nip*,n 54 | F* 55 | mov #1(R),-(sp) 56 | I' $2,#1(R) 57 | 58 | / ++,-- postfix 59 | cs32: 60 | %ai,n 61 | %abp,n 62 | mov A1,-(sp) 63 | I A1 64 | 65 | %aip,n 66 | mov A1,-(sp) 67 | I' $2,A1 68 | 69 | %nbp*,n 70 | %ni*,n 71 | F* 72 | mov #1(R),-(sp) 73 | I #1(R) 74 | 75 | %nip*,n 76 | F* 77 | mov #1(R),-(sp) 78 | I' $2,#1(R) 79 | 80 | / & unary 81 | cs35: 82 | %i,n 83 | mov $A1,-(sp) 84 | 85 | / * unary 86 | cs36: 87 | %aw,n 88 | mov *A1,-(sp) 89 | 90 | %nw*,n 91 | F* 92 | mov #1(R),-(sp) 93 | 94 | / + 95 | cs40: 96 | %n,aw 97 | FS 98 | I A2,(sp) 99 | 100 | %n,nw* 101 | FS 102 | S* 103 | I #2(R),(sp) 104 | 105 | %n,n 106 | FS 107 | S 108 | I R,(sp) 109 | 110 | / * 111 | cs42: 112 | %aw,a 113 | mov A1,(r4)+ 114 | movB2 A2,(r4) 115 | mov -(r4),-(sp) 116 | 117 | %n,a 118 | F 119 | mov R,(r4)+ 120 | movB2 A2,(r4) 121 | mov -(r4),-(sp) 122 | 123 | %n,nw* 124 | FS 125 | S* 126 | mov (sp)+,(r4)+ 127 | mov #2(R),(r4) 128 | mov -(r4),-(sp) 129 | 130 | %n,n 131 | FS 132 | S 133 | mov (sp)+,(r4)+ 134 | mov R,(r4) 135 | mov -(r4),-(sp) 136 | 137 | / & 138 | cs47: 139 | %n,c 140 | FS 141 | bic $!C2,(sp) 142 | 143 | %n,n 144 | FS 145 | S 146 | com R 147 | bic R,(sp) 148 | 149 | / | 150 | cs48: 151 | %n,a 152 | FS 153 | bisB2 A2,(sp) 154 | 155 | %n,n* 156 | FS 157 | S* 158 | bisB2 #2(R),(sp) 159 | 160 | %n,n 161 | FS 162 | S 163 | bis R,(sp) 164 | 165 | .data 166 | .even 167 | .text 168 | --------------------------------------------------------------------------------