148116Sbostic /*-
2*62213Sbostic * Copyright (c) 1980, 1993
3*62213Sbostic * The Regents of the University of California. All rights reserved.
448116Sbostic *
548116Sbostic * %sccs.include.redist.c%
622184Sdist */
7765Speter
814739Sthien #ifndef lint
9*62213Sbostic static char sccsid[] = "@(#)pclval.c 8.1 (Berkeley) 06/06/93";
1048116Sbostic #endif /* not lint */
11765Speter
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 *
pclvalue(var,modflag,required)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
nilfnil(p,c,modflag,firstp,r2)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