1765Speter /* Copyright (c) 1979 Regents of the University of California */ 2765Speter 3*14739Sthien #ifndef lint 4*14739Sthien static char sccsid[] = "@(#)pclval.c 1.5 08/19/83"; 5*14739Sthien #endif 6765Speter 7765Speter #include "whoami.h" 8765Speter #include "0.h" 9765Speter #include "tree.h" 10765Speter #include "opcode.h" 11765Speter #include "objfmt.h" 12*14739Sthien #include "tree_ty.h" 13765Speter #ifdef PC 14765Speter /* 15765Speter * and the rest of the file 16765Speter */ 17765Speter # include "pc.h" 18765Speter # include "pcops.h" 19765Speter 20765Speter extern int flagwas; 21765Speter /* 22765Speter * pclvalue computes the address 23765Speter * of a qualified name and 24765Speter * leaves it on the stack. 25765Speter * for pc, it can be asked for either an lvalue or an rvalue. 26765Speter * the semantics are the same, only the code is different. 27765Speter * for putting out calls to check for nil and fnil, 28765Speter * we have to traverse the list of qualifications twice: 29765Speter * once to put out the calls and once to put out the address to be checked. 30765Speter */ 31765Speter struct nl * 32*14739Sthien pclvalue( var , modflag , required ) 33*14739Sthien struct tnode *var; 34765Speter int modflag; 35765Speter int required; 36765Speter { 37765Speter register struct nl *p; 38*14739Sthien register struct tnode *c, *co; 39765Speter int f, o; 40*14739Sthien struct tnode l_node, tr; 41*14739Sthien VAR_NODE *v_node; 42*14739Sthien LIST_NODE *tr_ptr; 43*14739Sthien struct nl *firstp, *lastp; 44765Speter char *firstsymbol; 453832Speter char firstextra_flags; 46765Speter int firstbn; 47765Speter 48*14739Sthien if ( var == TR_NIL ) { 49*14739Sthien return NLNIL; 50765Speter } 51*14739Sthien if ( nowexp( var ) ) { 52*14739Sthien return NLNIL; 53765Speter } 54*14739Sthien if ( var->tag != T_VAR ) { 55765Speter error("Variable required"); /* Pass mesgs down from pt of call ? */ 56*14739Sthien return NLNIL; 57765Speter } 58*14739Sthien v_node = &(var->var_node); 59*14739Sthien firstp = p = lookup( v_node->cptr ); 60*14739Sthien if ( p == NLNIL ) { 61*14739Sthien return NLNIL; 62765Speter } 63765Speter firstsymbol = p -> symbol; 64765Speter firstbn = bn; 653832Speter firstextra_flags = p -> extra_flags; 66*14739Sthien c = v_node->qual; 67765Speter if ( ( modflag & NOUSE ) && ! lptr( c ) ) { 68765Speter p -> nl_flags = flagwas; 69765Speter } 70765Speter if ( modflag & MOD ) { 71765Speter p -> nl_flags |= NMOD; 72765Speter } 73765Speter /* 74765Speter * Only possibilities for p -> class here 75765Speter * are the named classes, i.e. CONST, TYPE 76765Speter * VAR, PROC, FUNC, REF, or a WITHPTR. 77765Speter */ 78*14739Sthien tr_ptr = &(l_node.list_node); 79765Speter if ( p -> class == WITHPTR ) { 80765Speter /* 81765Speter * Construct the tree implied by 82765Speter * the with statement 83765Speter */ 84*14739Sthien l_node.tag = T_LISTPP; 85*14739Sthien tr_ptr->list = &(tr); 86*14739Sthien tr_ptr->next = v_node->qual; 87*14739Sthien tr.tag = T_FIELD; 88*14739Sthien tr.field_node.id_ptr = v_node->cptr; 89*14739Sthien c = &(l_node); 90765Speter } 91765Speter /* 92765Speter * this not only puts out the names of functions to call 93765Speter * but also does all the semantic checking of the qualifications. 94765Speter */ 95*14739Sthien if ( ! nilfnil( p , c , modflag , firstp , v_node->cptr ) ) { 96*14739Sthien return NLNIL; 97765Speter } 98765Speter switch (p -> class) { 99765Speter case WITHPTR: 100765Speter case REF: 101765Speter /* 102765Speter * Obtain the indirect word 103765Speter * of the WITHPTR or REF 104765Speter * as the base of our lvalue 105765Speter */ 1063832Speter putRV( firstsymbol , firstbn , p -> value[ 0 ] , 1073832Speter firstextra_flags , p2type( p ) ); 108765Speter firstsymbol = 0; 109765Speter f = 0; /* have an lv on stack */ 110765Speter o = 0; 111765Speter break; 112765Speter case VAR: 113765Speter f = 1; /* no lv on stack yet */ 114765Speter o = p -> value[0]; 115765Speter break; 116765Speter default: 117765Speter error("%s %s found where variable required", classes[p -> class], p -> symbol); 118*14739Sthien return (NLNIL); 119765Speter } 120765Speter /* 121765Speter * Loop and handle each 122765Speter * qualification on the name 123765Speter */ 1243375Speter if ( c == NIL && 1253375Speter ( modflag & ASGN ) && 1263583Speter ( p -> value[ NL_FORV ] & FORVAR ) ) { 127765Speter error("Can't modify the for variable %s in the range of the loop", p -> symbol); 128*14739Sthien return (NLNIL); 129765Speter } 130*14739Sthien for ( ; c != TR_NIL ; c = c->list_node.next ) { 131*14739Sthien co = c->list_node.list; 132*14739Sthien if ( co == TR_NIL ) { 133*14739Sthien return NLNIL; 134765Speter } 135765Speter lastp = p; 136765Speter p = p -> type; 137*14739Sthien if ( p == NLNIL ) { 138*14739Sthien return NLNIL; 139765Speter } 140*14739Sthien switch ( co->tag ) { 141765Speter case T_PTR: 142765Speter /* 143765Speter * Pointer qualification. 144765Speter */ 145765Speter if ( f ) { 1463832Speter putLV( firstsymbol , firstbn , o , 1473832Speter firstextra_flags , p2type( p ) ); 148765Speter firstsymbol = 0; 149765Speter } else { 150765Speter if (o) { 151765Speter putleaf( P2ICON , o , 0 , P2INT 152*14739Sthien , (char *) 0 ); 153765Speter putop( P2PLUS , P2PTR | P2CHAR ); 154765Speter } 155765Speter } 156765Speter /* 157765Speter * Pointer cannot be 158765Speter * nil and file cannot 159765Speter * be at end-of-file. 160765Speter * the appropriate function name is 161765Speter * already out there from nilfnil. 162765Speter */ 163765Speter if ( p -> class == PTR ) { 164765Speter /* 165765Speter * this is the indirection from 166765Speter * the address of the pointer 167765Speter * to the pointer itself. 168765Speter * kirk sez: 169765Speter * fnil doesn't want this. 170765Speter * and does it itself for files 171765Speter * since only it knows where the 172765Speter * actual window is. 173765Speter * but i have to do this for 174765Speter * regular pointers. 175765Speter */ 176765Speter putop( P2UNARY P2MUL , p2type( p ) ); 177765Speter if ( opt( 't' ) ) { 178765Speter putop( P2CALL , P2INT ); 179765Speter } 180765Speter } else { 181765Speter putop( P2CALL , P2INT ); 182765Speter } 183765Speter f = o = 0; 184765Speter continue; 185765Speter case T_ARGL: 186765Speter case T_ARY: 187765Speter if ( f ) { 1883832Speter putLV( firstsymbol , firstbn , o , 1893832Speter firstextra_flags , p2type( p ) ); 190765Speter firstsymbol = 0; 191765Speter } else { 192765Speter if (o) { 193765Speter putleaf( P2ICON , o , 0 , P2INT 194*14739Sthien , (char *) 0 ); 195765Speter putop( P2PLUS , P2INT ); 196765Speter } 197765Speter } 198*14739Sthien (void) arycod( p , co->ary_node.expr_list ); 199765Speter f = o = 0; 200765Speter continue; 201765Speter case T_FIELD: 202765Speter /* 203765Speter * Field names are just 204765Speter * an offset with some 205765Speter * semantic checking. 206765Speter */ 207*14739Sthien p = reclook(p, co->field_node.id_ptr); 208765Speter o += p -> value[0]; 209765Speter continue; 210765Speter default: 211765Speter panic("lval2"); 212765Speter } 213765Speter } 214765Speter if (f) { 2153375Speter if ( required == LREQ ) { 2163832Speter putLV( firstsymbol , firstbn , o , 2173832Speter firstextra_flags , p2type( p -> type ) ); 2183375Speter } else { 2193832Speter putRV( firstsymbol , firstbn , o , 2203832Speter firstextra_flags , p2type( p -> type ) ); 2213375Speter } 222765Speter } else { 223765Speter if (o) { 224*14739Sthien putleaf( P2ICON , o , 0 , P2INT , (char *) 0 ); 225765Speter putop( P2PLUS , P2INT ); 226765Speter } 2273375Speter if ( required == RREQ ) { 2283375Speter putop( P2UNARY P2MUL , p2type( p -> type ) ); 2293375Speter } 230765Speter } 231765Speter return ( p -> type ); 232765Speter } 233765Speter 234765Speter /* 235765Speter * this recursively follows done a list of qualifications 236765Speter * and puts out the beginnings of calls to fnil for files 237765Speter * or nil for pointers (if checking is on) on the way back. 238765Speter * this returns true or false. 239765Speter */ 240*14739Sthien bool 241765Speter nilfnil( p , c , modflag , firstp , r2 ) 242*14739Sthien struct nl *p; 243*14739Sthien struct tnode *c; 244765Speter int modflag; 245765Speter struct nl *firstp; 246765Speter char *r2; /* no, not r2-d2 */ 247765Speter { 248*14739Sthien struct tnode *co; 249765Speter struct nl *lastp; 250765Speter int t; 251765Speter 252*14739Sthien if ( c == TR_NIL ) { 253765Speter return TRUE; 254765Speter } 255*14739Sthien co = ( c->list_node.list ); 256*14739Sthien if ( co == TR_NIL ) { 257765Speter return FALSE; 258765Speter } 259765Speter lastp = p; 260765Speter p = p -> type; 261*14739Sthien if ( p == NLNIL ) { 262765Speter return FALSE; 263765Speter } 264*14739Sthien switch ( co->tag ) { 265765Speter case T_PTR: 266765Speter /* 267765Speter * Pointer qualification. 268765Speter */ 269765Speter lastp -> nl_flags |= NUSED; 270765Speter if ( p -> class != PTR && p -> class != FILET) { 271765Speter error("^ allowed only on files and pointers, not on %ss", nameof(p)); 272765Speter goto bad; 273765Speter } 274765Speter break; 275765Speter case T_ARGL: 276765Speter if ( p -> class != ARRAY ) { 277765Speter if ( lastp == firstp ) { 278765Speter error("%s is a %s, not a function", r2, classes[firstp -> class]); 279765Speter } else { 280765Speter error("Illegal function qualificiation"); 281765Speter } 282765Speter return FALSE; 283765Speter } 284765Speter recovered(); 285765Speter error("Pascal uses [] for subscripting, not ()"); 286765Speter /* and fall through */ 287765Speter case T_ARY: 288765Speter if ( p -> class != ARRAY ) { 289765Speter error("Subscripting allowed only on arrays, not on %ss", nameof(p)); 290765Speter goto bad; 291765Speter } 292765Speter codeoff(); 293*14739Sthien t = arycod( p , co->ary_node.expr_list ); 294765Speter codeon(); 295765Speter switch ( t ) { 296765Speter case 0: 297765Speter return FALSE; 298765Speter case -1: 299765Speter goto bad; 300765Speter } 301765Speter break; 302765Speter case T_FIELD: 303765Speter /* 304765Speter * Field names are just 305765Speter * an offset with some 306765Speter * semantic checking. 307765Speter */ 308765Speter if ( p -> class != RECORD ) { 309765Speter error(". allowed only on records, not on %ss", nameof(p)); 310765Speter goto bad; 311765Speter } 312*14739Sthien if ( co->field_node.id_ptr == NIL ) { 313765Speter return FALSE; 314765Speter } 315*14739Sthien p = reclook( p , co->field_node.id_ptr ); 316765Speter if ( p == NIL ) { 317*14739Sthien error("%s is not a field in this record", co->field_node.id_ptr); 318765Speter goto bad; 319765Speter } 320765Speter if ( modflag & MOD ) { 321765Speter p -> nl_flags |= NMOD; 322765Speter } 323*14739Sthien if ((modflag & NOUSE) == 0 || lptr(c->field_node.other )) { 324765Speter p -> nl_flags |= NUSED; 325765Speter } 326765Speter break; 327765Speter default: 328765Speter panic("nilfnil"); 329765Speter } 330765Speter /* 331765Speter * recursive call, check the rest of the qualifications. 332765Speter */ 333*14739Sthien if ( ! nilfnil( p , c->list_node.next , modflag , firstp , r2 ) ) { 334765Speter return FALSE; 335765Speter } 336765Speter /* 337765Speter * the point of all this. 338765Speter */ 339*14739Sthien if ( co->tag == T_PTR ) { 340765Speter if ( p -> class == PTR ) { 341765Speter if ( opt( 't' ) ) { 342765Speter putleaf( P2ICON , 0 , 0 343765Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 344765Speter , "_NIL" ); 345765Speter } 346765Speter } else { 347765Speter putleaf( P2ICON , 0 , 0 348765Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 349765Speter , "_FNIL" ); 350765Speter } 351765Speter } 352765Speter return TRUE; 353765Speter bad: 354765Speter cerror("Error occurred on qualification of %s", r2); 355765Speter return FALSE; 356765Speter } 357765Speter #endif PC 358