1: # 2: /* 3: * C compiler 4: * 5: * 6: */ 7: 8: #include "c0h.c" 9: 10: /* 11: * Called from tree, this routine takes the top 1, 2, or 3 12: * operands on the expression stack, makes a new node with 13: * the operator op, and puts it on the stack. 14: * Essentially all the work is in inserting 15: * appropriate conversions. 16: */ 17: build(op) { 18: register int t1; 19: int t2, t3, t; 20: struct tnode *p3, *disarray(); 21: register struct tnode *p1, *p2; 22: int d, dope, leftc, cvn, pcvn; 23: 24: /* 25: * a[i] => *(a+i) 26: */ 27: if (op==LBRACK) { 28: build(PLUS); 29: op = STAR; 30: } 31: dope = opdope[op]; 32: if ((dope&BINARY)!=0) { 33: p2 = chkfun(disarray(*--cp)); 34: t2 = p2->type; 35: } 36: p1 = *--cp; 37: /* 38: * sizeof gets turned into a number here. 39: * Bug: sizeof(structure-member-array) is 2 because 40: * the array has been turned into a ptr already. 41: */ 42: if (op==SIZEOF) { 43: t1 = length(p1); 44: p1->op = CON; 45: p1->type = INT; 46: p1->dimp = 0; 47: p1->value = t1; 48: *cp++ = p1; 49: return; 50: } 51: if (op!=AMPER) { 52: p1 = disarray(p1); 53: if (op!=CALL) 54: p1 = chkfun(p1); 55: } 56: t1 = p1->type; 57: pcvn = 0; 58: t = INT; 59: switch (op) { 60: 61: /* end of expression */ 62: case 0: 63: *cp++ = p1; 64: return; 65: 66: /* no-conversion operators */ 67: case QUEST: 68: if (p2->op!=COLON) 69: error("Illegal conditional"); 70: t = t2; 71: 72: case COMMA: 73: case LOGAND: 74: case LOGOR: 75: *cp++ = block(2, op, t, 0, p1, p2); 76: return; 77: 78: case CALL: 79: if ((t1&XTYPE) != FUNC) 80: error("Call of non-function"); 81: *cp++ = block(2,CALL,decref(t1),p1->dimp,p1,p2); 82: return; 83: 84: case STAR: 85: if (p1->op==AMPER ) { 86: *cp++ = p1->tr1; 87: return; 88: } 89: if ((t1&XTYPE) == FUNC) 90: error("Illegal indirection"); 91: *cp++ = block(1,STAR,decref(t1),p1->dimp,p1); 92: return; 93: 94: case AMPER: 95: if (p1->op==STAR) { 96: p1->tr1->dimp = p1->dimp; 97: p1->tr1->type = incref(t1); 98: *cp++ = p1->tr1; 99: return; 100: } 101: if (p1->op==NAME) { 102: *cp++ = block(1,op,incref(t1),p1->dimp,p1); 103: return; 104: } 105: error("Illegal lvalue"); 106: break; 107: 108: /* 109: * a->b goes to (*a).b 110: */ 111: case ARROW: 112: *cp++ = p1; 113: chkw(p1, -1); 114: p1->type = PTR+STRUCT; 115: build(STAR); 116: p1 = *--cp; 117: 118: /* 119: * In a.b, a fairly complicated process has to 120: * be used to make the left operand look 121: * as if it had the type of the second. 122: * Also, the offset in the structure has to be 123: * given a special type to prevent conversion. 124: */ 125: case DOT: 126: if (p2->op!=NAME || (p2->class!=MOS && p2->class!=FMOS)) 127: error("Illegal structure ref"); 128: *cp++ = p1; 129: t = t2; 130: if ((t&XTYPE) == ARRAY) { 131: t = decref(t); 132: p2->ssp++; 133: } 134: setype(p1, t, p2->dimp); 135: build(AMPER); 136: *cp++ = block(1,CON,NOTYPE,0,p2->nloc); 137: build(PLUS); 138: if ((t2&XTYPE) != ARRAY) 139: build(STAR); 140: if (p2->class == FMOS) 141: *cp++ = block(2, FSEL, t, 0, *--cp, p2->dimp); 142: return; 143: } 144: if ((dope&LVALUE)!=0) 145: chklval(p1); 146: if ((dope&LWORD)!=0) 147: chkw(p1, LONG); 148: if ((dope&RWORD)!=0) 149: chkw(p2, LONG); 150: if ((dope&BINARY)==0) { 151: if (op==ITOF) 152: t1 = DOUBLE; 153: else if (op==FTOI) 154: t1 = INT; 155: if (!fold(op, p1, 0)) 156: *cp++ = block(1,op,t1,p1->dimp,p1); 157: return; 158: } 159: cvn = 0; 160: if (t1==STRUCT || t2==STRUCT) { 161: error("Unimplemented structure operation"); 162: t1 = t2 = INT; 163: } 164: if (t2==NOTYPE) { 165: t = t1; 166: p2->type = INT; /* no int cv for struct */ 167: t2 = INT; 168: } else 169: cvn = cvtab[lintyp(t1)][lintyp(t2)]; 170: leftc = (cvn>>4)&017; 171: cvn =& 017; 172: t = leftc? t2:t1; 173: if (dope&ASSGOP) { 174: t = t1; 175: if (op==ASSIGN && (cvn==ITP||cvn==PTI)) 176: cvn = leftc = 0; 177: if (leftc) 178: cvn = leftc; 179: leftc = 0; 180: } else if (op==COLON && t1>=PTR && t1==t2) 181: cvn = 0; 182: else if (dope&RELAT) { 183: if (op>=LESSEQ && (t1>=PTR || t2>=PTR)) 184: op =+ LESSEQP-LESSEQ; 185: if (cvn==PTI) 186: cvn = 0; 187: } 188: if (cvn==PTI) { 189: cvn = 0; 190: if (op==MINUS) { 191: t = INT; 192: pcvn++; 193: } else { 194: if (t1!=t2 || t1!=(PTR+CHAR)) 195: cvn = XX; 196: } 197: } 198: if (cvn) { 199: t1 = plength(p1); 200: t2 = plength(p2); 201: if (cvn==XX || (cvn==PTI&&t1!=t2)) 202: error("Illegal conversion"); 203: else if (leftc) 204: p1 = convert(p1, t, cvn, t2); 205: else 206: p2 = convert(p2, t, cvn, t1); 207: } 208: if (dope&RELAT) 209: t = INT; 210: if (fold(op, p1, p2)==0) 211: *cp++ = block(2,op,t,(p1->dimp==0? p2:p1)->dimp,p1,p2); 212: if (pcvn && t1!=(PTR+CHAR)) { 213: p1 = *--cp; 214: *cp++ = convert(p1, 0, PTI, plength(p1->tr1)); 215: } 216: } 217: 218: /* 219: * Generate the appropirate conversion operator. 220: * For pointer <=> integer this is a multiplication 221: * or division, otherwise a special operator. 222: */ 223: convert(p, t, cvn, len) 224: struct tnode *p; 225: { 226: register int n; 227: 228: switch(cvn) { 229: 230: case PTI: 231: case ITP: 232: if (len==1) 233: return(p); 234: return(block(2, (cvn==PTI?DIVIDE:TIMES), t, 0, p, 235: block(1, CON, 0, 0, len))); 236: 237: case ITF: 238: n = ITOF; 239: break; 240: case FTI: 241: n = FTOI; 242: break; 243: case ITL: 244: n = ITOL; 245: break; 246: case LTI: 247: n = LTOI; 248: break; 249: case FTL: 250: n = FTOL; 251: break; 252: case LTF: 253: n = LTOF; 254: break; 255: } 256: return(block(1, n, t, 0, p)); 257: } 258: 259: /* 260: * Traverse an expression tree, adjust things 261: * so the types of things in it are consistent 262: * with the view that its top node has 263: * type at. 264: * Used with structure references. 265: */ 266: setype(ap, at, adimptr) 267: struct tnode *ap; 268: { 269: register struct tnode *p; 270: register t, dimptr; 271: 272: p = ap; 273: t = at; 274: dimptr = adimptr; 275: p->type = t; 276: if (dimptr != -1) 277: p->dimp = dimptr; 278: switch(p->op) { 279: 280: case AMPER: 281: setype(p->tr1, decref(t), dimptr); 282: return; 283: 284: case STAR: 285: setype(p->tr1, incref(t), dimptr); 286: return; 287: 288: case PLUS: 289: case MINUS: 290: setype(p->tr1, t, dimptr); 291: } 292: } 293: 294: /* 295: * A mention of a function name is turned into 296: * a pointer to that function. 297: */ 298: chkfun(ap) 299: struct tnode *ap; 300: { 301: register struct tnode *p; 302: register int t; 303: 304: p = ap; 305: if (((t = p->type)&XTYPE)==FUNC) 306: return(block(1,AMPER,incref(t),p->dimp,p)); 307: return(p); 308: } 309: 310: /* 311: * A mention of an array is turned into 312: * a pointer to the base of the array. 313: */ 314: struct tnode *disarray(ap) 315: struct tnode *ap; 316: { 317: register int t; 318: register struct tnode *p; 319: 320: p = ap; 321: /* check array & not MOS */ 322: if (((t = p->type)&XTYPE)!=ARRAY || p->op==NAME&&p->class==MOS) 323: return(p); 324: p->ssp++; 325: *cp++ = p; 326: setype(p, decref(t), -1); 327: build(AMPER); 328: return(*--cp); 329: } 330: 331: /* 332: * make sure that p is a ptr to a node 333: * with type int or char or 'okt.' 334: * okt might be nonexistent or 'long' 335: * (e.g. for <<). 336: */ 337: chkw(p, okt) 338: struct tnode *p; 339: { 340: register int t; 341: 342: if ((t=p->type)>CHAR && t<PTR && t!=okt) 343: error("Integer operand required"); 344: return; 345: } 346: 347: /* 348: *'linearize' a type for looking up in the 349: * conversion table 350: */ 351: lintyp(t) 352: { 353: switch(t) { 354: 355: case INT: 356: case CHAR: 357: return(0); 358: 359: case FLOAT: 360: case DOUBLE: 361: return(1); 362: 363: case LONG: 364: return(2); 365: 366: default: 367: return(3); 368: } 369: } 370: 371: /* 372: * Report an error. 373: */ 374: error(s, p1, p2, p3, p4, p5, p6) 375: { 376: nerror++; 377: printf("%d: ", line); 378: printf(s, p1, p2, p3, p4, p5, p6); 379: printf("\n"); 380: } 381: 382: /* 383: * Generate a node in an expression tree, 384: * setting the operator, type, degree (unused in this pass) 385: * and the operands. 386: */ 387: block(an, op, t, d, p1,p2,p3) 388: int *p1, *p2, *p3; 389: { 390: register int *ap, *p, n; 391: int *oldp; 392: 393: n = an+3; 394: p = gblock(n); 395: oldp = p; 396: ap = &op; 397: do { 398: *p++ = *ap++; 399: } while (--n); 400: return(oldp); 401: } 402: 403: /* 404: * Assign an unitialized block for use in the 405: * expression tree. 406: */ 407: gblock(n) 408: { 409: register int *p; 410: 411: p = space; 412: if ((space =+ n) >= &osspace[OSSIZ]) { 413: error("Expression overflow"); 414: exit(1); 415: } 416: return(p); 417: } 418: 419: /* 420: * Check that a tree can be used as an lvalue. 421: */ 422: chklval(ap) 423: struct tnode *ap; 424: { 425: register struct tnode *p; 426: 427: p = ap; 428: if (p->op!=NAME && p->op!=STAR) 429: error("Lvalue required"); 430: } 431: 432: /* 433: * reduce some forms of `constant op constant' 434: * to a constant. More of this is done in the next pass 435: * but this is used to allow constant expressions 436: * to be used in switches and array bounds. 437: */ 438: fold(op, ap1, ap2) 439: struct tnode *ap1, *ap2; 440: { 441: register struct tnode *p1; 442: register int v1, v2; 443: 444: p1 = ap1; 445: if (p1->op!=CON || (ap2!=0 && ap2->op!=CON)) 446: return(0); 447: v1 = p1->value; 448: v2 = ap2->value; 449: switch (op) { 450: 451: case PLUS: 452: v1 =+ v2; 453: break; 454: 455: case MINUS: 456: v1 =- v2; 457: break; 458: 459: case TIMES: 460: v1 =* v2; 461: break; 462: 463: case DIVIDE: 464: v1 =/ v2; 465: break; 466: 467: case MOD: 468: v1 =% v2; 469: break; 470: 471: case AND: 472: v1 =& v2; 473: break; 474: 475: case OR: 476: v1 =| v2; 477: break; 478: 479: case EXOR: 480: v1 =^ v2; 481: break; 482: 483: case NEG: 484: v1 = - v1; 485: break; 486: 487: case COMPL: 488: v1 = ~ v1; 489: break; 490: 491: case LSHIFT: 492: v1 =<< v2; 493: break; 494: 495: case RSHIFT: 496: v1 =>> v2; 497: break; 498: 499: default: 500: return(0); 501: } 502: p1->value = v1; 503: *cp++ = p1; 504: return(1); 505: } 506: 507: /* 508: * Compile an expression expected to have constant value, 509: * for example an array bound or a case value. 510: */ 511: conexp() 512: { 513: register struct tnode *t; 514: 515: initflg++; 516: if (t = tree()) 517: if (t->op != CON) 518: error("Constant required"); 519: initflg--; 520: return(t->value); 521: }