1*22184Sdist /* 2*22184Sdist * Copyright (c) 1980 Regents of the University of California. 3*22184Sdist * All rights reserved. The Berkeley software License Agreement 4*22184Sdist * specifies the terms and conditions for redistribution. 5*22184Sdist */ 6765Speter 714739Sthien #ifndef lint 8*22184Sdist static char sccsid[] = "@(#)pclval.c 5.1 (Berkeley) 06/05/85"; 9*22184Sdist #endif not lint 10765Speter 11*22184Sdist 12765Speter #include "whoami.h" 13765Speter #include "0.h" 14765Speter #include "tree.h" 15765Speter #include "opcode.h" 16765Speter #include "objfmt.h" 1714739Sthien #include "tree_ty.h" 18765Speter #ifdef PC 19765Speter /* 20765Speter * and the rest of the file 21765Speter */ 22765Speter # include "pc.h" 2318465Sralph # include <pcc.h> 24765Speter 25765Speter extern int flagwas; 26765Speter /* 27765Speter * pclvalue computes the address 28765Speter * of a qualified name and 29765Speter * leaves it on the stack. 30765Speter * for pc, it can be asked for either an lvalue or an rvalue. 31765Speter * the semantics are the same, only the code is different. 32765Speter * for putting out calls to check for nil and fnil, 33765Speter * we have to traverse the list of qualifications twice: 34765Speter * once to put out the calls and once to put out the address to be checked. 35765Speter */ 36765Speter struct nl * 3714739Sthien pclvalue( var , modflag , required ) 3814739Sthien struct tnode *var; 39765Speter int modflag; 40765Speter int required; 41765Speter { 42765Speter register struct nl *p; 4314739Sthien register struct tnode *c, *co; 44765Speter int f, o; 4514739Sthien struct tnode l_node, tr; 4614739Sthien VAR_NODE *v_node; 4714739Sthien LIST_NODE *tr_ptr; 4815965Smckusick struct nl *firstp, *lastp; 49765Speter char *firstsymbol; 503832Speter char firstextra_flags; 51765Speter int firstbn; 5215965Smckusick int s; 53765Speter 5414739Sthien if ( var == TR_NIL ) { 5514739Sthien return NLNIL; 56765Speter } 5714739Sthien if ( nowexp( var ) ) { 5814739Sthien return NLNIL; 59765Speter } 6014739Sthien if ( var->tag != T_VAR ) { 61765Speter error("Variable required"); /* Pass mesgs down from pt of call ? */ 6214739Sthien return NLNIL; 63765Speter } 6414739Sthien v_node = &(var->var_node); 6514739Sthien firstp = p = lookup( v_node->cptr ); 6614739Sthien if ( p == NLNIL ) { 6714739Sthien return NLNIL; 68765Speter } 69765Speter firstsymbol = p -> symbol; 70765Speter firstbn = bn; 713832Speter firstextra_flags = p -> extra_flags; 7214739Sthien c = v_node->qual; 73765Speter if ( ( modflag & NOUSE ) && ! lptr( c ) ) { 74765Speter p -> nl_flags = flagwas; 75765Speter } 76765Speter if ( modflag & MOD ) { 77765Speter p -> nl_flags |= NMOD; 78765Speter } 79765Speter /* 80765Speter * Only possibilities for p -> class here 81765Speter * are the named classes, i.e. CONST, TYPE 82765Speter * VAR, PROC, FUNC, REF, or a WITHPTR. 83765Speter */ 8414739Sthien tr_ptr = &(l_node.list_node); 85765Speter if ( p -> class == WITHPTR ) { 86765Speter /* 87765Speter * Construct the tree implied by 88765Speter * the with statement 89765Speter */ 9014739Sthien l_node.tag = T_LISTPP; 9114739Sthien tr_ptr->list = &(tr); 9214739Sthien tr_ptr->next = v_node->qual; 9314739Sthien tr.tag = T_FIELD; 9414739Sthien tr.field_node.id_ptr = v_node->cptr; 9514739Sthien c = &(l_node); 96765Speter } 97765Speter /* 98765Speter * this not only puts out the names of functions to call 99765Speter * but also does all the semantic checking of the qualifications. 100765Speter */ 10114739Sthien if ( ! nilfnil( p , c , modflag , firstp , v_node->cptr ) ) { 10214739Sthien return NLNIL; 103765Speter } 104765Speter switch (p -> class) { 105765Speter case WITHPTR: 106765Speter case REF: 107765Speter /* 108765Speter * Obtain the indirect word 109765Speter * of the WITHPTR or REF 110765Speter * as the base of our lvalue 111765Speter */ 1123832Speter putRV( firstsymbol , firstbn , p -> value[ 0 ] , 1133832Speter firstextra_flags , p2type( p ) ); 114765Speter firstsymbol = 0; 115765Speter f = 0; /* have an lv on stack */ 116765Speter o = 0; 117765Speter break; 118765Speter case VAR: 11915965Smckusick if (p->type->class != CRANGE) { 12015965Smckusick f = 1; /* no lv on stack yet */ 12115965Smckusick o = p -> value[0]; 12215965Smckusick } else { 12315965Smckusick error("Conformant array bound %s found where variable required", p->symbol); 12415965Smckusick return(NIL); 12515965Smckusick } 126765Speter break; 127765Speter default: 128765Speter error("%s %s found where variable required", classes[p -> class], p -> symbol); 12914739Sthien return (NLNIL); 130765Speter } 131765Speter /* 132765Speter * Loop and handle each 133765Speter * qualification on the name 134765Speter */ 1353375Speter if ( c == NIL && 1363375Speter ( modflag & ASGN ) && 1373583Speter ( p -> value[ NL_FORV ] & FORVAR ) ) { 138765Speter error("Can't modify the for variable %s in the range of the loop", p -> symbol); 13914739Sthien return (NLNIL); 140765Speter } 14115965Smckusick s = 0; 14214739Sthien for ( ; c != TR_NIL ; c = c->list_node.next ) { 14314739Sthien co = c->list_node.list; 14414739Sthien if ( co == TR_NIL ) { 14514739Sthien return NLNIL; 146765Speter } 14715965Smckusick lastp = p; 148765Speter p = p -> type; 14914739Sthien if ( p == NLNIL ) { 15014739Sthien return NLNIL; 151765Speter } 15215987Saoki /* 15315987Saoki * If we haven't seen enough subscripts, and the next 15415987Saoki * qualification isn't array reference, then it's an error. 15515987Saoki */ 15615987Saoki if (s && co->tag != T_ARY) { 15715987Saoki error("Too few subscripts (%d given, %d required)", 15815987Saoki s, p->value[0]); 15915987Saoki } 16014739Sthien switch ( co->tag ) { 161765Speter case T_PTR: 162765Speter /* 163765Speter * Pointer qualification. 164765Speter */ 165765Speter if ( f ) { 1663832Speter putLV( firstsymbol , firstbn , o , 1673832Speter firstextra_flags , p2type( p ) ); 168765Speter firstsymbol = 0; 169765Speter } else { 170765Speter if (o) { 17118465Sralph putleaf( PCC_ICON , o , 0 , PCCT_INT 17214739Sthien , (char *) 0 ); 17318465Sralph putop( PCC_PLUS , PCCTM_PTR | PCCT_CHAR ); 174765Speter } 175765Speter } 176765Speter /* 177765Speter * Pointer cannot be 178765Speter * nil and file cannot 179765Speter * be at end-of-file. 180765Speter * the appropriate function name is 181765Speter * already out there from nilfnil. 182765Speter */ 183765Speter if ( p -> class == PTR ) { 184765Speter /* 185765Speter * this is the indirection from 186765Speter * the address of the pointer 187765Speter * to the pointer itself. 188765Speter * kirk sez: 189765Speter * fnil doesn't want this. 190765Speter * and does it itself for files 191765Speter * since only it knows where the 192765Speter * actual window is. 193765Speter * but i have to do this for 194765Speter * regular pointers. 195765Speter */ 19618465Sralph putop( PCCOM_UNARY PCC_MUL , p2type( p ) ); 197765Speter if ( opt( 't' ) ) { 19818465Sralph putop( PCC_CALL , PCCT_INT ); 199765Speter } 200765Speter } else { 20118465Sralph putop( PCC_CALL , PCCT_INT ); 202765Speter } 203765Speter f = o = 0; 204765Speter continue; 205765Speter case T_ARGL: 206765Speter case T_ARY: 207765Speter if ( f ) { 2083832Speter putLV( firstsymbol , firstbn , o , 2093832Speter firstextra_flags , p2type( p ) ); 210765Speter firstsymbol = 0; 211765Speter } else { 212765Speter if (o) { 21318465Sralph putleaf( PCC_ICON , o , 0 , PCCT_INT 21414739Sthien , (char *) 0 ); 21518465Sralph putop( PCC_PLUS , PCCT_INT ); 216765Speter } 217765Speter } 21815965Smckusick s = arycod( p , co->ary_node.expr_list, s); 21915965Smckusick if (s == p->value[0]) { 22015965Smckusick s = 0; 22115965Smckusick } else { 22215965Smckusick p = lastp; 22315965Smckusick } 224765Speter f = o = 0; 225765Speter continue; 226765Speter case T_FIELD: 227765Speter /* 228765Speter * Field names are just 229765Speter * an offset with some 230765Speter * semantic checking. 231765Speter */ 23214739Sthien p = reclook(p, co->field_node.id_ptr); 233765Speter o += p -> value[0]; 234765Speter continue; 235765Speter default: 236765Speter panic("lval2"); 237765Speter } 238765Speter } 23915987Saoki if (s) { 24015987Saoki error("Too few subscripts (%d given, %d required)", 24115987Saoki s, p->type->value[0]); 24215987Saoki return NLNIL; 24315987Saoki } 244765Speter if (f) { 2453375Speter if ( required == LREQ ) { 2463832Speter putLV( firstsymbol , firstbn , o , 2473832Speter firstextra_flags , p2type( p -> type ) ); 2483375Speter } else { 2493832Speter putRV( firstsymbol , firstbn , o , 2503832Speter firstextra_flags , p2type( p -> type ) ); 2513375Speter } 252765Speter } else { 253765Speter if (o) { 25418465Sralph putleaf( PCC_ICON , o , 0 , PCCT_INT , (char *) 0 ); 25518465Sralph putop( PCC_PLUS , PCCT_INT ); 256765Speter } 2573375Speter if ( required == RREQ ) { 25818465Sralph putop( PCCOM_UNARY PCC_MUL , p2type( p -> type ) ); 2593375Speter } 260765Speter } 261765Speter return ( p -> type ); 262765Speter } 263765Speter 264765Speter /* 265765Speter * this recursively follows done a list of qualifications 266765Speter * and puts out the beginnings of calls to fnil for files 267765Speter * or nil for pointers (if checking is on) on the way back. 268765Speter * this returns true or false. 269765Speter */ 27014739Sthien bool 271765Speter nilfnil( p , c , modflag , firstp , r2 ) 27214739Sthien struct nl *p; 27314739Sthien struct tnode *c; 274765Speter int modflag; 275765Speter struct nl *firstp; 276765Speter char *r2; /* no, not r2-d2 */ 277765Speter { 27814739Sthien struct tnode *co; 279765Speter struct nl *lastp; 280765Speter int t; 28115965Smckusick static int s = 0; 282765Speter 28314739Sthien if ( c == TR_NIL ) { 284765Speter return TRUE; 285765Speter } 28614739Sthien co = ( c->list_node.list ); 28714739Sthien if ( co == TR_NIL ) { 288765Speter return FALSE; 289765Speter } 290765Speter lastp = p; 291765Speter p = p -> type; 29214739Sthien if ( p == NLNIL ) { 293765Speter return FALSE; 294765Speter } 29514739Sthien switch ( co->tag ) { 296765Speter case T_PTR: 297765Speter /* 298765Speter * Pointer qualification. 299765Speter */ 300765Speter lastp -> nl_flags |= NUSED; 301765Speter if ( p -> class != PTR && p -> class != FILET) { 302765Speter error("^ allowed only on files and pointers, not on %ss", nameof(p)); 303765Speter goto bad; 304765Speter } 305765Speter break; 306765Speter case T_ARGL: 307765Speter if ( p -> class != ARRAY ) { 308765Speter if ( lastp == firstp ) { 309765Speter error("%s is a %s, not a function", r2, classes[firstp -> class]); 310765Speter } else { 311765Speter error("Illegal function qualificiation"); 312765Speter } 313765Speter return FALSE; 314765Speter } 315765Speter recovered(); 316765Speter error("Pascal uses [] for subscripting, not ()"); 317765Speter /* and fall through */ 318765Speter case T_ARY: 319765Speter if ( p -> class != ARRAY ) { 320765Speter error("Subscripting allowed only on arrays, not on %ss", nameof(p)); 321765Speter goto bad; 322765Speter } 323765Speter codeoff(); 32415965Smckusick s = arycod( p , co->ary_node.expr_list , s ); 325765Speter codeon(); 32615965Smckusick switch ( s ) { 327765Speter case 0: 328765Speter return FALSE; 329765Speter case -1: 330765Speter goto bad; 331765Speter } 33215965Smckusick if (s == p->value[0]) { 33315965Smckusick s = 0; 33415965Smckusick } else { 33515965Smckusick p = lastp; 33615965Smckusick } 337765Speter break; 338765Speter case T_FIELD: 339765Speter /* 340765Speter * Field names are just 341765Speter * an offset with some 342765Speter * semantic checking. 343765Speter */ 344765Speter if ( p -> class != RECORD ) { 345765Speter error(". allowed only on records, not on %ss", nameof(p)); 346765Speter goto bad; 347765Speter } 34814739Sthien if ( co->field_node.id_ptr == NIL ) { 349765Speter return FALSE; 350765Speter } 35114739Sthien p = reclook( p , co->field_node.id_ptr ); 352765Speter if ( p == NIL ) { 35314739Sthien error("%s is not a field in this record", co->field_node.id_ptr); 354765Speter goto bad; 355765Speter } 356765Speter if ( modflag & MOD ) { 357765Speter p -> nl_flags |= NMOD; 358765Speter } 35914739Sthien if ((modflag & NOUSE) == 0 || lptr(c->field_node.other )) { 360765Speter p -> nl_flags |= NUSED; 361765Speter } 362765Speter break; 363765Speter default: 364765Speter panic("nilfnil"); 365765Speter } 366765Speter /* 367765Speter * recursive call, check the rest of the qualifications. 368765Speter */ 36914739Sthien if ( ! nilfnil( p , c->list_node.next , modflag , firstp , r2 ) ) { 370765Speter return FALSE; 371765Speter } 372765Speter /* 373765Speter * the point of all this. 374765Speter */ 37514739Sthien if ( co->tag == T_PTR ) { 376765Speter if ( p -> class == PTR ) { 377765Speter if ( opt( 't' ) ) { 37818465Sralph putleaf( PCC_ICON , 0 , 0 37918465Sralph , PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR ) 380765Speter , "_NIL" ); 381765Speter } 382765Speter } else { 38318465Sralph putleaf( PCC_ICON , 0 , 0 38418465Sralph , PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR ) 385765Speter , "_FNIL" ); 386765Speter } 387765Speter } 388765Speter return TRUE; 389765Speter bad: 390765Speter cerror("Error occurred on qualification of %s", r2); 391765Speter return FALSE; 392765Speter } 393765Speter #endif PC 394