1765Speter /* Copyright (c) 1979 Regents of the University of California */ 2765Speter 3*3832Speter static char sccsid[] = "@(#)pclval.c 1.4 06/01/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; 41*3832Speter char firstextra_flags; 42765Speter int firstbn; 43765Speter 44765Speter if ( r == NIL ) { 45765Speter return NIL; 46765Speter } 47765Speter if ( nowexp( r ) ) { 48765Speter return NIL; 49765Speter } 50765Speter if ( r[0] != T_VAR ) { 51765Speter error("Variable required"); /* Pass mesgs down from pt of call ? */ 52765Speter return NIL; 53765Speter } 54765Speter firstp = p = lookup( r[2] ); 55765Speter if ( p == NIL ) { 56765Speter return NIL; 57765Speter } 58765Speter firstsymbol = p -> symbol; 59765Speter firstbn = bn; 60*3832Speter firstextra_flags = p -> extra_flags; 61765Speter c = r[3]; 62765Speter if ( ( modflag & NOUSE ) && ! lptr( c ) ) { 63765Speter p -> nl_flags = flagwas; 64765Speter } 65765Speter if ( modflag & MOD ) { 66765Speter p -> nl_flags |= NMOD; 67765Speter } 68765Speter /* 69765Speter * Only possibilities for p -> class here 70765Speter * are the named classes, i.e. CONST, TYPE 71765Speter * VAR, PROC, FUNC, REF, or a WITHPTR. 72765Speter */ 73765Speter if ( p -> class == WITHPTR ) { 74765Speter /* 75765Speter * Construct the tree implied by 76765Speter * the with statement 77765Speter */ 78765Speter trp[0] = T_LISTPP; 79765Speter trp[1] = tr; 80765Speter trp[2] = r[3]; 81765Speter tr[0] = T_FIELD; 82765Speter tr[1] = r[2]; 83765Speter c = trp; 84765Speter } 85765Speter /* 86765Speter * this not only puts out the names of functions to call 87765Speter * but also does all the semantic checking of the qualifications. 88765Speter */ 89765Speter if ( ! nilfnil( p , c , modflag , firstp , r[2] ) ) { 90765Speter return NIL; 91765Speter } 92765Speter switch (p -> class) { 93765Speter case WITHPTR: 94765Speter case REF: 95765Speter /* 96765Speter * Obtain the indirect word 97765Speter * of the WITHPTR or REF 98765Speter * as the base of our lvalue 99765Speter */ 100*3832Speter putRV( firstsymbol , firstbn , p -> value[ 0 ] , 101*3832Speter firstextra_flags , p2type( p ) ); 102765Speter firstsymbol = 0; 103765Speter f = 0; /* have an lv on stack */ 104765Speter o = 0; 105765Speter break; 106765Speter case VAR: 107765Speter f = 1; /* no lv on stack yet */ 108765Speter o = p -> value[0]; 109765Speter break; 110765Speter default: 111765Speter error("%s %s found where variable required", classes[p -> class], p -> symbol); 112765Speter return (NIL); 113765Speter } 114765Speter /* 115765Speter * Loop and handle each 116765Speter * qualification on the name 117765Speter */ 1183375Speter if ( c == NIL && 1193375Speter ( modflag & ASGN ) && 1203583Speter ( p -> value[ NL_FORV ] & FORVAR ) ) { 121765Speter error("Can't modify the for variable %s in the range of the loop", p -> symbol); 122765Speter return (NIL); 123765Speter } 124765Speter for ( ; c != NIL ; c = c[2] ) { 125765Speter co = c[1]; 126765Speter if ( co == NIL ) { 127765Speter return NIL; 128765Speter } 129765Speter lastp = p; 130765Speter p = p -> type; 131765Speter if ( p == NIL ) { 132765Speter return NIL; 133765Speter } 134765Speter switch ( co[0] ) { 135765Speter case T_PTR: 136765Speter /* 137765Speter * Pointer qualification. 138765Speter */ 139765Speter if ( f ) { 140*3832Speter putLV( firstsymbol , firstbn , o , 141*3832Speter firstextra_flags , p2type( p ) ); 142765Speter firstsymbol = 0; 143765Speter } else { 144765Speter if (o) { 145765Speter putleaf( P2ICON , o , 0 , P2INT 146765Speter , 0 ); 147765Speter putop( P2PLUS , P2PTR | P2CHAR ); 148765Speter } 149765Speter } 150765Speter /* 151765Speter * Pointer cannot be 152765Speter * nil and file cannot 153765Speter * be at end-of-file. 154765Speter * the appropriate function name is 155765Speter * already out there from nilfnil. 156765Speter */ 157765Speter if ( p -> class == PTR ) { 158765Speter /* 159765Speter * this is the indirection from 160765Speter * the address of the pointer 161765Speter * to the pointer itself. 162765Speter * kirk sez: 163765Speter * fnil doesn't want this. 164765Speter * and does it itself for files 165765Speter * since only it knows where the 166765Speter * actual window is. 167765Speter * but i have to do this for 168765Speter * regular pointers. 169765Speter */ 170765Speter putop( P2UNARY P2MUL , p2type( p ) ); 171765Speter if ( opt( 't' ) ) { 172765Speter putop( P2CALL , P2INT ); 173765Speter } 174765Speter } else { 175765Speter putop( P2CALL , P2INT ); 176765Speter } 177765Speter f = o = 0; 178765Speter continue; 179765Speter case T_ARGL: 180765Speter case T_ARY: 181765Speter if ( f ) { 182*3832Speter putLV( firstsymbol , firstbn , o , 183*3832Speter firstextra_flags , p2type( p ) ); 184765Speter firstsymbol = 0; 185765Speter } else { 186765Speter if (o) { 187765Speter putleaf( P2ICON , o , 0 , P2INT 188765Speter , 0 ); 189765Speter putop( P2PLUS , P2INT ); 190765Speter } 191765Speter } 192765Speter arycod( p , co[1] ); 193765Speter f = o = 0; 194765Speter continue; 195765Speter case T_FIELD: 196765Speter /* 197765Speter * Field names are just 198765Speter * an offset with some 199765Speter * semantic checking. 200765Speter */ 201765Speter p = reclook(p, co[1]); 202765Speter o += p -> value[0]; 203765Speter continue; 204765Speter default: 205765Speter panic("lval2"); 206765Speter } 207765Speter } 208765Speter if (f) { 2093375Speter if ( required == LREQ ) { 210*3832Speter putLV( firstsymbol , firstbn , o , 211*3832Speter firstextra_flags , p2type( p -> type ) ); 2123375Speter } else { 213*3832Speter putRV( firstsymbol , firstbn , o , 214*3832Speter firstextra_flags , p2type( p -> type ) ); 2153375Speter } 216765Speter } else { 217765Speter if (o) { 218765Speter putleaf( P2ICON , o , 0 , P2INT , 0 ); 219765Speter putop( P2PLUS , P2INT ); 220765Speter } 2213375Speter if ( required == RREQ ) { 2223375Speter putop( P2UNARY P2MUL , p2type( p -> type ) ); 2233375Speter } 224765Speter } 225765Speter return ( p -> type ); 226765Speter } 227765Speter 228765Speter /* 229765Speter * this recursively follows done a list of qualifications 230765Speter * and puts out the beginnings of calls to fnil for files 231765Speter * or nil for pointers (if checking is on) on the way back. 232765Speter * this returns true or false. 233765Speter */ 234765Speter nilfnil( p , c , modflag , firstp , r2 ) 235765Speter struct nl *p; 236765Speter int *c; 237765Speter int modflag; 238765Speter struct nl *firstp; 239765Speter char *r2; /* no, not r2-d2 */ 240765Speter { 241765Speter int *co; 242765Speter struct nl *lastp; 243765Speter int t; 244765Speter 245765Speter if ( c == NIL ) { 246765Speter return TRUE; 247765Speter } 248765Speter co = (int *) ( c[1] ); 249765Speter if ( co == NIL ) { 250765Speter return FALSE; 251765Speter } 252765Speter lastp = p; 253765Speter p = p -> type; 254765Speter if ( p == NIL ) { 255765Speter return FALSE; 256765Speter } 257765Speter switch ( co[0] ) { 258765Speter case T_PTR: 259765Speter /* 260765Speter * Pointer qualification. 261765Speter */ 262765Speter lastp -> nl_flags |= NUSED; 263765Speter if ( p -> class != PTR && p -> class != FILET) { 264765Speter error("^ allowed only on files and pointers, not on %ss", nameof(p)); 265765Speter goto bad; 266765Speter } 267765Speter break; 268765Speter case T_ARGL: 269765Speter if ( p -> class != ARRAY ) { 270765Speter if ( lastp == firstp ) { 271765Speter error("%s is a %s, not a function", r2, classes[firstp -> class]); 272765Speter } else { 273765Speter error("Illegal function qualificiation"); 274765Speter } 275765Speter return FALSE; 276765Speter } 277765Speter recovered(); 278765Speter error("Pascal uses [] for subscripting, not ()"); 279765Speter /* and fall through */ 280765Speter case T_ARY: 281765Speter if ( p -> class != ARRAY ) { 282765Speter error("Subscripting allowed only on arrays, not on %ss", nameof(p)); 283765Speter goto bad; 284765Speter } 285765Speter codeoff(); 286765Speter t = arycod( p , co[1] ); 287765Speter codeon(); 288765Speter switch ( t ) { 289765Speter case 0: 290765Speter return FALSE; 291765Speter case -1: 292765Speter goto bad; 293765Speter } 294765Speter break; 295765Speter case T_FIELD: 296765Speter /* 297765Speter * Field names are just 298765Speter * an offset with some 299765Speter * semantic checking. 300765Speter */ 301765Speter if ( p -> class != RECORD ) { 302765Speter error(". allowed only on records, not on %ss", nameof(p)); 303765Speter goto bad; 304765Speter } 305765Speter if ( co[1] == NIL ) { 306765Speter return FALSE; 307765Speter } 308765Speter p = reclook( p , co[1] ); 309765Speter if ( p == NIL ) { 310765Speter error("%s is not a field in this record", co[1]); 311765Speter goto bad; 312765Speter } 313765Speter if ( modflag & MOD ) { 314765Speter p -> nl_flags |= NMOD; 315765Speter } 316765Speter if ( ( modflag & NOUSE ) == 0 || lptr( c[2] ) ) { 317765Speter p -> nl_flags |= NUSED; 318765Speter } 319765Speter break; 320765Speter default: 321765Speter panic("nilfnil"); 322765Speter } 323765Speter /* 324765Speter * recursive call, check the rest of the qualifications. 325765Speter */ 326765Speter if ( ! nilfnil( p , c[2] , modflag , firstp , r2 ) ) { 327765Speter return FALSE; 328765Speter } 329765Speter /* 330765Speter * the point of all this. 331765Speter */ 332765Speter if ( co[0] == T_PTR ) { 333765Speter if ( p -> class == PTR ) { 334765Speter if ( opt( 't' ) ) { 335765Speter putleaf( P2ICON , 0 , 0 336765Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 337765Speter , "_NIL" ); 338765Speter } 339765Speter } else { 340765Speter putleaf( P2ICON , 0 , 0 341765Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 342765Speter , "_FNIL" ); 343765Speter } 344765Speter } 345765Speter return TRUE; 346765Speter bad: 347765Speter cerror("Error occurred on qualification of %s", r2); 348765Speter return FALSE; 349765Speter } 350765Speter #endif PC 351