1: # 2: /* C compiler 3: * 4: * 5: * 6: * Called from cc: 7: * c0 source temp1 temp2 [ profileflag ] 8: * temp1 contains some ascii text and the binary expression 9: * trees. Each tree is introduced by the # character. 10: * Strings are put on temp2, which cc tacks onto 11: * temp1 for assembly. 12: */ 13: 14: #include "c0h.c" 15: 16: int isn 1; 17: int stflg 1; 18: int peeksym -1; 19: int line 1; 20: int debug 0; 21: int dimp 0; 22: struct tname funcblk { NAME, 0, 0, REG, 0, 0 }; 23: int *treespace { osspace }; 24: 25: struct kwtab { 26: char *kwname; 27: int kwval; 28: } kwtab[] 29: { 30: "int", INT, 31: "char", CHAR, 32: "float", FLOAT, 33: "double", DOUBLE, 34: "struct", STRUCT, 35: "long", LONG, 36: "auto", AUTO, 37: "extern", EXTERN, 38: "static", STATIC, 39: "register", REG, 40: "goto", GOTO, 41: "return", RETURN, 42: "if", IF, 43: "while", WHILE, 44: "else", ELSE, 45: "switch", SWITCH, 46: "case", CASE, 47: "break", BREAK, 48: "continue", CONTIN, 49: "do", DO, 50: "default", DEFAULT, 51: "for", FOR, 52: "sizeof", SIZEOF, 53: 0, 0, 54: }; 55: 56: main(argc, argv) 57: char *argv[]; 58: { 59: extern fin; 60: register char *sp; 61: register i; 62: register struct kwtab *ip; 63: 64: if(argc<3) { 65: error("Arg count"); 66: exit(1); 67: } 68: if((fin=open(argv[1],0))<0) { 69: error("Can't find %s", argv[1]); 70: exit(1); 71: } 72: if (fcreat(argv[2], obuf)<0 || fcreat(argv[3], sbuf)<0) { 73: error("Can't create temp"); 74: exit(1); 75: } 76: if (argc>4) 77: proflg++; 78: /* 79: * The hash table locations of the keywords 80: * are marked; if an identifier hashes to one of 81: * these locations, it is looked up in in the keyword 82: * table first. 83: */ 84: for (ip=kwtab; (sp = ip->kwname); ip++) { 85: i = 0; 86: while (*sp) 87: i =+ *sp++; 88: hshtab[i%hshsiz].hflag = FKEYW; 89: } 90: while(!eof) { 91: extdef(); 92: blkend(); 93: } 94: outcode("B", EOF); 95: strflg++; 96: outcode("B", EOF); 97: fflush(obuf); 98: fflush(sbuf); 99: exit(nerror!=0); 100: } 101: 102: /* 103: * Look up the identifier in symbuf in the symbol table. 104: * If it hashes to the same spot as a keyword, try the keyword table 105: * first. An initial "." is ignored in the hash. 106: * Return is a ptr to the symbol table entry. 107: */ 108: lookup() 109: { 110: int ihash; 111: register struct hshtab *rp; 112: register char *sp, *np; 113: 114: ihash = 0; 115: sp = symbuf; 116: if (*sp=='.') 117: sp++; 118: while (sp<symbuf+ncps) 119: ihash =+ *sp++; 120: rp = &hshtab[ihash%hshsiz]; 121: if (rp->hflag&FKEYW) 122: if (findkw()) 123: return(KEYW); 124: while (*(np = rp->name)) { 125: for (sp=symbuf; sp<symbuf+ncps;) 126: if (*np++ != *sp++) 127: goto no; 128: csym = rp; 129: return(NAME); 130: no: 131: if (++rp >= &hshtab[hshsiz]) 132: rp = hshtab; 133: } 134: if(++hshused >= hshsiz) { 135: error("Symbol table overflow"); 136: exit(1); 137: } 138: rp->hclass = 0; 139: rp->htype = 0; 140: rp->hoffset = 0; 141: rp->dimp = 0; 142: rp->hflag =| xdflg; 143: sp = symbuf; 144: for (np=rp->name; sp<symbuf+ncps;) 145: *np++ = *sp++; 146: csym = rp; 147: return(NAME); 148: } 149: 150: /* 151: * Search the keyword table. 152: * Ignore initial "." to avoid member-of-structure 153: * problems. 154: */ 155: findkw() 156: { 157: register struct kwtab *kp; 158: register char *p1, *p2; 159: char *wp; 160: 161: wp = symbuf; 162: if (*wp=='.') 163: wp++; 164: for (kp=kwtab; (p2 = kp->kwname); kp++) { 165: p1 = wp; 166: while (*p1 == *p2++) 167: if (*p1++ == '\0') { 168: cval = kp->kwval; 169: return(1); 170: } 171: } 172: return(0); 173: } 174: 175: 176: /* 177: * Return the next symbol from the input. 178: * peeksym is a pushed-back symbol, peekc is a pushed-back 179: * character (after peeksym). 180: * mosflg means that the next symbol, if an identifier, 181: * is a member of structure or a structure tag, and it 182: * gets a "." prepended to it to distinguish 183: * it from other identifiers. 184: */ 185: symbol() { 186: register c; 187: register char *sp; 188: 189: if (peeksym>=0) { 190: c = peeksym; 191: peeksym = -1; 192: if (c==NAME) 193: mosflg = 0; 194: return(c); 195: } 196: if (peekc) { 197: c = peekc; 198: peekc = 0; 199: } else 200: if (eof) 201: return(EOF); 202: else 203: c = getchar(); 204: loop: 205: switch(ctab[c]) { 206: 207: case INSERT: /* ignore newlines */ 208: inhdr = 1; 209: c = getchar(); 210: goto loop; 211: 212: case NEWLN: 213: if (!inhdr) 214: line++; 215: inhdr = 0; 216: 217: case SPACE: 218: c = getchar(); 219: goto loop; 220: 221: case EOF: 222: eof++; 223: return(0); 224: 225: case PLUS: 226: return(subseq(c,PLUS,INCBEF)); 227: 228: case MINUS: 229: return(subseq(c,subseq('>',MINUS,ARROW),DECBEF)); 230: 231: case ASSIGN: 232: if (subseq(' ',0,1)) return(ASSIGN); 233: c = symbol(); 234: if (c>=PLUS && c<=EXOR) { 235: if (spnextchar() != ' ' 236: && (c==MINUS || c==AND || c==TIMES)) { 237: error("Warning: assignment operator assumed"); 238: nerror--; 239: } 240: return(c+ASPLUS-PLUS); 241: } 242: if (c==ASSIGN) 243: return(EQUAL); 244: peeksym = c; 245: return(ASSIGN); 246: 247: case LESS: 248: if (subseq(c,0,1)) return(LSHIFT); 249: return(subseq('=',LESS,LESSEQ)); 250: 251: case GREAT: 252: if (subseq(c,0,1)) return(RSHIFT); 253: return(subseq('=',GREAT,GREATEQ)); 254: 255: case EXCLA: 256: return(subseq('=',EXCLA,NEQUAL)); 257: 258: case DIVIDE: 259: if (subseq('*',1,0)) 260: return(DIVIDE); 261: while ((c = spnextchar()) != EOF) { 262: peekc = 0; 263: if (c=='*') { 264: if (spnextchar() == '/') { 265: peekc = 0; 266: c = getchar(); 267: goto loop; 268: } 269: } 270: } 271: eof++; 272: error("Nonterminated comment"); 273: return(0); 274: 275: case PERIOD: 276: case DIGIT: 277: peekc = c; 278: if ((c=getnum(c=='0'?8:10)) == FCON) 279: cval = isn++; 280: return(c); 281: 282: case DQUOTE: 283: return(getstr()); 284: 285: case SQUOTE: 286: return(getcc()); 287: 288: case LETTER: 289: sp = symbuf; 290: if (mosflg) { 291: *sp++ = '.'; 292: mosflg = 0; 293: } 294: while(ctab[c]==LETTER || ctab[c]==DIGIT) { 295: if (sp<symbuf+ncps) *sp++ = c; 296: c = getchar(); 297: } 298: while(sp<symbuf+ncps) 299: *sp++ = '\0'; 300: peekc = c; 301: if ((c=lookup())==KEYW && cval==SIZEOF) 302: c = SIZEOF; 303: return(c); 304: 305: case AND: 306: return(subseq('&', AND, LOGAND)); 307: 308: case OR: 309: return(subseq('|', OR, LOGOR)); 310: 311: case UNKN: 312: error("Unknown character"); 313: c = getchar(); 314: goto loop; 315: 316: } 317: return(ctab[c]); 318: } 319: 320: /* 321: * If the next input character is c, return a and advance. 322: * Otherwise push back the character and return a. 323: */ 324: subseq(c,a,b) 325: { 326: if (spnextchar() != c) 327: return(a); 328: peekc = 0; 329: return(b); 330: } 331: 332: /* 333: * Read a double-quoted string, placing it on the 334: * string buffer. 335: */ 336: getstr() 337: { 338: register int c; 339: register char *sp; 340: 341: nchstr = 1; 342: sp = savstr; 343: while((c=mapch('"')) >= 0) { 344: nchstr++; 345: if (sp >= &savstr[STRSIZ]) { 346: sp = savstr; 347: error("String too long"); 348: } 349: *sp++ = c; 350: } 351: strptr = sp; 352: cval = isn++; 353: return(STRING); 354: } 355: 356: /* 357: * Write out a string, either in-line 358: * or in the string temp file labelled by 359: * lab. 360: */ 361: putstr(lab) 362: { 363: register char *sp; 364: 365: if (lab) { 366: strflg++; 367: outcode("BNB", LABEL, lab, BDATA); 368: } else 369: outcode("B", BDATA); 370: for (sp = savstr; sp<strptr; ) 371: outcode("1N", *sp++ & 0377); 372: outcode("100"); 373: strflg = 0; 374: } 375: 376: /* 377: * read a single-quoted character constant. 378: * The routine is sensitive to the layout of 379: * characters in a word. 380: */ 381: getcc() 382: { 383: register int c, cc; 384: register char *ccp; 385: 386: cval = 0; 387: ccp = &cval; 388: cc = 0; 389: while((c=mapch('\'')) >= 0) 390: if(cc++ < NCPW) 391: *ccp++ = c; 392: if(cc>NCPW) 393: error("Long character constant"); 394: return(CON); 395: } 396: 397: /* 398: * Read a character in a string or character constant, 399: * detecting the end of the string. 400: * It implements the escape sequences. 401: */ 402: mapch(ac) 403: { 404: register int a, c, n; 405: static mpeek; 406: 407: c = ac; 408: if (a = mpeek) 409: mpeek = 0; 410: else 411: a = getchar(); 412: loop: 413: if (a==c) 414: return(-1); 415: switch(a) { 416: 417: case '\n': 418: case '\0': 419: error("Nonterminated string"); 420: peekc = a; 421: return(-1); 422: 423: case '\\': 424: switch (a=getchar()) { 425: 426: case 't': 427: return('\t'); 428: 429: case 'n': 430: return('\n'); 431: 432: case 'b': 433: return('\b'); 434: 435: case '0': case '1': case '2': case '3': 436: case '4': case '5': case '6': case '7': 437: n = 0; 438: c = 0; 439: while (++c<=3 && '0'<=a && a<='7') { 440: n =<< 3; 441: n =+ a-'0'; 442: a = getchar(); 443: } 444: mpeek = a; 445: return(n); 446: 447: case 'r': 448: return('\r'); 449: 450: case '\n': 451: if (!inhdr) 452: line++; 453: inhdr = 0; 454: a = getchar(); 455: goto loop; 456: } 457: } 458: return(a); 459: } 460: 461: /* 462: * Read an expression and return a pointer to its tree. 463: * It's the classical bottom-up, priority-driven scheme. 464: * The initflg prevents the parse from going past 465: * "," or ":" because those delimitesrs are special 466: * in initializer (and some other) expressions. 467: */ 468: tree() 469: { 470: #define SEOF 200 471: #define SSIZE 20 472: int *op, opst[SSIZE], *pp, prst[SSIZE]; 473: register int andflg, o; 474: register struct hshtab *cs; 475: int p, ps, os; 476: 477: space = treespace; 478: op = opst; 479: pp = prst; 480: cp = cmst; 481: *op = SEOF; 482: *pp = 06; 483: andflg = 0; 484: 485: advanc: 486: switch (o=symbol()) { 487: 488: case NAME: 489: cs = csym; 490: if (cs->hclass==0 && cs->htype==0) 491: if(nextchar()=='(') { 492: /* set function */ 493: cs->hclass = EXTERN; 494: cs->htype = FUNC; 495: } else if (initflg) 496: cs->hclass = EXTERN; 497: else { 498: /* set label */ 499: cs->htype = ARRAY; 500: if (cs->hoffset==0) 501: cs->hoffset = isn++; 502: } 503: *cp++ = copname(cs); 504: goto tand; 505: 506: case FCON: 507: if (!initflg) 508: outcode("BBNB1N1N1N1N0B", DATA,LABEL, 509: cval, WDATA, fcval, PROG); 510: 511: case CON: 512: case SFCON: 513: *cp++ = block(1,o,(o==CON?INT:DOUBLE),0,cval); 514: goto tand; 515: 516: /* fake a static char array */ 517: case STRING: 518: putstr(cval); 519: *cp++ = block(3, NAME, ARRAY+CHAR,0,STATIC,0,cval); 520: 521: tand: 522: if(cp>=cmst+cmsiz) { 523: error("Expression overflow"); 524: exit(1); 525: } 526: if (andflg) 527: goto syntax; 528: andflg = 1; 529: goto advanc; 530: 531: case INCBEF: 532: case DECBEF: 533: if (andflg) 534: o =+ 2; 535: goto oponst; 536: 537: case COMPL: 538: case EXCLA: 539: case SIZEOF: 540: if (andflg) 541: goto syntax; 542: goto oponst; 543: 544: case MINUS: 545: if (!andflg) { 546: if ((peeksym=symbol())==FCON) { 547: fcval = - fcval; 548: goto advanc; 549: } 550: if (peeksym==SFCON) { 551: fcval = - fcval; 552: cval =^ 0100000; 553: goto advanc; 554: } 555: o = NEG; 556: } 557: andflg = 0; 558: goto oponst; 559: 560: case AND: 561: case TIMES: 562: if (andflg) 563: andflg = 0; else 564: if(o==AND) 565: o = AMPER; 566: else 567: o = STAR; 568: goto oponst; 569: 570: case LPARN: 571: if (andflg) { 572: o = symbol(); 573: if (o==RPARN) 574: o = MCALL; 575: else { 576: peeksym = o; 577: o = CALL; 578: andflg = 0; 579: } 580: } 581: goto oponst; 582: 583: case RBRACK: 584: case RPARN: 585: if (!andflg) 586: goto syntax; 587: goto oponst; 588: 589: case DOT: 590: case ARROW: 591: mosflg++; 592: break; 593: 594: } 595: /* binaries */ 596: if (!andflg) 597: goto syntax; 598: andflg = 0; 599: 600: oponst: 601: p = (opdope[o]>>9) & 077; 602: if ((o==COMMA || o==COLON) && initflg) 603: p = 05; 604: opon1: 605: ps = *pp; 606: if (p>ps || p==ps && (opdope[o]&RASSOC)!=0) { 607: switch (o) { 608: 609: case INCAFT: 610: case DECAFT: 611: p = 37; 612: break; 613: case LPARN: 614: case LBRACK: 615: case CALL: 616: p = 04; 617: } 618: if (op >= &opst[SSIZE-1]) { 619: error("expression overflow"); 620: exit(1); 621: } 622: *++op = o; 623: *++pp = p; 624: goto advanc; 625: } 626: --pp; 627: switch (os = *op--) { 628: 629: case SEOF: 630: peeksym = o; 631: build(0); /* flush conversions */ 632: return(*--cp); 633: 634: case CALL: 635: if (o!=RPARN) 636: goto syntax; 637: build(os); 638: goto advanc; 639: 640: case MCALL: 641: *cp++ = block(0,0,0,0); /* 0 arg call */ 642: os = CALL; 643: break; 644: 645: case INCBEF: 646: case INCAFT: 647: case DECBEF: 648: case DECAFT: 649: *cp++ = block(1, CON, INT, 0, 1); 650: break; 651: 652: case LPARN: 653: if (o!=RPARN) 654: goto syntax; 655: goto advanc; 656: 657: case LBRACK: 658: if (o!=RBRACK) 659: goto syntax; 660: build(LBRACK); 661: goto advanc; 662: } 663: build(os); 664: goto opon1; 665: 666: syntax: 667: error("Expression syntax"); 668: errflush(o); 669: return(0); 670: } 671: 672: /* 673: * Generate a tree node for a name. 674: * All the relevant info from the symbol table is 675: * copied out, including the name if it's an external. 676: * This is because the symbol table is gone in the next 677: * pass, so a ptr isn't sufficient. 678: */ 679: copname(acs) 680: struct hshtab *acs; 681: { 682: register struct hshtab *cs; 683: register struct tname *tp; 684: register char *cp1; 685: int i; 686: char *cp2; 687: 688: cs = acs; 689: tp = gblock(sizeof(*tp)/NCPW); 690: tp->op = NAME; 691: tp->type = cs->htype; 692: tp->dimp = cs->hdimp; 693: if ((tp->class = cs->hclass)==0) 694: tp->class = STATIC; 695: tp->offset = 0; 696: tp->nloc = cs->hoffset; 697: if (cs->hclass==EXTERN) { 698: gblock((ncps-NCPW)/NCPW); 699: cp1 = tp->nname; 700: cp2 = cs->name; 701: i = ncps; 702: do { 703: *cp1++ = *cp2++; 704: } while (--i); 705: } 706: if (cs->hflag&FFIELD) 707: tp->class = FMOS; 708: return(tp); 709: }