/* D E S I G N A T O R E V A L U A T I O N */ #ifndef NORCSID static char *RcsId = "$Header$"; #endif /* Code generation for designators. This file contains some routines that generate code common to address as well as value computations, and leave a description in a "desig" structure. It also contains routines to load an address, load a value or perform a store. */ #include "debug.h" #include #include #include #include "type.h" #include "def.h" #include "scope.h" #include "desig.h" #include "LLlex.h" #include "node.h" extern int proclevel; struct desig Desig; struct desig InitDesig = {DSG_INIT, 0, 0}; CodeValue(ds, size) register struct desig *ds; arith size; { /* Generate code to load the value of the designator described in "ds" */ switch(ds->dsg_kind) { case DSG_LOADED: break; case DSG_FIXED: if (size == word_size) { if (ds->dsg_name) { C_loe_dnam(ds->dsg_name, ds->dsg_offset); } else C_lol(ds->dsg_offset); break; } if (size == dword_size) { if (ds->dsg_name) { C_lde_dnam(ds->dsg_name, ds->dsg_offset); } else C_ldl(ds->dsg_offset); break; } /* Fall through */ case DSG_PLOADED: case DSG_PFIXED: CodeAddress(ds); C_loi(size); break; case DSG_INDEXED: C_lar(word_size); break; default: crash("(CodeValue)"); } ds->dsg_kind = DSG_LOADED; } CodeStore(ds, size) register struct desig *ds; arith size; { /* Generate code to store the value on the stack in the designator described in "ds" */ switch(ds->dsg_kind) { case DSG_FIXED: if (size == word_size) { if (ds->dsg_name) { C_ste_dnam(ds->dsg_name, ds->dsg_offset); } else C_stl(ds->dsg_offset); break; } if (size == dword_size) { if (ds->dsg_name) { C_sde_dnam(ds->dsg_name, ds->dsg_offset); } else C_sdl(ds->dsg_offset); break; } /* Fall through */ case DSG_PLOADED: case DSG_PFIXED: CodeAddress(ds); C_sti(size); break; case DSG_INDEXED: C_sar(word_size); break; default: crash("(CodeStore)"); } ds->dsg_kind = DSG_INIT; } CodeAddress(ds) register struct desig *ds; { /* Generate code to load the address of the designator described in "ds" */ switch(ds->dsg_kind) { case DSG_PLOADED: if (ds->dsg_offset) { C_adp(ds->dsg_offset); } break; case DSG_FIXED: if (ds->dsg_name) { C_lae_dnam(ds->dsg_name, ds->dsg_offset); break; } C_lal(ds->dsg_offset); break; case DSG_PFIXED: ds->dsg_kind = DSG_FIXED; CodeValue(ds, pointer_size); break; case DSG_INDEXED: C_aar(word_size); break; default: crash("(CodeAddress)"); } ds->dsg_offset = 0; ds->dsg_kind = DSG_PLOADED; } CodeFieldDesig(df, ds) register struct def *df; register struct desig *ds; { /* Generate code for a field designator. Only the code common for address as well as value computation is generated, and the resulting information on where to find the designator is placed in "ds". "df" indicates the definition of the field. */ register struct withdesig *wds; if (ds->dsg_kind == DSG_INIT) { /* In a WITH statement. We must find the designator in the WITH statement, and act as if the field is a selection of this designator. So, first find the right WITH statement, which is the first one of the proper record type. Notice that the proper record type is recognized by its scope indication. */ wds = WithDesigs; assert(wds != 0); while (wds->w_scope != df->df_scope) { wds = wds->w_next; assert(wds != 0); } /* Found it. Now, act like it was a selection. */ *ds = wds->w_desig; assert(ds->dsg_kind == DSG_PFIXED); } switch(ds->dsg_kind) { case DSG_PLOADED: case DSG_FIXED: ds->dsg_offset += df->fld_off; break; case DSG_PFIXED: case DSG_INDEXED: CodeAddress(ds); ds->dsg_kind = DSG_PLOADED; ds->dsg_offset = df->fld_off; break; default: crash("(CodeFieldDesig)"); } } CodeVarDesig(df, ds) register struct def *df; register struct desig *ds; { /* Generate code for a variable represented by a "def" structure. Of course, there are numerous cases: the variable is local, it is a value parameter, it is a var parameter, it is one of those of an enclosing procedure, or it is global. */ register struct scope *sc = df->df_scope; /* Selections from a module are handled earlier, when identifying the variable, so ... */ assert(ds->dsg_kind == DSG_INIT); if (df->var_addrgiven) { /* the programmer specified an address in the declaration of the variable. Generate code to push the address. */ CodeConst(df->var_off, pointer_size); ds->dsg_kind = DSG_PLOADED; ds->dsg_offset = 0; df->df_flags |= D_NOREG; return; } if (df->var_name) { /* this variable has been given a name, so it is global. It is directly accessible. */ ds->dsg_name = df->var_name; ds->dsg_offset = 0; ds->dsg_kind = DSG_FIXED; df->df_flags |= D_NOREG; return; } if (sc->sc_level == 0) { /* the variable is global, but declared in a module local to the implementation or program module. Such variables can be accessed through an offset from the name of the module. */ ds->dsg_name = &(sc->sc_name[1]); ds->dsg_offset = df->var_off; ds->dsg_kind = DSG_FIXED; df->df_flags |= D_NOREG; return; } if (sc->sc_level != proclevel) { /* the variable is local to a statically enclosing procedure. */ assert(proclevel > sc->sc_level); if (df->df_flags & (D_VARPAR|D_VALPAR)) { /* value or var parameter */ C_lxa((arith) (proclevel - sc->sc_level)); if ((df->df_flags & D_VARPAR) || IsConformantArray(df->df_type)) { /* var parameter */ C_adp(df->var_off); C_loi(pointer_size); ds->dsg_offset = 0; ds->dsg_kind = DSG_PLOADED; return; } } else C_lxl((arith) (proclevel - sc->sc_level)); ds->dsg_kind = DSG_PLOADED; ds->dsg_offset = df->var_off; df->df_flags |= D_NOREG; return; } /* Now, finally, we have a local variable or a local parameter */ if ((df->df_flags & D_VARPAR) || IsConformantArray(df->df_type)) { /* a var parameter; address directly accessible. */ ds->dsg_kind = DSG_PFIXED; } else ds->dsg_kind = DSG_FIXED; ds->dsg_offset =df->var_off; } CodeDesig(nd, ds) register struct node *nd; register struct desig *ds; { /* Generate code for a designator. Use divide and conquer principle */ register struct def *df; switch(nd->nd_class) { /* Divide */ case Def: df = nd->nd_def; df->df_flags |= D_USED; switch(df->df_kind) { case D_FIELD: CodeFieldDesig(df, ds); break; case D_VARIABLE: CodeVarDesig(df, ds); break; default: crash("(CodeDesig) Def"); } break; case Link: assert(nd->nd_symb == '.'); CodeDesig(nd->nd_left, ds); CodeFieldDesig(nd->nd_def, ds); break; case Oper: assert(nd->nd_symb == '['); CodeDesig(nd->nd_left, ds); CodeAddress(ds); CodePExpr(nd->nd_right); if (nd->nd_right->nd_type->tp_size > word_size) { CodeCoercion(nd->nd_right->nd_type, int_type); } /* Now load address of descriptor */ if (IsConformantArray(nd->nd_left->nd_type)) { assert(nd->nd_left->nd_class == Def); df = nd->nd_left->nd_def; if (proclevel > df->df_scope->sc_level) { C_lxa(proclevel - df->df_scope->sc_level); C_adp(df->var_off + pointer_size); } else C_lal(df->var_off + pointer_size); } else { C_lae_dlb(nd->nd_left->nd_type->arr_descr, (arith) 0); } ds->dsg_kind = DSG_INDEXED; break; case Uoper: assert(nd->nd_symb == '^'); CodeDesig(nd->nd_right, ds); switch(ds->dsg_kind) { case DSG_LOADED: ds->dsg_kind = DSG_PLOADED; break; case DSG_INDEXED: case DSG_PLOADED: case DSG_PFIXED: CodeValue(ds, pointer_size); ds->dsg_kind = DSG_PLOADED; ds->dsg_offset = 0; break; case DSG_FIXED: ds->dsg_kind = DSG_PFIXED; break; default: crash("(CodeDesig) Uoper"); } break; default: crash("(CodeDesig) class"); } }