1765Speter /* Copyright (c) 1979 Regents of the University of California */ 2765Speter 3*3583Speter static char sccsid[] = "@(#)pclval.c 1.3 04/21/81"; 4765Speter 5765Speter #include "whoami.h" 6765Speter #include "0.h" 7765Speter #include "tree.h" 8765Speter #include "opcode.h" 9765Speter #include "objfmt.h" 10765Speter #ifdef PC 11765Speter /* 12765Speter * and the rest of the file 13765Speter */ 14765Speter # include "pc.h" 15765Speter # include "pcops.h" 16765Speter 17765Speter extern int flagwas; 18765Speter /* 19765Speter * pclvalue computes the address 20765Speter * of a qualified name and 21765Speter * leaves it on the stack. 22765Speter * for pc, it can be asked for either an lvalue or an rvalue. 23765Speter * the semantics are the same, only the code is different. 24765Speter * for putting out calls to check for nil and fnil, 25765Speter * we have to traverse the list of qualifications twice: 26765Speter * once to put out the calls and once to put out the address to be checked. 27765Speter */ 28765Speter struct nl * 29765Speter pclvalue( r , modflag , required ) 30765Speter int *r; 31765Speter int modflag; 32765Speter int required; 33765Speter { 34765Speter register struct nl *p; 35765Speter register *c, *co; 36765Speter int f, o; 37765Speter int tr[2], trp[3]; 38765Speter struct nl *firstp; 39765Speter struct nl *lastp; 40765Speter char *firstsymbol; 41765Speter int firstbn; 42765Speter 43765Speter if ( r == NIL ) { 44765Speter return NIL; 45765Speter } 46765Speter if ( nowexp( r ) ) { 47765Speter return NIL; 48765Speter } 49765Speter if ( r[0] != T_VAR ) { 50765Speter error("Variable required"); /* Pass mesgs down from pt of call ? */ 51765Speter return NIL; 52765Speter } 53765Speter firstp = p = lookup( r[2] ); 54765Speter if ( p == NIL ) { 55765Speter return NIL; 56765Speter } 57765Speter firstsymbol = p -> symbol; 58765Speter firstbn = bn; 59765Speter c = r[3]; 60765Speter if ( ( modflag & NOUSE ) && ! lptr( c ) ) { 61765Speter p -> nl_flags = flagwas; 62765Speter } 63765Speter if ( modflag & MOD ) { 64765Speter p -> nl_flags |= NMOD; 65765Speter } 66765Speter /* 67765Speter * Only possibilities for p -> class here 68765Speter * are the named classes, i.e. CONST, TYPE 69765Speter * VAR, PROC, FUNC, REF, or a WITHPTR. 70765Speter */ 71765Speter if ( p -> class == WITHPTR ) { 72765Speter /* 73765Speter * Construct the tree implied by 74765Speter * the with statement 75765Speter */ 76765Speter trp[0] = T_LISTPP; 77765Speter trp[1] = tr; 78765Speter trp[2] = r[3]; 79765Speter tr[0] = T_FIELD; 80765Speter tr[1] = r[2]; 81765Speter c = trp; 82765Speter } 83765Speter /* 84765Speter * this not only puts out the names of functions to call 85765Speter * but also does all the semantic checking of the qualifications. 86765Speter */ 87765Speter if ( ! nilfnil( p , c , modflag , firstp , r[2] ) ) { 88765Speter return NIL; 89765Speter } 90765Speter switch (p -> class) { 91765Speter case WITHPTR: 92765Speter case REF: 93765Speter /* 94765Speter * Obtain the indirect word 95765Speter * of the WITHPTR or REF 96765Speter * as the base of our lvalue 97765Speter */ 98765Speter putRV( firstsymbol , firstbn , p -> value[ 0 ] 99765Speter , p2type( p ) ); 100765Speter firstsymbol = 0; 101765Speter f = 0; /* have an lv on stack */ 102765Speter o = 0; 103765Speter break; 104765Speter case VAR: 105765Speter f = 1; /* no lv on stack yet */ 106765Speter o = p -> value[0]; 107765Speter break; 108765Speter default: 109765Speter error("%s %s found where variable required", classes[p -> class], p -> symbol); 110765Speter return (NIL); 111765Speter } 112765Speter /* 113765Speter * Loop and handle each 114765Speter * qualification on the name 115765Speter */ 1163375Speter if ( c == NIL && 1173375Speter ( modflag & ASGN ) && 118*3583Speter ( p -> value[ NL_FORV ] & FORVAR ) ) { 119765Speter error("Can't modify the for variable %s in the range of the loop", p -> symbol); 120765Speter return (NIL); 121765Speter } 122765Speter for ( ; c != NIL ; c = c[2] ) { 123765Speter co = c[1]; 124765Speter if ( co == NIL ) { 125765Speter return NIL; 126765Speter } 127765Speter lastp = p; 128765Speter p = p -> type; 129765Speter if ( p == NIL ) { 130765Speter return NIL; 131765Speter } 132765Speter switch ( co[0] ) { 133765Speter case T_PTR: 134765Speter /* 135765Speter * Pointer qualification. 136765Speter */ 137765Speter if ( f ) { 138765Speter putLV( firstsymbol , firstbn , o 139765Speter , p2type( p ) ); 140765Speter firstsymbol = 0; 141765Speter } else { 142765Speter if (o) { 143765Speter putleaf( P2ICON , o , 0 , P2INT 144765Speter , 0 ); 145765Speter putop( P2PLUS , P2PTR | P2CHAR ); 146765Speter } 147765Speter } 148765Speter /* 149765Speter * Pointer cannot be 150765Speter * nil and file cannot 151765Speter * be at end-of-file. 152765Speter * the appropriate function name is 153765Speter * already out there from nilfnil. 154765Speter */ 155765Speter if ( p -> class == PTR ) { 156765Speter /* 157765Speter * this is the indirection from 158765Speter * the address of the pointer 159765Speter * to the pointer itself. 160765Speter * kirk sez: 161765Speter * fnil doesn't want this. 162765Speter * and does it itself for files 163765Speter * since only it knows where the 164765Speter * actual window is. 165765Speter * but i have to do this for 166765Speter * regular pointers. 167765Speter */ 168765Speter putop( P2UNARY P2MUL , p2type( p ) ); 169765Speter if ( opt( 't' ) ) { 170765Speter putop( P2CALL , P2INT ); 171765Speter } 172765Speter } else { 173765Speter putop( P2CALL , P2INT ); 174765Speter } 175765Speter f = o = 0; 176765Speter continue; 177765Speter case T_ARGL: 178765Speter case T_ARY: 179765Speter if ( f ) { 180765Speter putLV( firstsymbol , firstbn , o 181765Speter , p2type( p ) ); 182765Speter firstsymbol = 0; 183765Speter } else { 184765Speter if (o) { 185765Speter putleaf( P2ICON , o , 0 , P2INT 186765Speter , 0 ); 187765Speter putop( P2PLUS , P2INT ); 188765Speter } 189765Speter } 190765Speter arycod( p , co[1] ); 191765Speter f = o = 0; 192765Speter continue; 193765Speter case T_FIELD: 194765Speter /* 195765Speter * Field names are just 196765Speter * an offset with some 197765Speter * semantic checking. 198765Speter */ 199765Speter p = reclook(p, co[1]); 200765Speter o += p -> value[0]; 201765Speter continue; 202765Speter default: 203765Speter panic("lval2"); 204765Speter } 205765Speter } 206765Speter if (f) { 2073375Speter if ( required == LREQ ) { 2083375Speter putLV( firstsymbol , firstbn , o , p2type( p -> type ) ); 2093375Speter } else { 2103375Speter putRV( firstsymbol , firstbn , o , p2type( p -> type ) ); 2113375Speter } 212765Speter } else { 213765Speter if (o) { 214765Speter putleaf( P2ICON , o , 0 , P2INT , 0 ); 215765Speter putop( P2PLUS , P2INT ); 216765Speter } 2173375Speter if ( required == RREQ ) { 2183375Speter putop( P2UNARY P2MUL , p2type( p -> type ) ); 2193375Speter } 220765Speter } 221765Speter return ( p -> type ); 222765Speter } 223765Speter 224765Speter /* 225765Speter * this recursively follows done a list of qualifications 226765Speter * and puts out the beginnings of calls to fnil for files 227765Speter * or nil for pointers (if checking is on) on the way back. 228765Speter * this returns true or false. 229765Speter */ 230765Speter nilfnil( p , c , modflag , firstp , r2 ) 231765Speter struct nl *p; 232765Speter int *c; 233765Speter int modflag; 234765Speter struct nl *firstp; 235765Speter char *r2; /* no, not r2-d2 */ 236765Speter { 237765Speter int *co; 238765Speter struct nl *lastp; 239765Speter int t; 240765Speter 241765Speter if ( c == NIL ) { 242765Speter return TRUE; 243765Speter } 244765Speter co = (int *) ( c[1] ); 245765Speter if ( co == NIL ) { 246765Speter return FALSE; 247765Speter } 248765Speter lastp = p; 249765Speter p = p -> type; 250765Speter if ( p == NIL ) { 251765Speter return FALSE; 252765Speter } 253765Speter switch ( co[0] ) { 254765Speter case T_PTR: 255765Speter /* 256765Speter * Pointer qualification. 257765Speter */ 258765Speter lastp -> nl_flags |= NUSED; 259765Speter if ( p -> class != PTR && p -> class != FILET) { 260765Speter error("^ allowed only on files and pointers, not on %ss", nameof(p)); 261765Speter goto bad; 262765Speter } 263765Speter break; 264765Speter case T_ARGL: 265765Speter if ( p -> class != ARRAY ) { 266765Speter if ( lastp == firstp ) { 267765Speter error("%s is a %s, not a function", r2, classes[firstp -> class]); 268765Speter } else { 269765Speter error("Illegal function qualificiation"); 270765Speter } 271765Speter return FALSE; 272765Speter } 273765Speter recovered(); 274765Speter error("Pascal uses [] for subscripting, not ()"); 275765Speter /* and fall through */ 276765Speter case T_ARY: 277765Speter if ( p -> class != ARRAY ) { 278765Speter error("Subscripting allowed only on arrays, not on %ss", nameof(p)); 279765Speter goto bad; 280765Speter } 281765Speter codeoff(); 282765Speter t = arycod( p , co[1] ); 283765Speter codeon(); 284765Speter switch ( t ) { 285765Speter case 0: 286765Speter return FALSE; 287765Speter case -1: 288765Speter goto bad; 289765Speter } 290765Speter break; 291765Speter case T_FIELD: 292765Speter /* 293765Speter * Field names are just 294765Speter * an offset with some 295765Speter * semantic checking. 296765Speter */ 297765Speter if ( p -> class != RECORD ) { 298765Speter error(". allowed only on records, not on %ss", nameof(p)); 299765Speter goto bad; 300765Speter } 301765Speter if ( co[1] == NIL ) { 302765Speter return FALSE; 303765Speter } 304765Speter p = reclook( p , co[1] ); 305765Speter if ( p == NIL ) { 306765Speter error("%s is not a field in this record", co[1]); 307765Speter goto bad; 308765Speter } 309765Speter if ( modflag & MOD ) { 310765Speter p -> nl_flags |= NMOD; 311765Speter } 312765Speter if ( ( modflag & NOUSE ) == 0 || lptr( c[2] ) ) { 313765Speter p -> nl_flags |= NUSED; 314765Speter } 315765Speter break; 316765Speter default: 317765Speter panic("nilfnil"); 318765Speter } 319765Speter /* 320765Speter * recursive call, check the rest of the qualifications. 321765Speter */ 322765Speter if ( ! nilfnil( p , c[2] , modflag , firstp , r2 ) ) { 323765Speter return FALSE; 324765Speter } 325765Speter /* 326765Speter * the point of all this. 327765Speter */ 328765Speter if ( co[0] == T_PTR ) { 329765Speter if ( p -> class == PTR ) { 330765Speter if ( opt( 't' ) ) { 331765Speter putleaf( P2ICON , 0 , 0 332765Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 333765Speter , "_NIL" ); 334765Speter } 335765Speter } else { 336765Speter putleaf( P2ICON , 0 , 0 337765Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 338765Speter , "_FNIL" ); 339765Speter } 340765Speter } 341765Speter return TRUE; 342765Speter bad: 343765Speter cerror("Error occurred on qualification of %s", r2); 344765Speter return FALSE; 345765Speter } 346765Speter #endif PC 347