summaryrefslogtreecommitdiff
path: root/src/iconc/inline.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/iconc/inline.c')
-rw-r--r--src/iconc/inline.c2007
1 files changed, 0 insertions, 2007 deletions
diff --git a/src/iconc/inline.c b/src/iconc/inline.c
deleted file mode 100644
index 234229c..0000000
--- a/src/iconc/inline.c
+++ /dev/null
@@ -1,2007 +0,0 @@
-/*
- * 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 <expr>;
- */
- part_asgn(rslt, ".vword.integr = ", ilc0);
- dwrd_asgn(rslt, "Integer");
- break;
- case TypCDbl:
- /*
- * return/suspend C_double <expr>;
- */
- 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 <expr>;
- */
- 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); /* <expr> */
- cd->ElemTyp(4) = A_Str;
- cd->Str(4) = ");";
- cd_add(cd);
- break;
- case RetDesc:
- /*
- * return/suspend <expr>;
- */
- part_asgn(rslt, " = ", ilc0);
- break;
- case RetNVar:
- /*
- * return/suspend named_var(<desc-pntr>);
- */
- part_asgn(rslt, ".vword.descptr = ", ilc0);
- dwrd_asgn(rslt, "Var");
- break;
- case RetSVar:
- /*
- * return/suspend struct_var(<desc-pntr>, <block_pntr>);
- */
- 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 <type>(<block-pntr>);
- */
- part_asgn(rslt, ".vword.bptr = (union block *)", ilc0);
- dwrd_asgn(rslt, cap_id);
- break;
- case TRetDescP:
- /*
- * return/suspend <type>(<descriptor-pntr>);
- */
- part_asgn(rslt, ".vword.descptr = (dptr)", ilc0);
- dwrd_asgn(rslt, cap_id);
- break;
- case TRetCharP:
- /*
- * return/suspend <type>(<char-pntr>);
- */
- part_asgn(rslt, ".vword.sptr = (char *)", ilc0);
- dwrd_asgn(rslt, cap_id);
- break;
- case TRetCInt:
- /*
- * return/suspend <type>(<integer>);
- */
- 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(<len>, <char-pntr>);
- */
- part_asgn(rslt, ".vword.sptr = ", ilc->code[1]);
- part_asgn(rslt, ".dword = ", ilc0);
- }
- else if (typcd == stv_typ) {
- /*
- * return/suspend substr(<desc-pntr>, <start>, <len>);
- */
- 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;
- }