1765Speter /* Copyright (c) 1979 Regents of the University of California */ 2765Speter 314739Sthien #ifndef lint 4*18465Sralph static char sccsid[] = "@(#)pclval.c 2.2 03/20/85"; 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" 18*18465Sralph # include <pcc.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; 4315965Smckusick struct nl *firstp, *lastp; 44765Speter char *firstsymbol; 453832Speter char firstextra_flags; 46765Speter int firstbn; 4715965Smckusick 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: 11415965Smckusick if (p->type->class != CRANGE) { 11515965Smckusick f = 1; /* no lv on stack yet */ 11615965Smckusick o = p -> value[0]; 11715965Smckusick } else { 11815965Smckusick error("Conformant array bound %s found where variable required", p->symbol); 11915965Smckusick return(NIL); 12015965Smckusick } 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 } 13615965Smckusick 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 } 14215965Smckusick lastp = p; 143765Speter p = p -> type; 14414739Sthien if ( p == NLNIL ) { 14514739Sthien return NLNIL; 146765Speter } 14715987Saoki /* 14815987Saoki * If we haven't seen enough subscripts, and the next 14915987Saoki * qualification isn't array reference, then it's an error. 15015987Saoki */ 15115987Saoki if (s && co->tag != T_ARY) { 15215987Saoki error("Too few subscripts (%d given, %d required)", 15315987Saoki s, p->value[0]); 15415987Saoki } 15514739Sthien switch ( co->tag ) { 156765Speter case T_PTR: 157765Speter /* 158765Speter * Pointer qualification. 159765Speter */ 160765Speter if ( f ) { 1613832Speter putLV( firstsymbol , firstbn , o , 1623832Speter firstextra_flags , p2type( p ) ); 163765Speter firstsymbol = 0; 164765Speter } else { 165765Speter if (o) { 166*18465Sralph putleaf( PCC_ICON , o , 0 , PCCT_INT 16714739Sthien , (char *) 0 ); 168*18465Sralph putop( PCC_PLUS , PCCTM_PTR | PCCT_CHAR ); 169765Speter } 170765Speter } 171765Speter /* 172765Speter * Pointer cannot be 173765Speter * nil and file cannot 174765Speter * be at end-of-file. 175765Speter * the appropriate function name is 176765Speter * already out there from nilfnil. 177765Speter */ 178765Speter if ( p -> class == PTR ) { 179765Speter /* 180765Speter * this is the indirection from 181765Speter * the address of the pointer 182765Speter * to the pointer itself. 183765Speter * kirk sez: 184765Speter * fnil doesn't want this. 185765Speter * and does it itself for files 186765Speter * since only it knows where the 187765Speter * actual window is. 188765Speter * but i have to do this for 189765Speter * regular pointers. 190765Speter */ 191*18465Sralph putop( PCCOM_UNARY PCC_MUL , p2type( p ) ); 192765Speter if ( opt( 't' ) ) { 193*18465Sralph putop( PCC_CALL , PCCT_INT ); 194765Speter } 195765Speter } else { 196*18465Sralph putop( PCC_CALL , PCCT_INT ); 197765Speter } 198765Speter f = o = 0; 199765Speter continue; 200765Speter case T_ARGL: 201765Speter case T_ARY: 202765Speter if ( f ) { 2033832Speter putLV( firstsymbol , firstbn , o , 2043832Speter firstextra_flags , p2type( p ) ); 205765Speter firstsymbol = 0; 206765Speter } else { 207765Speter if (o) { 208*18465Sralph putleaf( PCC_ICON , o , 0 , PCCT_INT 20914739Sthien , (char *) 0 ); 210*18465Sralph putop( PCC_PLUS , PCCT_INT ); 211765Speter } 212765Speter } 21315965Smckusick s = arycod( p , co->ary_node.expr_list, s); 21415965Smckusick if (s == p->value[0]) { 21515965Smckusick s = 0; 21615965Smckusick } else { 21715965Smckusick p = lastp; 21815965Smckusick } 219765Speter f = o = 0; 220765Speter continue; 221765Speter case T_FIELD: 222765Speter /* 223765Speter * Field names are just 224765Speter * an offset with some 225765Speter * semantic checking. 226765Speter */ 22714739Sthien p = reclook(p, co->field_node.id_ptr); 228765Speter o += p -> value[0]; 229765Speter continue; 230765Speter default: 231765Speter panic("lval2"); 232765Speter } 233765Speter } 23415987Saoki if (s) { 23515987Saoki error("Too few subscripts (%d given, %d required)", 23615987Saoki s, p->type->value[0]); 23715987Saoki return NLNIL; 23815987Saoki } 239765Speter if (f) { 2403375Speter if ( required == LREQ ) { 2413832Speter putLV( firstsymbol , firstbn , o , 2423832Speter firstextra_flags , p2type( p -> type ) ); 2433375Speter } else { 2443832Speter putRV( firstsymbol , firstbn , o , 2453832Speter firstextra_flags , p2type( p -> type ) ); 2463375Speter } 247765Speter } else { 248765Speter if (o) { 249*18465Sralph putleaf( PCC_ICON , o , 0 , PCCT_INT , (char *) 0 ); 250*18465Sralph putop( PCC_PLUS , PCCT_INT ); 251765Speter } 2523375Speter if ( required == RREQ ) { 253*18465Sralph putop( PCCOM_UNARY PCC_MUL , p2type( p -> type ) ); 2543375Speter } 255765Speter } 256765Speter return ( p -> type ); 257765Speter } 258765Speter 259765Speter /* 260765Speter * this recursively follows done a list of qualifications 261765Speter * and puts out the beginnings of calls to fnil for files 262765Speter * or nil for pointers (if checking is on) on the way back. 263765Speter * this returns true or false. 264765Speter */ 26514739Sthien bool 266765Speter nilfnil( p , c , modflag , firstp , r2 ) 26714739Sthien struct nl *p; 26814739Sthien struct tnode *c; 269765Speter int modflag; 270765Speter struct nl *firstp; 271765Speter char *r2; /* no, not r2-d2 */ 272765Speter { 27314739Sthien struct tnode *co; 274765Speter struct nl *lastp; 275765Speter int t; 27615965Smckusick static int s = 0; 277765Speter 27814739Sthien if ( c == TR_NIL ) { 279765Speter return TRUE; 280765Speter } 28114739Sthien co = ( c->list_node.list ); 28214739Sthien if ( co == TR_NIL ) { 283765Speter return FALSE; 284765Speter } 285765Speter lastp = p; 286765Speter p = p -> type; 28714739Sthien if ( p == NLNIL ) { 288765Speter return FALSE; 289765Speter } 29014739Sthien switch ( co->tag ) { 291765Speter case T_PTR: 292765Speter /* 293765Speter * Pointer qualification. 294765Speter */ 295765Speter lastp -> nl_flags |= NUSED; 296765Speter if ( p -> class != PTR && p -> class != FILET) { 297765Speter error("^ allowed only on files and pointers, not on %ss", nameof(p)); 298765Speter goto bad; 299765Speter } 300765Speter break; 301765Speter case T_ARGL: 302765Speter if ( p -> class != ARRAY ) { 303765Speter if ( lastp == firstp ) { 304765Speter error("%s is a %s, not a function", r2, classes[firstp -> class]); 305765Speter } else { 306765Speter error("Illegal function qualificiation"); 307765Speter } 308765Speter return FALSE; 309765Speter } 310765Speter recovered(); 311765Speter error("Pascal uses [] for subscripting, not ()"); 312765Speter /* and fall through */ 313765Speter case T_ARY: 314765Speter if ( p -> class != ARRAY ) { 315765Speter error("Subscripting allowed only on arrays, not on %ss", nameof(p)); 316765Speter goto bad; 317765Speter } 318765Speter codeoff(); 31915965Smckusick s = arycod( p , co->ary_node.expr_list , s ); 320765Speter codeon(); 32115965Smckusick switch ( s ) { 322765Speter case 0: 323765Speter return FALSE; 324765Speter case -1: 325765Speter goto bad; 326765Speter } 32715965Smckusick if (s == p->value[0]) { 32815965Smckusick s = 0; 32915965Smckusick } else { 33015965Smckusick p = lastp; 33115965Smckusick } 332765Speter break; 333765Speter case T_FIELD: 334765Speter /* 335765Speter * Field names are just 336765Speter * an offset with some 337765Speter * semantic checking. 338765Speter */ 339765Speter if ( p -> class != RECORD ) { 340765Speter error(". allowed only on records, not on %ss", nameof(p)); 341765Speter goto bad; 342765Speter } 34314739Sthien if ( co->field_node.id_ptr == NIL ) { 344765Speter return FALSE; 345765Speter } 34614739Sthien p = reclook( p , co->field_node.id_ptr ); 347765Speter if ( p == NIL ) { 34814739Sthien error("%s is not a field in this record", co->field_node.id_ptr); 349765Speter goto bad; 350765Speter } 351765Speter if ( modflag & MOD ) { 352765Speter p -> nl_flags |= NMOD; 353765Speter } 35414739Sthien if ((modflag & NOUSE) == 0 || lptr(c->field_node.other )) { 355765Speter p -> nl_flags |= NUSED; 356765Speter } 357765Speter break; 358765Speter default: 359765Speter panic("nilfnil"); 360765Speter } 361765Speter /* 362765Speter * recursive call, check the rest of the qualifications. 363765Speter */ 36414739Sthien if ( ! nilfnil( p , c->list_node.next , modflag , firstp , r2 ) ) { 365765Speter return FALSE; 366765Speter } 367765Speter /* 368765Speter * the point of all this. 369765Speter */ 37014739Sthien if ( co->tag == T_PTR ) { 371765Speter if ( p -> class == PTR ) { 372765Speter if ( opt( 't' ) ) { 373*18465Sralph putleaf( PCC_ICON , 0 , 0 374*18465Sralph , PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR ) 375765Speter , "_NIL" ); 376765Speter } 377765Speter } else { 378*18465Sralph putleaf( PCC_ICON , 0 , 0 379*18465Sralph , PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR ) 380765Speter , "_FNIL" ); 381765Speter } 382765Speter } 383765Speter return TRUE; 384765Speter bad: 385765Speter cerror("Error occurred on qualification of %s", r2); 386765Speter return FALSE; 387765Speter } 388765Speter #endif PC 389