1765Speter /* Copyright (c) 1979 Regents of the University of California */ 2765Speter 314739Sthien #ifndef lint 4*15965Smckusick static char sccsid[] = "@(#)pclval.c 1.8 02/08/84"; 514739Sthien #endif 6765Speter 7765Speter #include "whoami.h" 8765Speter #include "0.h" 9765Speter #include "tree.h" 10765Speter #include "opcode.h" 11765Speter #include "objfmt.h" 1214739Sthien #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 * 3214739Sthien pclvalue( var , modflag , required ) 3314739Sthien struct tnode *var; 34765Speter int modflag; 35765Speter int required; 36765Speter { 37765Speter register struct nl *p; 3814739Sthien register struct tnode *c, *co; 39765Speter int f, o; 4014739Sthien struct tnode l_node, tr; 4114739Sthien VAR_NODE *v_node; 4214739Sthien LIST_NODE *tr_ptr; 43*15965Smckusick struct nl *firstp, *lastp; 44765Speter char *firstsymbol; 453832Speter char firstextra_flags; 46765Speter int firstbn; 47*15965Smckusick int s; 48765Speter 4914739Sthien if ( var == TR_NIL ) { 5014739Sthien return NLNIL; 51765Speter } 5214739Sthien if ( nowexp( var ) ) { 5314739Sthien return NLNIL; 54765Speter } 5514739Sthien if ( var->tag != T_VAR ) { 56765Speter error("Variable required"); /* Pass mesgs down from pt of call ? */ 5714739Sthien return NLNIL; 58765Speter } 5914739Sthien v_node = &(var->var_node); 6014739Sthien firstp = p = lookup( v_node->cptr ); 6114739Sthien if ( p == NLNIL ) { 6214739Sthien return NLNIL; 63765Speter } 64765Speter firstsymbol = p -> symbol; 65765Speter firstbn = bn; 663832Speter firstextra_flags = p -> extra_flags; 6714739Sthien c = v_node->qual; 68765Speter if ( ( modflag & NOUSE ) && ! lptr( c ) ) { 69765Speter p -> nl_flags = flagwas; 70765Speter } 71765Speter if ( modflag & MOD ) { 72765Speter p -> nl_flags |= NMOD; 73765Speter } 74765Speter /* 75765Speter * Only possibilities for p -> class here 76765Speter * are the named classes, i.e. CONST, TYPE 77765Speter * VAR, PROC, FUNC, REF, or a WITHPTR. 78765Speter */ 7914739Sthien tr_ptr = &(l_node.list_node); 80765Speter if ( p -> class == WITHPTR ) { 81765Speter /* 82765Speter * Construct the tree implied by 83765Speter * the with statement 84765Speter */ 8514739Sthien l_node.tag = T_LISTPP; 8614739Sthien tr_ptr->list = &(tr); 8714739Sthien tr_ptr->next = v_node->qual; 8814739Sthien tr.tag = T_FIELD; 8914739Sthien tr.field_node.id_ptr = v_node->cptr; 9014739Sthien c = &(l_node); 91765Speter } 92765Speter /* 93765Speter * this not only puts out the names of functions to call 94765Speter * but also does all the semantic checking of the qualifications. 95765Speter */ 9614739Sthien if ( ! nilfnil( p , c , modflag , firstp , v_node->cptr ) ) { 9714739Sthien return NLNIL; 98765Speter } 99765Speter switch (p -> class) { 100765Speter case WITHPTR: 101765Speter case REF: 102765Speter /* 103765Speter * Obtain the indirect word 104765Speter * of the WITHPTR or REF 105765Speter * as the base of our lvalue 106765Speter */ 1073832Speter putRV( firstsymbol , firstbn , p -> value[ 0 ] , 1083832Speter firstextra_flags , p2type( p ) ); 109765Speter firstsymbol = 0; 110765Speter f = 0; /* have an lv on stack */ 111765Speter o = 0; 112765Speter break; 113765Speter case VAR: 114*15965Smckusick if (p->type->class != CRANGE) { 115*15965Smckusick f = 1; /* no lv on stack yet */ 116*15965Smckusick o = p -> value[0]; 117*15965Smckusick } else { 118*15965Smckusick error("Conformant array bound %s found where variable required", p->symbol); 119*15965Smckusick return(NIL); 120*15965Smckusick } 121765Speter break; 122765Speter default: 123765Speter error("%s %s found where variable required", classes[p -> class], p -> symbol); 12414739Sthien return (NLNIL); 125765Speter } 126765Speter /* 127765Speter * Loop and handle each 128765Speter * qualification on the name 129765Speter */ 1303375Speter if ( c == NIL && 1313375Speter ( modflag & ASGN ) && 1323583Speter ( p -> value[ NL_FORV ] & FORVAR ) ) { 133765Speter error("Can't modify the for variable %s in the range of the loop", p -> symbol); 13414739Sthien return (NLNIL); 135765Speter } 136*15965Smckusick s = 0; 13714739Sthien for ( ; c != TR_NIL ; c = c->list_node.next ) { 13814739Sthien co = c->list_node.list; 13914739Sthien if ( co == TR_NIL ) { 14014739Sthien return NLNIL; 141765Speter } 142*15965Smckusick lastp = p; 143765Speter p = p -> type; 14414739Sthien if ( p == NLNIL ) { 14514739Sthien return NLNIL; 146765Speter } 14714739Sthien switch ( co->tag ) { 148765Speter case T_PTR: 149765Speter /* 150765Speter * Pointer qualification. 151765Speter */ 152765Speter if ( f ) { 1533832Speter putLV( firstsymbol , firstbn , o , 1543832Speter firstextra_flags , p2type( p ) ); 155765Speter firstsymbol = 0; 156765Speter } else { 157765Speter if (o) { 158765Speter putleaf( P2ICON , o , 0 , P2INT 15914739Sthien , (char *) 0 ); 160765Speter putop( P2PLUS , P2PTR | P2CHAR ); 161765Speter } 162765Speter } 163765Speter /* 164765Speter * Pointer cannot be 165765Speter * nil and file cannot 166765Speter * be at end-of-file. 167765Speter * the appropriate function name is 168765Speter * already out there from nilfnil. 169765Speter */ 170765Speter if ( p -> class == PTR ) { 171765Speter /* 172765Speter * this is the indirection from 173765Speter * the address of the pointer 174765Speter * to the pointer itself. 175765Speter * kirk sez: 176765Speter * fnil doesn't want this. 177765Speter * and does it itself for files 178765Speter * since only it knows where the 179765Speter * actual window is. 180765Speter * but i have to do this for 181765Speter * regular pointers. 182765Speter */ 183765Speter putop( P2UNARY P2MUL , p2type( p ) ); 184765Speter if ( opt( 't' ) ) { 185765Speter putop( P2CALL , P2INT ); 186765Speter } 187765Speter } else { 188765Speter putop( P2CALL , P2INT ); 189765Speter } 190765Speter f = o = 0; 191765Speter continue; 192765Speter case T_ARGL: 193765Speter case T_ARY: 194765Speter if ( f ) { 1953832Speter putLV( firstsymbol , firstbn , o , 1963832Speter firstextra_flags , p2type( p ) ); 197765Speter firstsymbol = 0; 198765Speter } else { 199765Speter if (o) { 200765Speter putleaf( P2ICON , o , 0 , P2INT 20114739Sthien , (char *) 0 ); 202765Speter putop( P2PLUS , P2INT ); 203765Speter } 204765Speter } 205*15965Smckusick s = arycod( p , co->ary_node.expr_list, s); 206*15965Smckusick if (s == p->value[0]) { 207*15965Smckusick s = 0; 208*15965Smckusick } else { 209*15965Smckusick p = lastp; 210*15965Smckusick } 211765Speter f = o = 0; 212765Speter continue; 213765Speter case T_FIELD: 214765Speter /* 215765Speter * Field names are just 216765Speter * an offset with some 217765Speter * semantic checking. 218765Speter */ 21914739Sthien p = reclook(p, co->field_node.id_ptr); 220765Speter o += p -> value[0]; 221765Speter continue; 222765Speter default: 223765Speter panic("lval2"); 224765Speter } 225765Speter } 226765Speter if (f) { 2273375Speter if ( required == LREQ ) { 2283832Speter putLV( firstsymbol , firstbn , o , 2293832Speter firstextra_flags , p2type( p -> type ) ); 2303375Speter } else { 2313832Speter putRV( firstsymbol , firstbn , o , 2323832Speter firstextra_flags , p2type( p -> type ) ); 2333375Speter } 234765Speter } else { 235765Speter if (o) { 23614739Sthien putleaf( P2ICON , o , 0 , P2INT , (char *) 0 ); 237765Speter putop( P2PLUS , P2INT ); 238765Speter } 2393375Speter if ( required == RREQ ) { 2403375Speter putop( P2UNARY P2MUL , p2type( p -> type ) ); 2413375Speter } 242765Speter } 243765Speter return ( p -> type ); 244765Speter } 245765Speter 246765Speter /* 247765Speter * this recursively follows done a list of qualifications 248765Speter * and puts out the beginnings of calls to fnil for files 249765Speter * or nil for pointers (if checking is on) on the way back. 250765Speter * this returns true or false. 251765Speter */ 25214739Sthien bool 253765Speter nilfnil( p , c , modflag , firstp , r2 ) 25414739Sthien struct nl *p; 25514739Sthien struct tnode *c; 256765Speter int modflag; 257765Speter struct nl *firstp; 258765Speter char *r2; /* no, not r2-d2 */ 259765Speter { 26014739Sthien struct tnode *co; 261765Speter struct nl *lastp; 262765Speter int t; 263*15965Smckusick static int s = 0; 264765Speter 26514739Sthien if ( c == TR_NIL ) { 266765Speter return TRUE; 267765Speter } 26814739Sthien co = ( c->list_node.list ); 26914739Sthien if ( co == TR_NIL ) { 270765Speter return FALSE; 271765Speter } 272765Speter lastp = p; 273765Speter p = p -> type; 27414739Sthien if ( p == NLNIL ) { 275765Speter return FALSE; 276765Speter } 27714739Sthien switch ( co->tag ) { 278765Speter case T_PTR: 279765Speter /* 280765Speter * Pointer qualification. 281765Speter */ 282765Speter lastp -> nl_flags |= NUSED; 283765Speter if ( p -> class != PTR && p -> class != FILET) { 284765Speter error("^ allowed only on files and pointers, not on %ss", nameof(p)); 285765Speter goto bad; 286765Speter } 287765Speter break; 288765Speter case T_ARGL: 289765Speter if ( p -> class != ARRAY ) { 290765Speter if ( lastp == firstp ) { 291765Speter error("%s is a %s, not a function", r2, classes[firstp -> class]); 292765Speter } else { 293765Speter error("Illegal function qualificiation"); 294765Speter } 295765Speter return FALSE; 296765Speter } 297765Speter recovered(); 298765Speter error("Pascal uses [] for subscripting, not ()"); 299765Speter /* and fall through */ 300765Speter case T_ARY: 301765Speter if ( p -> class != ARRAY ) { 302765Speter error("Subscripting allowed only on arrays, not on %ss", nameof(p)); 303765Speter goto bad; 304765Speter } 305765Speter codeoff(); 306*15965Smckusick s = arycod( p , co->ary_node.expr_list , s ); 307765Speter codeon(); 308*15965Smckusick switch ( s ) { 309765Speter case 0: 310765Speter return FALSE; 311765Speter case -1: 312765Speter goto bad; 313765Speter } 314*15965Smckusick if (s == p->value[0]) { 315*15965Smckusick s = 0; 316*15965Smckusick } else { 317*15965Smckusick p = lastp; 318*15965Smckusick } 319765Speter break; 320765Speter case T_FIELD: 321765Speter /* 322765Speter * Field names are just 323765Speter * an offset with some 324765Speter * semantic checking. 325765Speter */ 326765Speter if ( p -> class != RECORD ) { 327765Speter error(". allowed only on records, not on %ss", nameof(p)); 328765Speter goto bad; 329765Speter } 33014739Sthien if ( co->field_node.id_ptr == NIL ) { 331765Speter return FALSE; 332765Speter } 33314739Sthien p = reclook( p , co->field_node.id_ptr ); 334765Speter if ( p == NIL ) { 33514739Sthien error("%s is not a field in this record", co->field_node.id_ptr); 336765Speter goto bad; 337765Speter } 338765Speter if ( modflag & MOD ) { 339765Speter p -> nl_flags |= NMOD; 340765Speter } 34114739Sthien if ((modflag & NOUSE) == 0 || lptr(c->field_node.other )) { 342765Speter p -> nl_flags |= NUSED; 343765Speter } 344765Speter break; 345765Speter default: 346765Speter panic("nilfnil"); 347765Speter } 348765Speter /* 349765Speter * recursive call, check the rest of the qualifications. 350765Speter */ 35114739Sthien if ( ! nilfnil( p , c->list_node.next , modflag , firstp , r2 ) ) { 352765Speter return FALSE; 353765Speter } 354765Speter /* 355765Speter * the point of all this. 356765Speter */ 35714739Sthien if ( co->tag == T_PTR ) { 358765Speter if ( p -> class == PTR ) { 359765Speter if ( opt( 't' ) ) { 360765Speter putleaf( P2ICON , 0 , 0 361765Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 362765Speter , "_NIL" ); 363765Speter } 364765Speter } else { 365765Speter putleaf( P2ICON , 0 , 0 366765Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 367765Speter , "_FNIL" ); 368765Speter } 369765Speter } 370765Speter return TRUE; 371765Speter bad: 372765Speter cerror("Error occurred on qualification of %s", r2); 373765Speter return FALSE; 374765Speter } 375765Speter #endif PC 376