1*765Speter /* Copyright (c) 1979 Regents of the University of California */ 2*765Speter 3*765Speter static char sccsid[] = "@(#)pclval.c 1.1 08/27/80"; 4*765Speter 5*765Speter #include "whoami.h" 6*765Speter #include "0.h" 7*765Speter #include "tree.h" 8*765Speter #include "opcode.h" 9*765Speter #include "objfmt.h" 10*765Speter #ifdef PC 11*765Speter /* 12*765Speter * and the rest of the file 13*765Speter */ 14*765Speter # include "pc.h" 15*765Speter # include "pcops.h" 16*765Speter 17*765Speter extern int flagwas; 18*765Speter /* 19*765Speter * pclvalue computes the address 20*765Speter * of a qualified name and 21*765Speter * leaves it on the stack. 22*765Speter * for pc, it can be asked for either an lvalue or an rvalue. 23*765Speter * the semantics are the same, only the code is different. 24*765Speter * for putting out calls to check for nil and fnil, 25*765Speter * we have to traverse the list of qualifications twice: 26*765Speter * once to put out the calls and once to put out the address to be checked. 27*765Speter */ 28*765Speter struct nl * 29*765Speter pclvalue( r , modflag , required ) 30*765Speter int *r; 31*765Speter int modflag; 32*765Speter int required; 33*765Speter { 34*765Speter register struct nl *p; 35*765Speter register *c, *co; 36*765Speter int f, o; 37*765Speter int tr[2], trp[3]; 38*765Speter struct nl *firstp; 39*765Speter struct nl *lastp; 40*765Speter char *firstsymbol; 41*765Speter int firstbn; 42*765Speter 43*765Speter if ( r == NIL ) { 44*765Speter return NIL; 45*765Speter } 46*765Speter if ( nowexp( r ) ) { 47*765Speter return NIL; 48*765Speter } 49*765Speter if ( r[0] != T_VAR ) { 50*765Speter error("Variable required"); /* Pass mesgs down from pt of call ? */ 51*765Speter return NIL; 52*765Speter } 53*765Speter firstp = p = lookup( r[2] ); 54*765Speter if ( p == NIL ) { 55*765Speter return NIL; 56*765Speter } 57*765Speter firstsymbol = p -> symbol; 58*765Speter firstbn = bn; 59*765Speter c = r[3]; 60*765Speter if ( ( modflag & NOUSE ) && ! lptr( c ) ) { 61*765Speter p -> nl_flags = flagwas; 62*765Speter } 63*765Speter if ( modflag & MOD ) { 64*765Speter p -> nl_flags |= NMOD; 65*765Speter } 66*765Speter /* 67*765Speter * Only possibilities for p -> class here 68*765Speter * are the named classes, i.e. CONST, TYPE 69*765Speter * VAR, PROC, FUNC, REF, or a WITHPTR. 70*765Speter */ 71*765Speter if ( p -> class == WITHPTR ) { 72*765Speter /* 73*765Speter * Construct the tree implied by 74*765Speter * the with statement 75*765Speter */ 76*765Speter trp[0] = T_LISTPP; 77*765Speter trp[1] = tr; 78*765Speter trp[2] = r[3]; 79*765Speter tr[0] = T_FIELD; 80*765Speter tr[1] = r[2]; 81*765Speter c = trp; 82*765Speter } 83*765Speter /* 84*765Speter * this not only puts out the names of functions to call 85*765Speter * but also does all the semantic checking of the qualifications. 86*765Speter */ 87*765Speter if ( ! nilfnil( p , c , modflag , firstp , r[2] ) ) { 88*765Speter return NIL; 89*765Speter } 90*765Speter switch (p -> class) { 91*765Speter case WITHPTR: 92*765Speter case REF: 93*765Speter /* 94*765Speter * Obtain the indirect word 95*765Speter * of the WITHPTR or REF 96*765Speter * as the base of our lvalue 97*765Speter */ 98*765Speter putRV( firstsymbol , firstbn , p -> value[ 0 ] 99*765Speter , p2type( p ) ); 100*765Speter firstsymbol = 0; 101*765Speter f = 0; /* have an lv on stack */ 102*765Speter o = 0; 103*765Speter break; 104*765Speter case VAR: 105*765Speter f = 1; /* no lv on stack yet */ 106*765Speter o = p -> value[0]; 107*765Speter break; 108*765Speter default: 109*765Speter error("%s %s found where variable required", classes[p -> class], p -> symbol); 110*765Speter return (NIL); 111*765Speter } 112*765Speter /* 113*765Speter * Loop and handle each 114*765Speter * qualification on the name 115*765Speter */ 116*765Speter if ( c == NIL && ( modflag & ASGN ) && p -> value[ NL_FORV ] ) { 117*765Speter error("Can't modify the for variable %s in the range of the loop", p -> symbol); 118*765Speter return (NIL); 119*765Speter } 120*765Speter for ( ; c != NIL ; c = c[2] ) { 121*765Speter co = c[1]; 122*765Speter if ( co == NIL ) { 123*765Speter return NIL; 124*765Speter } 125*765Speter lastp = p; 126*765Speter p = p -> type; 127*765Speter if ( p == NIL ) { 128*765Speter return NIL; 129*765Speter } 130*765Speter switch ( co[0] ) { 131*765Speter case T_PTR: 132*765Speter /* 133*765Speter * Pointer qualification. 134*765Speter */ 135*765Speter if ( f ) { 136*765Speter putLV( firstsymbol , firstbn , o 137*765Speter , p2type( p ) ); 138*765Speter firstsymbol = 0; 139*765Speter } else { 140*765Speter if (o) { 141*765Speter putleaf( P2ICON , o , 0 , P2INT 142*765Speter , 0 ); 143*765Speter putop( P2PLUS , P2PTR | P2CHAR ); 144*765Speter } 145*765Speter } 146*765Speter /* 147*765Speter * Pointer cannot be 148*765Speter * nil and file cannot 149*765Speter * be at end-of-file. 150*765Speter * the appropriate function name is 151*765Speter * already out there from nilfnil. 152*765Speter */ 153*765Speter if ( p -> class == PTR ) { 154*765Speter /* 155*765Speter * this is the indirection from 156*765Speter * the address of the pointer 157*765Speter * to the pointer itself. 158*765Speter * kirk sez: 159*765Speter * fnil doesn't want this. 160*765Speter * and does it itself for files 161*765Speter * since only it knows where the 162*765Speter * actual window is. 163*765Speter * but i have to do this for 164*765Speter * regular pointers. 165*765Speter */ 166*765Speter putop( P2UNARY P2MUL , p2type( p ) ); 167*765Speter if ( opt( 't' ) ) { 168*765Speter putop( P2CALL , P2INT ); 169*765Speter } 170*765Speter } else { 171*765Speter putop( P2CALL , P2INT ); 172*765Speter } 173*765Speter f = o = 0; 174*765Speter continue; 175*765Speter case T_ARGL: 176*765Speter case T_ARY: 177*765Speter if ( f ) { 178*765Speter putLV( firstsymbol , firstbn , o 179*765Speter , p2type( p ) ); 180*765Speter firstsymbol = 0; 181*765Speter } else { 182*765Speter if (o) { 183*765Speter putleaf( P2ICON , o , 0 , P2INT 184*765Speter , 0 ); 185*765Speter putop( P2PLUS , P2INT ); 186*765Speter } 187*765Speter } 188*765Speter arycod( p , co[1] ); 189*765Speter f = o = 0; 190*765Speter continue; 191*765Speter case T_FIELD: 192*765Speter /* 193*765Speter * Field names are just 194*765Speter * an offset with some 195*765Speter * semantic checking. 196*765Speter */ 197*765Speter p = reclook(p, co[1]); 198*765Speter o += p -> value[0]; 199*765Speter continue; 200*765Speter default: 201*765Speter panic("lval2"); 202*765Speter } 203*765Speter } 204*765Speter if (f) { 205*765Speter putLV( firstsymbol , firstbn , o , p2type( p -> type ) ); 206*765Speter } else { 207*765Speter if (o) { 208*765Speter putleaf( P2ICON , o , 0 , P2INT , 0 ); 209*765Speter putop( P2PLUS , P2INT ); 210*765Speter } 211*765Speter } 212*765Speter if ( required == RREQ ) { 213*765Speter putop( P2UNARY P2MUL , p2type( p -> type ) ); 214*765Speter } 215*765Speter return ( p -> type ); 216*765Speter } 217*765Speter 218*765Speter /* 219*765Speter * this recursively follows done a list of qualifications 220*765Speter * and puts out the beginnings of calls to fnil for files 221*765Speter * or nil for pointers (if checking is on) on the way back. 222*765Speter * this returns true or false. 223*765Speter */ 224*765Speter nilfnil( p , c , modflag , firstp , r2 ) 225*765Speter struct nl *p; 226*765Speter int *c; 227*765Speter int modflag; 228*765Speter struct nl *firstp; 229*765Speter char *r2; /* no, not r2-d2 */ 230*765Speter { 231*765Speter int *co; 232*765Speter struct nl *lastp; 233*765Speter int t; 234*765Speter 235*765Speter if ( c == NIL ) { 236*765Speter return TRUE; 237*765Speter } 238*765Speter co = (int *) ( c[1] ); 239*765Speter if ( co == NIL ) { 240*765Speter return FALSE; 241*765Speter } 242*765Speter lastp = p; 243*765Speter p = p -> type; 244*765Speter if ( p == NIL ) { 245*765Speter return FALSE; 246*765Speter } 247*765Speter switch ( co[0] ) { 248*765Speter case T_PTR: 249*765Speter /* 250*765Speter * Pointer qualification. 251*765Speter */ 252*765Speter lastp -> nl_flags |= NUSED; 253*765Speter if ( p -> class != PTR && p -> class != FILET) { 254*765Speter error("^ allowed only on files and pointers, not on %ss", nameof(p)); 255*765Speter goto bad; 256*765Speter } 257*765Speter break; 258*765Speter case T_ARGL: 259*765Speter if ( p -> class != ARRAY ) { 260*765Speter if ( lastp == firstp ) { 261*765Speter error("%s is a %s, not a function", r2, classes[firstp -> class]); 262*765Speter } else { 263*765Speter error("Illegal function qualificiation"); 264*765Speter } 265*765Speter return FALSE; 266*765Speter } 267*765Speter recovered(); 268*765Speter error("Pascal uses [] for subscripting, not ()"); 269*765Speter /* and fall through */ 270*765Speter case T_ARY: 271*765Speter if ( p -> class != ARRAY ) { 272*765Speter error("Subscripting allowed only on arrays, not on %ss", nameof(p)); 273*765Speter goto bad; 274*765Speter } 275*765Speter codeoff(); 276*765Speter t = arycod( p , co[1] ); 277*765Speter codeon(); 278*765Speter switch ( t ) { 279*765Speter case 0: 280*765Speter return FALSE; 281*765Speter case -1: 282*765Speter goto bad; 283*765Speter } 284*765Speter break; 285*765Speter case T_FIELD: 286*765Speter /* 287*765Speter * Field names are just 288*765Speter * an offset with some 289*765Speter * semantic checking. 290*765Speter */ 291*765Speter if ( p -> class != RECORD ) { 292*765Speter error(". allowed only on records, not on %ss", nameof(p)); 293*765Speter goto bad; 294*765Speter } 295*765Speter if ( co[1] == NIL ) { 296*765Speter return FALSE; 297*765Speter } 298*765Speter p = reclook( p , co[1] ); 299*765Speter if ( p == NIL ) { 300*765Speter error("%s is not a field in this record", co[1]); 301*765Speter goto bad; 302*765Speter } 303*765Speter if ( modflag & MOD ) { 304*765Speter p -> nl_flags |= NMOD; 305*765Speter } 306*765Speter if ( ( modflag & NOUSE ) == 0 || lptr( c[2] ) ) { 307*765Speter p -> nl_flags |= NUSED; 308*765Speter } 309*765Speter break; 310*765Speter default: 311*765Speter panic("nilfnil"); 312*765Speter } 313*765Speter /* 314*765Speter * recursive call, check the rest of the qualifications. 315*765Speter */ 316*765Speter if ( ! nilfnil( p , c[2] , modflag , firstp , r2 ) ) { 317*765Speter return FALSE; 318*765Speter } 319*765Speter /* 320*765Speter * the point of all this. 321*765Speter */ 322*765Speter if ( co[0] == T_PTR ) { 323*765Speter if ( p -> class == PTR ) { 324*765Speter if ( opt( 't' ) ) { 325*765Speter putleaf( P2ICON , 0 , 0 326*765Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 327*765Speter , "_NIL" ); 328*765Speter } 329*765Speter } else { 330*765Speter putleaf( P2ICON , 0 , 0 331*765Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 332*765Speter , "_FNIL" ); 333*765Speter } 334*765Speter } 335*765Speter return TRUE; 336*765Speter bad: 337*765Speter cerror("Error occurred on qualification of %s", r2); 338*765Speter return FALSE; 339*765Speter } 340*765Speter #endif PC 341