/* * inline.c - routines to put run-time routines in-line. */ #include "../h/gsupport.h" #include "ctrans.h" #include "ccode.h" #include "csym.h" #include "ctree.h" #include "cproto.h" #include "cglobals.h" /* * Prototypes for static functions. */ static void arth_arg ( struct il_code *var, struct val_loc *v_orig, int chk, struct code *cnv); static int body_fnc (struct il_code *il); static void chkforblk (void); static void cnv_dest (int loc, int is_cstr, struct il_code *src, int sym_indx, struct il_c *dest, struct code *cd, int i); static void dwrd_asgn (struct val_loc *vloc, char *typ); static struct il_c *line_ilc (struct il_c *ilc); static int gen_if (struct code *cond_cd, struct il_code *il_then, struct il_code *il_else, struct val_loc **locs); static int gen_il (struct il_code *il); static void gen_ilc (struct il_c *il); static void gen_ilret (struct il_c *ilc); static int gen_tcase (struct il_code *il, int has_dflt); static void il_var (struct il_code *il, struct code *cd, int indx); static void mrg_locs (struct val_loc **locs); static struct code *oper_lbl (char *s); static void part_asgn (struct val_loc *vloc, char *asgn, struct il_c *value); static void rstr_locs (struct val_loc **locs); static struct val_loc **sav_locs (void); static void sub_ilc (struct il_c *ilc, struct code *cd, int indx); /* * There are many parameters that are shared by multiple routines. There * are copied into statics. */ static struct val_loc *rslt; /* result location */ static struct code **scont_strt; /* label following operation code */ static struct code **scont_fail; /* resumption label for in-line suspend */ static struct c_fnc *cont; /* success continuation */ static struct implement *impl; /* data base entry for operation */ static int nsyms; /* number symbols in operation symbol table */ static int n_vararg; /* size of variable part of arg list */ static nodeptr intrnl_lftm; /* lifetime of internal variables */ static struct val_loc **tended; /* array of tended locals */ /* * gen_inlin - generate in-line code for an operation. */ void gen_inlin(il, r, strt, fail, c, ip, ns, st, n, dcl_var, n_va) struct il_code *il; struct val_loc *r; struct code **strt; struct code **fail; struct c_fnc *c; struct implement *ip; int ns; struct op_symentry *st; nodeptr n; int dcl_var; int n_va; { struct code *cd; struct val_loc *tnd; int i; /* * Copy arguments in to globals. */ rslt = r; scont_strt = strt; scont_fail = fail; cont = c; impl = ip; nsyms = ns; cur_symtab = st; intrnl_lftm = n->intrnl_lftm; cur_symtyps = n->symtyps; n_vararg = n_va; /* * Generate code to initialize local tended descriptors and determine * how to access the descriptors. */ for (i = 0; i < impl->ntnds; ++i) { if (cur_symtab[dcl_var].n_refs + cur_symtab[dcl_var].n_mods > 0) { tnd = chk_alc(NULL, n->intrnl_lftm); switch (impl->tnds[i].var_type) { case TndDesc: cur_symtab[dcl_var].loc = tnd; break; case TndStr: cd = alc_ary(2); cd->ElemTyp(0) = A_ValLoc; cd->ValLoc(0) = tnd; cd->ElemTyp(1) = A_Str; cd->Str(1) = " = emptystr;"; cd_add(cd); cur_symtab[dcl_var].loc = loc_cpy(tnd, M_CharPtr); break; case TndBlk: cd = alc_ary(2); cd->ElemTyp(0) = A_ValLoc; cd->ValLoc(0) = tnd; cd->ElemTyp(1) = A_Str; cd->Str(1) = " = nullptr;"; cd_add(cd); cur_symtab[dcl_var].loc = loc_cpy(tnd, M_BlkPtr); cur_symtab[dcl_var].loc->blk_name = impl->tnds[i].blk_name; break; } if (impl->tnds[i].init != NULL) { cd = alc_ary(4); cd->ElemTyp(0) = A_ValLoc; cd->ValLoc(0) = cur_symtab[dcl_var].loc; cd->ElemTyp(1) = A_Str; cd->Str(1) = " = "; sub_ilc(impl->tnds[i].init, cd, 2); cd->ElemTyp(3) = A_Str; cd->Str(3) = ";"; cd_add(cd); } } ++dcl_var; } /* * If there are local non-tended variables, generate code for the * declarations, placing everything in braces. */ if (impl->nvars > 0) { cd = NewCode(0); cd->cd_id = C_LBrack; /* { */ cd_add(cd); for (i = 0; i < impl->nvars; ++i) { if (cur_symtab[dcl_var].n_refs + cur_symtab[dcl_var].n_mods > 0) { gen_ilc(impl->vars[i].dcl); cur_symtab[dcl_var].loc = cvar_loc(impl->vars[i].name); } ++dcl_var; } } gen_il(il); /* generate executable code */ if (impl->nvars > 0) { cd = NewCode(0); cd->cd_id = C_RBrack; /* } */ cd_add(cd); } } /* * gen_il - generate code from a sub-tree of in-line code from the data * base. Determine if execution can continue past this code. * */ static int gen_il(il) struct il_code *il; { struct code *cd; struct code *cd1; struct il_code *il_cond; struct il_code *il_then; struct il_code *il_else; struct il_code *il_t; struct val_loc **locs; struct val_loc **locs1; struct val_loc *tnd; int fall_thru; int cond; int ncases; int indx; int ntended; int i; if (il == NULL) return 1; switch (il->il_type) { case IL_Const: /* should have been replaced by literal node */ return 1; case IL_If1: case IL_If2: /* * if-then or if-then-else statement. */ il_then = il->u[1].fld; if (il->il_type == IL_If2) il_else = il->u[2].fld; else il_else = NULL; il_cond = il->u[0].fld; if (il->u[0].fld->il_type == IL_Bang) { il_cond = il_cond->u[0].fld; il_t = il_then; il_then = il_else; il_else = il_t; } locs = sav_locs(); cond = cond_anlz(il_cond, &cd1); if (cond == (MaybeTrue | MaybeFalse)) fall_thru = gen_if(cd1, il_then, il_else, locs); else { if (cd1 != NULL) { cd_add(cd1); /* condition contains needed conversions */ cd = alc_ary(1); cd->ElemTyp(0) = A_Str; cd->Str(0) = ";"; cd_add(cd); } if (cond == MaybeTrue) fall_thru = gen_il(il_then); else if (cond == MaybeFalse) { locs1 = sav_locs(); rstr_locs(locs); locs = locs1; fall_thru = gen_il(il_else); } mrg_locs(locs); } return fall_thru; case IL_Tcase1: /* * type_case statement with no default clause. */ return gen_tcase(il, 0); case IL_Tcase2: /* * type_case statement with a default clause. */ return gen_tcase(il, 1); case IL_Lcase: /* * len_case statement. Determine which case matches the number * of arguments. */ ncases = il->u[0].n; indx = 1; for (i = 0; i < ncases; ++i) { if (il->u[indx++].n == n_vararg) /* selection number */ return gen_il(il->u[indx].fld); /* action */ ++indx; } return gen_il(il->u[indx].fld); /* default */ case IL_Acase: { /* * arith_case statement. */ struct il_code *var1; struct il_code *var2; struct val_loc *v_orig1; struct val_loc *v_orig2; struct code *cnv1; struct code *cnv2; int maybe_int; int maybe_dbl; int chk1; int chk2; var1 = il->u[0].fld; var2 = il->u[1].fld; v_orig1 = cur_symtab[var1->u[0].n].loc; /* remember for error msgs */ v_orig2 = cur_symtab[var2->u[0].n].loc; /* remember for error msgs */ arth_anlz(var1, var2, &maybe_int, &maybe_dbl, &chk1, &cnv1, &chk2, &cnv2); /* * This statement is in-lined if there is only C integer * arithmetic, only C double arithmetic, or only a run-time * error. */ arth_arg(var1, v_orig1, chk1, cnv1); arth_arg(var2, v_orig2, chk2, cnv2); if (maybe_int) return gen_il(il->u[2].fld); /* C_integer action */ else if (maybe_dbl) return gen_il(il->u[4].fld); /* C_double action */ else return 0; } case IL_Err1: /* * runerr() with no offending value. */ cd = alc_ary(3); cd->ElemTyp(0) = A_Str; cd->Str(0) = "err_msg("; cd->ElemTyp(1) = A_Intgr; cd->Intgr(1) = il->u[0].n; cd->ElemTyp(2) = A_Str; cd->Str(2) = ", NULL);"; cd_add(cd); if (err_conv) cd_add(sig_cd(on_failure, cur_fnc)); for (i = 0; i < nsyms; ++i) cur_symtab[i].loc = NULL; return 0; case IL_Err2: /* * runerr() with an offending value. Note the reference to * the offending value descriptor. */ cd = alc_ary(5); cd->ElemTyp(0) = A_Str; cd->Str(0) = "err_msg("; cd->ElemTyp(1) = A_Intgr; cd->Intgr(1) = il->u[0].n; cd->ElemTyp(2) = A_Str; cd->Str(2) = ", &("; il_var(il->u[1].fld, cd, 3); cd->ElemTyp(4) = A_Str; cd->Str(4) = "));"; cd_add(cd); if (err_conv) cd_add(sig_cd(on_failure, cur_fnc)); for (i = 0; i < nsyms; ++i) cur_symtab[i].loc = NULL; return 0; case IL_Lst: /* * Two consecutive pieces of RTL code. */ fall_thru = gen_il(il->u[0].fld); if (fall_thru) fall_thru = gen_il(il->u[1].fld); return fall_thru; case IL_Block: /* * inline {...} statement. * * Allocate and initialize any tended locals. */ ntended = il->u[1].n; if (ntended > 0) tended = (struct val_loc **)alloc((unsigned int) sizeof(struct val_loc *) * ntended); for (i = 2; i - 2 < ntended; ++i) { tnd = chk_alc(NULL, intrnl_lftm); tended[i - 2] = tnd; switch (il->u[i].n) { case TndDesc: break; case TndStr: cd = alc_ary(2); cd->ElemTyp(0) = A_ValLoc; cd->ValLoc(0) = tnd; cd->ElemTyp(1) = A_Str; cd->Str(1) = " = emptystr;"; cd_add(cd); break; case TndBlk: cd = alc_ary(2); cd->ElemTyp(0) = A_ValLoc; cd->ValLoc(0) = tnd; cd->ElemTyp(1) = A_Str; cd->Str(1) = " = nullptr;"; cd_add(cd); break; } } gen_ilc(il->u[i].c_cd); /* body of block */ /* * See if execution can fall through this code. */ if (il->u[0].n) return 1; else { for (i = 0; i < nsyms; ++i) cur_symtab[i].loc = NULL; return 0; } case IL_Call: /* * call to body function. */ return body_fnc(il); case IL_Abstr: /* * abstract type computation. Only used by type inference. */ return 1; default: fprintf(stderr, "compiler error: unknown info in data base\n"); exit(1); /* NOTREACHED */ } } /* * arth_arg - in-line code to check a conversion for an arith_case statement. */ static void arth_arg(var, v_orig, chk, cnv) struct il_code *var; struct val_loc *v_orig; int chk; struct code *cnv; { struct code *lbl; struct code *cd; if (chk) { /* * Must check the conversion. */ lbl = oper_lbl("converted"); cd_add(lbl); cur_fnc->cursor = lbl->prev; /* code goes before label */ if (cnv != NULL) { cd = NewCode(2); cd->cd_id = C_If; cd->Cond = cnv; cd->ThenStmt = mk_goto(lbl); cd_add(cd); } cd = alc_ary(3); cd->ElemTyp(0) = A_Str; cd->Str(0) = "err_msg(102, &("; cd->ElemTyp(1) = A_ValLoc; cd->ValLoc(1) = v_orig; /* var location before conversion */ cd->ElemTyp(2) = A_Str; cd->Str(2) = "));"; cd_add(cd); if (err_conv) cd_add(sig_cd(on_failure, cur_fnc)); cur_fnc->cursor = lbl; } else if (cnv != NULL) { cd_add(cnv); /* conversion cannot fail */ cd = alc_ary(1); cd->ElemTyp(0) = A_Str; cd->Str(0) = ";"; cd_add(cd); } } /* * body_fnc - generate code to call a body function. */ static int body_fnc(il) struct il_code *il; { struct code *arg_lst; struct code *cd; struct c_fnc *cont1; char *oper_nm; int ret_val; int ret_flag; int need_rslt; int num_sbuf; int num_cbuf; int expl_args; int arglst_sz; /* size of arg list in number of code pieces */ int il_indx; int cd_indx; int proto_prt; int i; /* * Determine if a function prototype has been printed yet for this * body function. */ proto_prt = il->u[0].n; il->u[0].n = 1; /* * Construct the name of the body function. */ oper_nm = (char *)alloc((unsigned int)(strlen(impl->name) + 6)); sprintf(oper_nm, "%c%c%c%c_%s", impl->oper_typ, impl->prefix[0], impl->prefix[1], (char)il->u[1].n, impl->name); /* * Extract from the call the flags and other information describing * the function, then use this information to deduce the arguments * needed by the function. */ ret_val = il->u[2].n; ret_flag = il->u[3].n; need_rslt = il->u[4].n; num_sbuf = il->u[5].n; num_cbuf = il->u[6].n; expl_args = il->u[7].n; /* * determine how large the argument list is. */ arglst_sz = 2 * expl_args - 1; if (num_sbuf > 0) arglst_sz += 3; if (num_cbuf > 0) arglst_sz += 2; if (need_rslt) arglst_sz += 3; if (arglst_sz > 0) arg_lst = alc_ary(arglst_sz); else arg_lst = alc_ary(0); if (!proto_prt) { /* * Determine whether the body function returns a C integer, double, * no value, or a signal. */ switch (ret_val) { case RetInt: fprintf(inclfile, "C_integer %s (", oper_nm); break; case RetDbl: fprintf(inclfile, "double %s (", oper_nm); break; case RetNoVal: fprintf(inclfile, "void %s (", oper_nm); break; case RetSig: fprintf(inclfile, "int %s (", oper_nm); break; } } /* * Produce prototype and code for the explicit arguments in the * function call. Note that the call entry contains C code for both. */ il_indx = 8; cd_indx = 0; while (expl_args--) { if (cd_indx > 0) { /* * Not first entry, precede by ','. */ arg_lst->ElemTyp(cd_indx) = A_Str; /* , */ arg_lst->Str(cd_indx) = ", "; if (!proto_prt) fprintf(inclfile, ", "); ++cd_indx; } if (!proto_prt) fprintf(inclfile, "%s", il->u[il_indx].c_cd->s); /* parameter dcl */ ++il_indx; sub_ilc(il->u[il_indx++].c_cd, arg_lst, cd_indx++); } /* * If string buffers are needed, allocate them and pass pointer to * function. */ if (num_sbuf > 0) { if (cd_indx > 0) { /* * Not first entry, precede by ','. */ arg_lst->ElemTyp(cd_indx) = A_Str; /* , */ arg_lst->Str(cd_indx) = ", "; if (!proto_prt) fprintf(inclfile, ", "); ++cd_indx; } arg_lst->ElemTyp(cd_indx) = A_Str; arg_lst->Str(cd_indx) = "(char (*)[MaxCvtLen])"; ++cd_indx; arg_lst->ElemTyp(cd_indx) = A_SBuf; arg_lst->Intgr(cd_indx) = alc_sbufs(num_sbuf, intrnl_lftm); if (!proto_prt) fprintf(inclfile, "char (*r_sbuf)[MaxCvtLen]"); ++cd_indx; } /* * If cset buffers are needed, allocate them and pass pointer to * function. */ if (num_cbuf > 0) { if (cd_indx > 0) { /* * Not first entry, precede by ','. */ arg_lst->ElemTyp(cd_indx) = A_Str; /* , */ arg_lst->Str(cd_indx) = ", "; if (!proto_prt) fprintf(inclfile, ", "); ++cd_indx; } arg_lst->ElemTyp(cd_indx) = A_CBuf; arg_lst->Intgr(cd_indx) = alc_cbufs(num_cbuf, intrnl_lftm); if (!proto_prt) fprintf(inclfile, "struct b_cset *r_cbuf"); ++cd_indx; } /* * See if the function needs a pointer to the result location * of the operation. */ if (need_rslt) { if (cd_indx > 0) { /* * Not first entry, precede by ','. */ arg_lst->ElemTyp(cd_indx) = A_Str; /* , */ arg_lst->Str(cd_indx) = ", "; if (!proto_prt) fprintf(inclfile, ", "); ++cd_indx; } arg_lst->ElemTyp(cd_indx) = A_Str; /* location of result */ arg_lst->Str(cd_indx) = "&"; ++cd_indx; arg_lst->ElemTyp(cd_indx) = A_ValLoc; arg_lst->ValLoc(cd_indx) = rslt; if (!proto_prt) fprintf(inclfile, "dptr rslt"); ++cd_indx; } if (!proto_prt) { /* * The last possible argument is the success continuation. * If there are no arguments, indicate this in the prototype. */ if (ret_flag & DoesSusp) { if (cd_indx > 0) fprintf(inclfile, ", "); fprintf(inclfile, "continuation succ_cont"); } else if (cd_indx == 0) fprintf(inclfile, "void"); fprintf(inclfile, ");\n"); } /* * Does this call need the success continuation for the operation. */ if (ret_flag & DoesSusp) cont1 = cont; else cont1 = NULL; switch (ret_val) { case RetInt: /* * The body function returns a C integer. */ cd = alc_ary(6); cd->ElemTyp(0) = A_ValLoc; cd->ValLoc(0) = rslt; cd->ElemTyp(1) = A_Str; cd->Str(1) = ".vword.integr = "; cd->ElemTyp(2) = A_Str; cd->Str(2) = oper_nm; cd->ElemTyp(3) = A_Str; cd->Str(3) = "("; cd->ElemTyp(4) = A_Ary; cd->Array(4) = arg_lst; cd->ElemTyp(5) = A_Str; cd->Str(5) = ");"; cd_add(cd); dwrd_asgn(rslt, "Integer"); cd_add(mk_goto(*scont_strt)); break; case RetDbl: /* * The body function returns a C double. */ cd = alc_ary(6); cd->ElemTyp(0) = A_ValLoc; cd->ValLoc(0) = rslt; cd->ElemTyp(1) = A_Str; cd->Str(1) = ".vword.bptr = (union block *)alcreal("; cd->ElemTyp(2) = A_Str; cd->Str(2) = oper_nm; cd->ElemTyp(3) = A_Str; cd->Str(3) = "("; cd->ElemTyp(4) = A_Ary; cd->Array(4) = arg_lst; cd->ElemTyp(5) = A_Str; cd->Str(5) = "));"; cd_add(cd); dwrd_asgn(rslt, "Real"); chkforblk(); /* make sure the block allocation succeeded */ cd_add(mk_goto(*scont_strt)); break; case RetNoVal: /* * The body function does not directly return a value. */ cd = alc_ary(4); cd->ElemTyp(0) = A_Str; cd->Str(0) = oper_nm; cd->ElemTyp(1) = A_Str; cd->Str(1) = "("; cd->ElemTyp(2) = A_Ary; cd->Array(2) = arg_lst; cd->ElemTyp(3) = A_Str; cd->Str(3) = ");"; cd_add(cd); if (ret_flag & DoesFail | (err_conv && (ret_flag & DoesEFail))) cd_add(sig_cd(on_failure, cur_fnc)); else if (ret_flag & DoesRet) cd_add(mk_goto(*scont_strt)); break; case RetSig: /* * The body function returns a signal. */ callo_add(oper_nm, ret_flag, cont1, 0, arg_lst, mk_goto(*scont_strt)); break; } /* * See if execution can fall through this call. */ if (ret_flag & DoesFThru) return 1; else { for (i = 0; i < nsyms; ++i) cur_symtab[i].loc = NULL; return 0; } } /* * il_var - generate code for a possibly subscripted variable into * an element of a code array. */ static void il_var(il, cd, indx) struct il_code *il; struct code *cd; int indx; { struct code *cd1; if (il->il_type == IL_Subscr) { /* * Subscripted variable. */ cd1 = cd; cd = alc_ary(4); cd1->ElemTyp(indx) = A_Ary; cd1->Array(indx) = cd; indx = 0; cd->ElemTyp(1) = A_Str; cd->Str(1) = "["; cd->ElemTyp(2) = A_Intgr; cd->Intgr(2) = il->u[1].n; cd->ElemTyp(3) = A_Str; cd->Str(3) = "]"; } /* * See if this is the result location of the operation or an ordinary * variable. */ cd->ElemTyp(indx) = A_ValLoc; if (il->u[0].n == RsltIndx) cd->ValLoc(indx) = rslt; else cd->ValLoc(indx) = cur_symtab[il->u[0].n].loc; } /* * part_asgn - generate code for an assignment to (part of) a descriptor. */ static void part_asgn(vloc, asgn, value) struct val_loc *vloc; char *asgn; struct il_c *value; { struct code *cd; cd = alc_ary(4); cd->ElemTyp(0) = A_ValLoc; cd->ValLoc(0) = vloc; cd->ElemTyp(1) = A_Str; cd->Str(1) = asgn; sub_ilc(value, cd, 2); /* value */ cd->ElemTyp(3) = A_Str; cd->Str(3) = ";"; cd_add(cd); } /* * dwrd_asgn - generate code to assign a type code to the dword of a descriptor. */ static void dwrd_asgn(vloc, typ) struct val_loc *vloc; char *typ; { struct code *cd; cd = alc_ary(4); cd->ElemTyp(0) = A_ValLoc; cd->ValLoc(0) = vloc; cd->ElemTyp(1) = A_Str; cd->Str(1) = ".dword = D_"; cd->ElemTyp(2) = A_Str; cd->Str(2) = typ; cd->ElemTyp(3) = A_Str; cd->Str(3) = ";"; cd_add(cd); } /* * sub_ilc - generate code from a sequence of C code and place it * in a slot in a code array. */ static void sub_ilc(ilc, cd, indx) struct il_c *ilc; struct code *cd; int indx; { struct il_c *ilc1; struct code *cd1; int n; /* * Count the number of pieces of C code to process. */ n = 0; for (ilc1 = ilc; ilc1 != NULL; ilc1 = ilc1->next) ++n; /* * If there is only one piece of code, place it directly in the * slot of the array. Otherwise allocate a sub-array and place it * in the slot. */ if (n > 1) { cd1 = cd; cd = alc_ary(n); cd1->ElemTyp(indx) = A_Ary; cd1->Array(indx) = cd; indx = 0; } while (ilc != NULL) { switch (ilc->il_c_type) { case ILC_Ref: case ILC_Mod: /* * Reference to variable in symbol table. */ cd->ElemTyp(indx) = A_ValLoc; if (ilc->n == RsltIndx) cd->ValLoc(indx) = rslt; else { if (ilc->s == NULL) cd->ValLoc(indx) = cur_symtab[ilc->n].loc; else { /* * Access the entire descriptor. */ cd->ValLoc(indx) = loc_cpy(cur_symtab[ilc->n].loc, M_None); } } break; case ILC_Tend: /* * Reference to a tended variable. */ cd->ElemTyp(indx) = A_ValLoc; cd->ValLoc(indx) = tended[ilc->n]; break; case ILC_Str: /* * String representing C code. */ cd->ElemTyp(indx) = A_Str; cd->Str(indx) = ilc->s; break; case ILC_SBuf: /* * String buffer for a conversion. */ cd->ElemTyp(indx) = A_SBuf; cd->Intgr(indx) = alc_sbufs(1, intrnl_lftm); break; case ILC_CBuf: /* * Cset buffer for a conversion. */ cd->ElemTyp(indx) = A_CBuf; cd->Intgr(indx) = alc_cbufs(1, intrnl_lftm); break; default: fprintf(stderr, "compiler error: unknown info in data base\n"); exit(1); } ilc = ilc->next; ++indx; } } /* * gen_ilret - generate code to set the result value from a suspend or * return. */ static void gen_ilret(ilc) struct il_c *ilc; { struct il_c *ilc0; struct code *cd; char *cap_id; int typcd; if (rslt == &ignore) return; /* Don't bother computing the result; it's never used */ ilc0 = ilc->code[0]; typcd = ilc->n; if (typcd < 0) { /* * RTL returns that do not look like function calls to standard Icon * type name. */ switch (typcd) { case TypCInt: /* * return/suspend C_integer ; */ part_asgn(rslt, ".vword.integr = ", ilc0); dwrd_asgn(rslt, "Integer"); break; case TypCDbl: /* * return/suspend C_double ; */ cd = alc_ary(4); cd->ElemTyp(0) = A_ValLoc; cd->ValLoc(0) = rslt; cd->ElemTyp(1) = A_Str; cd->Str(1) = ".vword.bptr = (union block *)alcreal("; sub_ilc(ilc0, cd, 2); /* value */ cd->ElemTyp(3) = A_Str; cd->Str(3) = ");"; cd_add(cd); dwrd_asgn(rslt, "Real"); chkforblk(); /* make sure the block allocation succeeded */ break; case TypCStr: /* * return/suspend C_string ; */ cd = alc_ary(5); cd->ElemTyp(0) = A_Str; cd->Str(0) = "AsgnCStr("; cd->ElemTyp(1) = A_ValLoc; cd->ValLoc(1) = rslt; cd->ElemTyp(2) = A_Str; cd->Str(2) = ", "; sub_ilc(ilc0, cd, 3); /* */ cd->ElemTyp(4) = A_Str; cd->Str(4) = ");"; cd_add(cd); break; case RetDesc: /* * return/suspend ; */ part_asgn(rslt, " = ", ilc0); break; case RetNVar: /* * return/suspend named_var(); */ part_asgn(rslt, ".vword.descptr = ", ilc0); dwrd_asgn(rslt, "Var"); break; case RetSVar: /* * return/suspend struct_var(, ); */ part_asgn(rslt, ".vword.descptr = (dptr)", ilc->code[1]); cd = alc_ary(6); cd->ElemTyp(0) = A_ValLoc; cd->ValLoc(0) = rslt; cd->ElemTyp(1) = A_Str; cd->Str(1) = ".dword = D_Var + ((word *)"; sub_ilc(ilc0, cd, 2); /* value */ cd->ElemTyp(3) = A_Str; cd->Str(3) = " - (word *)"; cd->ElemTyp(4) = A_ValLoc; cd->ValLoc(4) = rslt; cd->ElemTyp(5) = A_Str; cd->Str(5) = ".vword.descptr);"; cd_add(cd); break; case RetNone: /* * return/suspend result; * * Result already set, do nothing. */ break; default: fprintf(stderr, "compiler error: unknown RLT return in data base\n"); exit(1); /* NOTREACHED */ } } else { /* * RTL returns that look like function calls to standard Icon type * names. */ cap_id = icontypes[typcd].cap_id; switch (icontypes[typcd].rtl_ret) { case TRetBlkP: /* * return/suspend (); */ part_asgn(rslt, ".vword.bptr = (union block *)", ilc0); dwrd_asgn(rslt, cap_id); break; case TRetDescP: /* * return/suspend (); */ part_asgn(rslt, ".vword.descptr = (dptr)", ilc0); dwrd_asgn(rslt, cap_id); break; case TRetCharP: /* * return/suspend (); */ part_asgn(rslt, ".vword.sptr = (char *)", ilc0); dwrd_asgn(rslt, cap_id); break; case TRetCInt: /* * return/suspend (); */ part_asgn(rslt, ".vword.integr = (word)", ilc0); dwrd_asgn(rslt, cap_id); break; case TRetSpcl: /* * RTL returns that look like function calls to standard type * names but take more than one argument. */ if (typcd == str_typ) { /* * return/suspend string(, ); */ part_asgn(rslt, ".vword.sptr = ", ilc->code[1]); part_asgn(rslt, ".dword = ", ilc0); } else if (typcd == stv_typ) { /* * return/suspend substr(, , ); */ cd = alc_ary(9); cd->ElemTyp(0) = A_Str; cd->Str(0) = "SubStr(&"; cd->ElemTyp(1) = A_ValLoc; cd->ValLoc(1) = rslt; cd->ElemTyp(2) = A_Str; cd->Str(2) = ", "; sub_ilc(ilc0, cd, 3); cd->ElemTyp(4) = A_Str; cd->Str(4) = ", "; sub_ilc(ilc->code[2], cd, 5); cd->ElemTyp(6) = A_Str; cd->Str(6) = ", "; sub_ilc(ilc->code[1], cd, 7); cd->ElemTyp(8) = A_Str; cd->Str(8) = ");"; cd_add(cd); chkforblk(); /* make sure the block allocation succeeded */ } else { fprintf(stderr, "compiler error: unknown RLT return in data base\n"); exit(1); /* NOTREACHED */ } break; default: fprintf(stderr, "compiler error: unknown RLT return in data base\n"); exit(1); /* NOTREACHED */ } } } /* * chkforblk - generate code to make sure the allocation of a block * for the result descriptor was successful. */ static void chkforblk() { struct code *cd; struct code *cd1; struct code *lbl; lbl = alc_lbl("got allocation", 0); cd_add(lbl); cur_fnc->cursor = lbl->prev; /* code goes before label */ cd = NewCode(2); cd->cd_id = C_If; cd1 = alc_ary(3); cd1->ElemTyp(0) = A_Str; cd1->Str(0) = "("; cd1->ElemTyp(1) = A_ValLoc; cd1->ValLoc(1) = rslt; cd1->ElemTyp(2) = A_Str; cd1->Str(2) = ").vword.bptr != NULL"; cd->Cond = cd1; cd->ThenStmt = mk_goto(lbl); cd_add(cd); cd = alc_ary(1); cd->ElemTyp(0) = A_Str; cd->Str(0) = "err_msg(307, NULL);"; cd_add(cd); if (err_conv) cd_add(sig_cd(on_failure, cur_fnc)); cur_fnc->cursor = lbl; } /* * gen_ilc - generate code for an sequence of in-line C code. */ static void gen_ilc(ilc) struct il_c *ilc; { struct il_c *ilc1; struct code *cd; struct code *cd1; struct code *lbl1; struct code *fail_sav; struct code **lbls; int max_lbl; int i; /* * Determine how many labels there are in the code and allocate an * array to map from label numbers to labels in the code. */ max_lbl = -1; for (ilc1 = ilc; ilc1 != NULL; ilc1 = ilc1->next) { switch(ilc1->il_c_type) { case ILC_CGto: case ILC_Goto: case ILC_Lbl: if (ilc1->n > max_lbl) max_lbl = ilc1->n; } } ++max_lbl; /* adjust for 0 indexing */ if (max_lbl > 0) { lbls = (struct code **)alloc((unsigned int) sizeof(struct code *) * max_lbl); for (i = 0; i < max_lbl; ++i) lbls[i] = NULL; } while (ilc != NULL) { switch(ilc->il_c_type) { case ILC_Ref: case ILC_Mod: case ILC_Tend: case ILC_SBuf: case ILC_CBuf: case ILC_Str: /* * The beginning of a sequence of code fragments that can be * place on one line. */ ilc = line_ilc(ilc); break; case ILC_Fail: /* * fail - perform failure action. */ cd_add(sig_cd(on_failure, cur_fnc)); break; case ILC_EFail: /* * errorfail - same as fail if error conversion is supported. */ if (err_conv) cd_add(sig_cd(on_failure, cur_fnc)); break; case ILC_Ret: /* * return - set result location and jump out of operation. */ gen_ilret(ilc); cd_add(mk_goto(*scont_strt)); break; case ILC_Susp: /* * suspend - set result location. If there is a success * continuation, call it. Otherwise the "continuation" * will be generated in-line, so set up a resumption label. */ gen_ilret(ilc); if (cont == NULL) *scont_strt = cur_fnc->cursor; lbl1 = oper_lbl("end suspend"); cd_add(lbl1); if (cont == NULL) *scont_fail = lbl1; else { cur_fnc->cursor = lbl1->prev; fail_sav = on_failure; on_failure = lbl1; callc_add(cont); on_failure = fail_sav; cur_fnc->cursor = lbl1; } break; case ILC_LBrc: /* * non-deletable '{' */ cd = NewCode(0); cd->cd_id = C_LBrack; cd_add(cd); break; case ILC_RBrc: /* * non-deletable '}' */ cd = NewCode(0); cd->cd_id = C_RBrack; cd_add(cd); break; case ILC_CGto: /* * Conditional goto. */ i = ilc->n; if (lbls[i] == NULL) lbls[i] = oper_lbl("within"); cd = NewCode(2); cd->cd_id = C_If; cd1 = alc_ary(1); sub_ilc(ilc->code[0], cd1, 0); cd->Cond = cd1; cd->ThenStmt = mk_goto(lbls[i]); cd_add(cd); break; case ILC_Goto: /* * Goto. */ i = ilc->n; if (lbls[i] == NULL) lbls[i] = oper_lbl("within"); cd_add(mk_goto(lbls[i])); break; case ILC_Lbl: /* * Label. */ i = ilc->n; if (lbls[i] == NULL) lbls[i] = oper_lbl("within"); cd_add(lbls[i]); break; default: fprintf(stderr, "compiler error: unknown info in data base\n"); exit(1); } ilc = ilc->next; } if (max_lbl > 0) free((char *)lbls); } /* * line_ilc - gather a line of in-line code. */ static struct il_c *line_ilc(ilc) struct il_c *ilc; { struct il_c *ilc1; struct il_c *last; struct code *cd; int n; int i; /* * Count the number of pieces in the line. Determine the last * piece in the sequence; this is returned to the caller. */ n = 0; ilc1 = ilc; while (ilc1 != NULL) { switch(ilc1->il_c_type) { case ILC_Ref: case ILC_Mod: case ILC_Tend: case ILC_SBuf: case ILC_CBuf: case ILC_Str: ++n; last = ilc1; ilc1 = ilc1->next; break; default: ilc1 = NULL; } } /* * Construct the line. */ cd = alc_ary(n); for (i = 0; i < n; ++i) { switch(ilc->il_c_type) { case ILC_Ref: case ILC_Mod: /* * Reference to variable in symbol table. */ cd->ElemTyp(i) = A_ValLoc; if (ilc->n == RsltIndx) cd->ValLoc(i) = rslt; else cd->ValLoc(i) = cur_symtab[ilc->n].loc; break; case ILC_Tend: /* * Reference to a tended variable. */ cd->ElemTyp(i) = A_ValLoc; cd->ValLoc(i) = tended[ilc->n]; break; case ILC_SBuf: /* * String buffer for a conversion. */ cd->ElemTyp(i) = A_SBuf; cd->Intgr(i) = alc_sbufs(1, intrnl_lftm); break; case ILC_CBuf: /* * Cset buffer for a conversion. */ cd->ElemTyp(i) = A_CBuf; cd->Intgr(i) = alc_cbufs(1, intrnl_lftm); break; case ILC_Str: /* * String representing C code. */ cd->ElemTyp(i) = A_Str; cd->Str(i) = ilc->s; break; default: ilc = NULL; } ilc = ilc->next; } cd_add(cd); return last; } /* * generate code to perform simple type checking. */ struct code *typ_chk(var, typcd) struct il_code *var; int typcd; { struct code *cd; if (typcd == int_typ && largeints) { /* * Handle large integer support specially. */ cd = alc_ary(5); cd->ElemTyp(0) = A_Str; cd->Str(0) = "(("; il_var(var, cd, 1); /* value */ cd->ElemTyp(2) = A_Str; cd->Str(2) = ").dword == D_Integer || ("; il_var(var, cd, 3); /* value */ cd->ElemTyp(4) = A_Str; cd->Str(4) = ").dword == D_Lrgint)"; return cd; } else if (typcd < 0) { /* * Not a standard Icon type name. */ cd = alc_ary(3); cd->ElemTyp(0) = A_Str; switch (typcd) { case TypVar: cd->Str(0) = "((("; il_var(var, cd, 1); /* value */ cd->ElemTyp(2) = A_Str; cd->Str(2) = ").dword & D_Var) == D_Var)"; break; case TypCInt: cd->Str(0) = "(("; il_var(var, cd, 1); /* value */ cd->ElemTyp(2) = A_Str; cd->Str(2) = ").dword == D_Integer)"; break; } } else if (typcd == str_typ) { cd = alc_ary(3); cd->ElemTyp(0) = A_Str; cd->Str(0) = "(!(("; il_var(var, cd, 1); /* value */ cd->ElemTyp(2) = A_Str; cd->Str(2) = ").dword & F_Nqual))"; } else { cd = alc_ary(5); cd->ElemTyp(0) = A_Str; cd->Str(0) = "(("; il_var(var, cd, 1); /* value */ cd->ElemTyp(2) = A_Str; cd->Str(2) = ").dword == D_"; cd->ElemTyp(3) = A_Str; cd->Str(3) = icontypes[typcd].cap_id; /* type name */ cd->ElemTyp(4) = A_Str; cd->Str(4) = ")"; } return cd; } /* * oper_lbl - generate a label with an associated comment that includes * the operation name. */ static struct code *oper_lbl(s) char *s; { char *sbuf; sbuf = (char *)alloc((unsigned int)(strlen(s) + strlen(impl->name) + 3)); sprintf(sbuf, "%s: %s", s, impl->name); return alc_lbl(sbuf, 0); } /* * sav_locs - save the current interpretation of symbols that may * be affected by conversions. */ static struct val_loc **sav_locs() { struct val_loc **locs; int i; if (nsyms == 0) return NULL; locs = (struct val_loc **)alloc((unsigned int)(nsyms * sizeof(struct val_loc *))); for (i = 0; i < nsyms; ++i) locs[i] = cur_symtab[i].loc; return locs; } /* * rstr_locs - restore the interpretation of symbols that may * have been affected by conversions. */ static void rstr_locs(locs) struct val_loc **locs; { int i; for (i = 0; i < nsyms; ++i) cur_symtab[i].loc = locs[i]; free((char *)locs); } /* * mrg_locs - merge the interpretations of symbols along two execution * paths. Any ambiguity is caught by rtt, so differences only occur * if one path involves program termination so that the symbols * no longer have an interpretation along that path. */ static void mrg_locs(locs) struct val_loc **locs; { int i; for (i = 0; i < nsyms; ++i) if (cur_symtab[i].loc == NULL) cur_symtab[i].loc = locs[i]; free((char *)locs); } /* * il_cnv - generate code for an in-line conversion. */ struct code *il_cnv(typcd, src, dflt, dest) int typcd; struct il_code *src; struct il_c *dflt; struct il_c *dest; { struct code *cd; struct code *cd1; int dflt_to_ptr; int loc; int is_cstr; int sym_indx; int n; int i; sym_indx = src->u[0].n; /* * Determine whether the address must be taken of a default value and * whether the interpretation of the symbol in an in-place conversion * changes. */ dflt_to_ptr = 0; loc = PrmTend; is_cstr = 0; switch (typcd) { case TypCInt: case TypECInt: loc = PrmInt; break; case TypCDbl: loc = PrmDbl; break; case TypCStr: is_cstr = 1; break; case TypEInt: break; case TypTStr: case TypTCset: dflt_to_ptr = 1; break; default: /* * Cset, real, integer, or string */ if (typcd == cset_typ || typcd == str_typ) dflt_to_ptr = 1; break; } if (typcd == TypCDbl && !(eval_is(real_typ, sym_indx) & MaybeFalse)) { /* * Conversion from Icon real to C double. Just copy the C value * from the block. */ cd = alc_ary(5); cd->ElemTyp(0) = A_Str; cd->Str(0) = "(GetReal(&("; il_var(src, cd, 1); cd->ElemTyp(2) = A_Str; cd->Str(2) = "), "; cnv_dest(loc, is_cstr, src, sym_indx, dest, cd, 3); cd->ElemTyp(4) = A_Str; cd->Str(4) = "), 1)"; } else if (typcd == TypCDbl && !largeints && !(eval_is(int_typ, sym_indx) & MaybeFalse)) { /* * Conversion from Icon integer (not large integer) to C double. * Do as a C conversion by an assigment. */ cd = alc_ary(5); cd->ElemTyp(0) = A_Str; cd->Str(0) = "("; cd->ElemTyp(2) = A_Str; cd->Str(2) = " = IntVal( "; cd->ElemTyp(4) = A_Str; cd->Str(4) = "), 1)"; /* * Note that cnv_dest() must be called after the source is output * in case it changes the location of the parameter. */ il_var(src, cd, 3); cnv_dest(loc, is_cstr, src, sym_indx, dest, cd, 1); } else { /* * Compute the number of code fragments required to construct the * call to the conversion routine. */ n = 7; if (dflt != NULL) n += 2; cd = alc_ary(n); /* * The names of simple conversions are distinguished from defaulting * conversions by a prefix of "cnv_" or "def_". */ cd->ElemTyp(0) = A_Str; if (dflt == NULL) cd->Str(0) = "cnv_"; else cd->Str(0) = "def_"; /* * Determine the name of the conversion routine. */ cd->ElemTyp(1) = A_Str; /* may be overridden */ switch (typcd) { case TypCInt: cd->Str(1) = "c_int(&("; break; case TypCDbl: cd->Str(1) = "c_dbl(&("; break; case TypCStr: cd->Str(1) = "c_str(&("; break; case TypEInt: cd->Str(1) = "eint(&("; break; case TypECInt: cd->Str(1) = "ec_int(&("; break; case TypTStr: /* * Allocate a string buffer. */ cd1 = alc_ary(3); cd1->ElemTyp(0) = A_Str; cd1->Str(0) = "tstr("; cd1->ElemTyp(1) = A_SBuf; cd1->Intgr(1) = alc_sbufs(1, intrnl_lftm); cd1->ElemTyp(2) = A_Str; cd1->Str(2) = ", (&"; cd->ElemTyp(1) = A_Ary; cd->Array(1) = cd1; break; case TypTCset: /* * Allocate a cset buffer. */ cd1 = alc_ary(3); cd1->ElemTyp(0) = A_Str; cd1->Str(0) = "tcset("; cd1->ElemTyp(1) = A_CBuf; cd1->Intgr(1) = alc_cbufs(1, intrnl_lftm); cd1->ElemTyp(2) = A_Str; cd1->Str(2) = ", &("; cd->ElemTyp(1) = A_Ary; cd->Array(1) = cd1; break; default: /* * Cset, real, integer, or string */ if (typcd == cset_typ) cd->Str(1) = "cset(&("; else if (typcd == real_typ) cd->Str(1) = "real(&("; else if (typcd == int_typ) cd->Str(1) = "int(&("; else if (typcd == str_typ) cd->Str(1) = "str(&("; break; } il_var(src, cd, 2); cd->ElemTyp(3) = A_Str; if (dflt != NULL && dflt_to_ptr) cd->Str(3) = "), &("; else cd->Str(3) = "), "; /* * Determine if this conversion has a default value. */ i = 4; if (dflt != NULL) { sub_ilc(dflt, cd, i); ++i; cd->ElemTyp(i) = A_Str; if (dflt_to_ptr) cd->Str(i) = "), "; else cd->Str(i) = ", "; ++i; } cd->ElemTyp(i) = A_Str; cd->Str(i) = "&("; ++i; cnv_dest(loc, is_cstr, src, sym_indx, dest, cd, i); ++i; cd->ElemTyp(i) = A_Str; cd->Str(i) = "))"; } return cd; } /* * il_dflt - generate code for a defaulting conversion that always defaults. */ struct code *il_dflt(typcd, src, dflt, dest) int typcd; struct il_code *src; struct il_c *dflt; struct il_c *dest; { struct code *cd; int sym_indx; sym_indx = src->u[0].n; if (typcd == TypCDbl) { cd = alc_ary(5); cd->ElemTyp(0) = A_Str; cd->Str(0) = "("; cnv_dest(PrmDbl, 0, src, sym_indx, dest, cd, 1); /* variable */ cd->ElemTyp(2) = A_Str; cd->Str(2) = " = "; sub_ilc(dflt, cd, 3); /* default */ cd->ElemTyp(4) = A_Str; cd->Str(4) = ", 1)"; } else if (typcd == TypCInt || typcd == TypECInt) { cd = alc_ary(5); cd->ElemTyp(0) = A_Str; cd->Str(0) = "("; cnv_dest(PrmInt, 0, src, sym_indx, dest, cd, 1); /* variable */ cd->ElemTyp(2) = A_Str; cd->Str(2) = " = "; sub_ilc(dflt, cd, 3); /* default */ cd->ElemTyp(4) = A_Str; cd->Str(4) = ", 1)"; } else if (typcd == TypTStr || typcd == str_typ) { cd = alc_ary(5); cd->ElemTyp(0) = A_Str; cd->Str(0) = "("; cnv_dest(0, 0, src, sym_indx, dest, cd, 1); /* variable */ cd->ElemTyp(2) = A_Str; cd->Str(2) = " = "; sub_ilc(dflt, cd, 3); /* default */ cd->ElemTyp(4) = A_Str; cd->Str(4) = ", 1)"; } else if (typcd == TypCStr) { cd = alc_ary(5); cd->ElemTyp(0) = A_Str; cd->Str(0) = "(AsgnCStr("; cnv_dest(0, 1, src, sym_indx, dest, cd, 1); /* variable */ cd->ElemTyp(2) = A_Str; cd->Str(2) = ", "; sub_ilc(dflt, cd, 3); /* default */ cd->ElemTyp(4) = A_Str; cd->Str(4) = "), 1)"; } else if (typcd == TypTCset || typcd == cset_typ) { cd = alc_ary(7); cd->ElemTyp(0) = A_Str; cd->Str(0) = "(BlkLoc("; cnv_dest(0, 0, src, sym_indx, dest, cd, 1); /* variable */ cd->ElemTyp(2) = A_Str; cd->Str(2) = ") = (union block *)&"; sub_ilc(dflt, cd, 3); /* default */ cd->ElemTyp(4) = A_Str; cd->Str(4) = ", "; cnv_dest(0, 0, src, sym_indx, dest, cd, 5); /* variable */ cd->ElemTyp(6) = A_Str; cd->Str(6) = ".dword = D_Cset, 1)"; } else if (typcd == TypEInt || typcd == int_typ) { cd = alc_ary(7); cd->ElemTyp(0) = A_Str; cd->Str(0) = "(IntVal("; cnv_dest(0, 0, src, sym_indx, dest, cd, 1); /* variable */ cd->ElemTyp(2) = A_Str; cd->Str(2) = ") = "; sub_ilc(dflt, cd, 3); /* default */ cd->ElemTyp(4) = A_Str; cd->Str(4) = ", "; cnv_dest(0, 0, src, sym_indx, dest, cd, 5); /* variable */ cd->ElemTyp(6) = A_Str; cd->Str(6) = ".dword = D_Integer, 1)"; } else if (typcd == real_typ) { cd = alc_ary(7); cd->ElemTyp(0) = A_Str; cd->Str(0) = "((BlkLoc("; cnv_dest(0, 0, src, sym_indx, dest, cd, 1); /* variable */ cd->ElemTyp(2) = A_Str; cd->Str(2) = ") = (union block *)alcreal("; sub_ilc(dflt, cd, 3); /* default */ cd->ElemTyp(4) = A_Str; cd->Str(4) = ")) == NULL ? (fatalerr(0,NULL), 0) : ("; cnv_dest(0, 0, src, sym_indx, dest, cd, 5); /* variable */ cd->ElemTyp(6) = A_Str; cd->Str(6) = ".dword = D_Real, 1))"; } return cd; } /* * cnv_dest - output the destination of a conversion. */ static void cnv_dest(loc, is_cstr, src, sym_indx, dest, cd, i) int loc; int is_cstr; struct il_code *src; int sym_indx; struct il_c *dest; struct code *cd; int i; { if (dest == NULL) { /* * Convert "in place", changing the location of a parameter if needed. */ switch (loc) { case PrmInt: if (cur_symtab[sym_indx].itmp_indx < 0) cur_symtab[sym_indx].itmp_indx = alc_itmp(intrnl_lftm); cur_symtab[sym_indx].loc = itmp_loc(cur_symtab[sym_indx].itmp_indx); break; case PrmDbl: if (cur_symtab[sym_indx].dtmp_indx < 0) cur_symtab[sym_indx].dtmp_indx = alc_dtmp(intrnl_lftm); cur_symtab[sym_indx].loc = dtmp_loc(cur_symtab[sym_indx].dtmp_indx); break; } il_var(src, cd, i); if (is_cstr) cur_symtab[sym_indx].loc = loc_cpy(cur_symtab[sym_indx].loc,M_CharPtr); } else { if (is_cstr && dest->il_c_type == ILC_Mod && dest->next == NULL && dest->n != RsltIndx && cur_symtab[dest->n].loc->mod_access != M_None) { /* * We are converting to a C string. The destination variable * is not defined as a simple descriptor, but must be accessed * as such for this conversion. */ cd->ElemTyp(i) = A_ValLoc; cd->ValLoc(i) = loc_cpy(cur_symtab[dest->n].loc, M_None); } else sub_ilc(dest, cd, i); } } /* * il_copy - produce code for an optimized "conversion" that always succeeds * and just copies a value from one place to another. */ struct code *il_copy(dest, src) struct il_c *dest; struct val_loc *src; { struct code *cd; cd = alc_ary(5); cd->ElemTyp(0) = A_Str; cd->Str(0) = "("; sub_ilc(dest, cd, 1); cd->ElemTyp(2) = A_Str; cd->Str(2) = " = "; cd->ElemTyp(3) = A_ValLoc; cd->ValLoc(3) = src; cd->ElemTyp(4) = A_Str; cd->Str(4) = ", 1)"; return cd; } /* * loc_cpy - make a copy of a reference to a value location, but change * the way the location is accessed. */ struct val_loc *loc_cpy(loc, mod_access) struct val_loc *loc; int mod_access; { struct val_loc *new_loc; if (loc == NULL) return NULL; new_loc = NewStruct(val_loc); *new_loc = *loc; new_loc->mod_access = mod_access; return new_loc; } /* * gen_tcase - generate in-line code for a type_case statement. */ static int gen_tcase(il, has_dflt) struct il_code *il; int has_dflt; { struct case_anlz case_anlz; /* * We can only get here if the type_case statement can be implemented * with a no more than one type check. Determine how simple the * code can be. */ findcases(il, has_dflt, &case_anlz); if (case_anlz.il_then == NULL) { if (case_anlz.il_else == NULL) return 1; else return gen_il(case_anlz.il_else); } else return gen_if(typ_chk(il->u[0].fld, case_anlz.typcd), case_anlz.il_then, case_anlz.il_else, sav_locs()); } /* * gen_if - generate code to test a condition that might be true * of false. Determine if execution can continue past this if statement. */ static int gen_if(cond_cd, il_then, il_else, locs) struct code *cond_cd; struct il_code *il_then; struct il_code *il_else; struct val_loc **locs; { struct val_loc **locs1; struct code *lbl_then; struct code *lbl_end; struct code *else_loc; struct code *cd; int fall_thru; lbl_then = oper_lbl("then"); lbl_end = oper_lbl("end if"); cd = NewCode(2); cd->cd_id = C_If; cd->Cond = cond_cd; cd->ThenStmt = mk_goto(lbl_then); cd_add(cd); else_loc = cur_fnc->cursor; cd_add(lbl_then); fall_thru = gen_il(il_then); cd_add(lbl_end); locs1 = sav_locs(); rstr_locs(locs); cur_fnc->cursor = else_loc; /* go back for the else clause */ fall_thru |= gen_il(il_else); cd_add(mk_goto(lbl_end)); cur_fnc->cursor = lbl_end; mrg_locs(locs1); return fall_thru; }