diff options
Diffstat (limited to 'src/iconc/codegen.c')
-rw-r--r-- | src/iconc/codegen.c | 1918 |
1 files changed, 1918 insertions, 0 deletions
diff --git a/src/iconc/codegen.c b/src/iconc/codegen.c new file mode 100644 index 0000000..8ca5bd1 --- /dev/null +++ b/src/iconc/codegen.c @@ -0,0 +1,1918 @@ +/* + * codegen.c - routines to write out C code. + */ +#include "../h/gsupport.h" +#include "ctrans.h" +#include "cglobals.h" +#include "csym.h" +#include "ccode.h" +#include "ctree.h" +#include "cproto.h" + +#ifndef LoopThreshold +#define LoopThreshold 7 +#endif /* LoopThreshold */ + +/* + * MinOne - arrays sizes must be at least 1. + */ +#define MinOne(n) ((n) > 0 ? (n) : 1) + +/* + * ChkSeqNum - make sure a label has been given a sequence number. + */ +#define ChkSeqNum(x) if ((x)->SeqNum == 0) (x)->SeqNum = ++lbl_seq_num + +/* + * ChkBound - for a given procedure, signals that transfer control to a + * bounding label all use the same signal number. + */ +#define ChkBound(x) (((x)->LabFlg & Bounding) ? bound_sig : (x)) + +/* + * When a switch statement for signal handling is optimized, there + * are three possible forms of default clauses. + */ +#define DfltNone 0 /* no default clause */ +#define DfltBrk 1 /* default is just a break */ +#define DfltRetSig 2 /* default is to return the signal from the call */ + +/* + * Prototypes for static functions. + */ +static int arg_nms (struct lentry *lptr, int prt); +static void bi_proc (char *name, struct implement *ip); +static void chkforgn (int outer); +static int dyn_nms (struct lentry *lptr, int prt); +static void fldnames (struct fldname *fields); +static void fnc_blk (struct gentry *gptr); +static void frame (int outer); +static void good_clsg (struct code *call, int outer); +static void initpblk (FILE *f, int c, char *prefix, char *name, + int nquals, int nparam, int ndynam, int nstatic, + int frststat); +static char *is_builtin (struct gentry *gptr); +static void proc_blk (struct gentry *gptr, int init_glbl); +static void prt_ary (struct code *cd, int outer); +static void prt_cond (struct code *cond); +static void prt_cont (struct c_fnc *cont); +static void prt_var (struct lentry *var, int outer); +static void prtcall (struct code *call, int outer); +static void prtcode (struct code *cd, int outer); +static void prtpccall (int outer); +static void rec_blk (struct gentry *gptr, int init_glbl); +static void smpl_clsg (struct code *call, int outer); +static void stat_nms (struct lentry *lptr, int prt); +static void val_loc (struct val_loc *rslt, int outer); + +static int n_stat = -1; /* number of static variables */ + +/* + * var_dcls - produce declarations necessary to implement variables + * and to initialize globals and statics: procedure blocks, procedure + * frames, record blocks, declarations for globals and statics, the + * C main program. + */ +void var_dcls() + { + register int i; + register struct gentry *gptr; + struct gentry *gbl_main; + struct pentry *prc_main; + int n_glob = 0; + int flag; + int init_glbl; + int first; + char *pfx; + + /* + * Output initialized array of descriptors for globals. + */ + fprintf(codefile, "\nstatic struct {word dword; union block *vword;}"); + fprintf(codefile, " init_globals[NGlobals] = {\n"); + prc_main = NULL; + for (i = 0; i < GHSize; i++) + for (gptr = ghash[i]; gptr != NULL; gptr = gptr->blink) { + flag = gptr->flag & ~(F_Global | F_StrInv); + if (strcmp(gptr->name, "main") == 0 && (gptr->flag & F_Proc)) { + /* + * Remember main procedure. + */ + gbl_main = gptr; + prc_main = gbl_main->val.proc; + } + if (flag == 0) { + /* + * Ordinary variable. + */ + gptr->index = n_glob++; + fprintf(codefile, " {D_Null},\n"); + } + else { + /* + * Procedure, function, or record constructor. If the variable + * has not been optimized away, initialize the it to reference + * the procedure block. + */ + if (flag & F_SmplInv) { + init_glbl = 0; + flag &= ~(uword)F_SmplInv; + } + else { + init_glbl = 1; + gptr->index = n_glob++; + fprintf(codefile, " {D_Proc, "); + } + switch (flag) { + case F_Proc: + proc_blk(gptr, init_glbl); + break; + case F_Builtin: + if (init_glbl) + fnc_blk(gptr); + break; + case F_Record: + rec_blk(gptr, init_glbl); + } + } + } + if (n_glob == 0) + fprintf(codefile, " {D_Null} /* place holder */\n"); + fprintf(codefile, " };\n"); + + if (prc_main == NULL) { + nfatal(NULL, "main procedure missing", NULL); + return; + } + + /* + * Output array of descriptors initialized to the names of the + * global variables that have not been optimized away. + */ + if (n_glob == 0) + fprintf(codefile, "\nstruct sdescrip init_gnames[1];\n"); + else { + fprintf(codefile, "\nstruct sdescrip init_gnames[NGlobals] = {\n"); + for (i = 0; i < GHSize; i++) + for (gptr = ghash[i]; gptr != NULL; gptr = gptr->blink) + if (!(gptr->flag & F_SmplInv)) + fprintf(codefile, " {%d, \"%s\"},\n", strlen(gptr->name), + gptr->name); + fprintf(codefile, " };\n"); + } + + /* + * Output array of pointers to builtin functions that correspond to + * names of the global variables. + */ + if (n_glob == 0) + fprintf(codefile, "\nstruct b_proc *builtins[1];\n"); + else { + fprintf(codefile, "\nstruct b_proc *builtins[NGlobals] = {\n"); + for (i = 0; i < GHSize; i++) + for (gptr = ghash[i]; gptr != NULL; gptr = gptr->blink) + if (!(gptr->flag & F_SmplInv)) { + /* + * Need to output *something* to stay in step with other arrays. + */ + if (pfx = is_builtin(gptr)) { + fprintf(codefile, " (struct b_proc *)&BF%c%c_%s,\n", + pfx[0], pfx[1], gptr->name); + } + else + fprintf(codefile, " 0,\n"); + } + fprintf(codefile, " };\n"); + } + + /* + * Output C main function that initializes the run-time system and + * calls the main procedure. + */ + fprintf(codefile, "\n"); + fprintf(codefile, "int main(argc, argv)\n"); + fprintf(codefile, "int argc;\n"); + fprintf(codefile, "char **argv;\n"); + fprintf(codefile, " {\n"); + + /* + * If the main procedure requires a command-line argument list, we + * need a place to construct the Icon argument list. + */ + if (prc_main->nargs != 0 || !(gbl_main->flag & F_SmplInv)) { + fprintf(codefile, " struct {\n"); + fprintf(codefile, " struct tend_desc *previous;\n"); + fprintf(codefile, " int num;\n"); + fprintf(codefile, " struct descrip arg_lst;\n"); + fprintf(codefile, " } t;\n"); + fprintf(codefile, "\n"); + } + + /* + * Produce code to initialize run-time system variables. Some depend + * on compiler options. + */ + fprintf(codefile, " op_tbl = (struct b_proc *)init_op_tbl;\n"); + fprintf(codefile, " globals = (dptr)init_globals;\n"); + fprintf(codefile, " eglobals = &globals[%d];\n", n_glob); + fprintf(codefile, " gnames = (dptr)init_gnames;\n"); + fprintf(codefile, " egnames = &gnames[%d];\n", n_glob); + fprintf(codefile, " estatics = &statics[%d];\n", n_stat + 1); + if (debug_info) + fprintf(codefile, " debug_info = 1;\n"); + else + fprintf(codefile, " debug_info = 0;\n"); + if (line_info) { + fprintf(codefile, " line_info = 1;\n"); + fprintf(codefile, " file_name = \"\";\n"); + fprintf(codefile, " line_num = 0;\n"); + } + else + fprintf(codefile, " line_info = 0;\n"); + if (err_conv) + fprintf(codefile, " err_conv = 1;\n"); + else + fprintf(codefile, " err_conv = 0;\n"); + if (largeints) + fprintf(codefile, " largeints = 1;\n"); + else + fprintf(codefile, " largeints = 0;\n"); + + /* + * Produce code to call the routine to initialize the runtime system. + */ + if (trace) + fprintf(codefile, " init(*argv, &argc, argv, -1);\n"); + else + fprintf(codefile, " init(*argv, &argc, argv, 0);\n"); + fprintf(codefile, "\n"); + + /* + * If the main procedure requires an argument list (perhaps because + * it uses standard, rather than tailored calling conventions), + * set up the argument list. + */ + if (prc_main->nargs != 0 || !(gbl_main->flag & F_SmplInv)) { + fprintf(codefile, " t.arg_lst = nulldesc;\n"); + fprintf(codefile, " t.num = 1;\n"); + fprintf(codefile, " t.previous = NULL;\n"); + fprintf(codefile, " tend = (struct tend_desc *)&t;\n"); + if (prc_main->nargs == 0) + fprintf(codefile, + " /* main() takes no arguments: construct no list */\n"); + else + fprintf(codefile, " cmd_line(argc, argv, &t.arg_lst);\n"); + fprintf(codefile, "\n"); + } + else + fprintf(codefile, " tend = NULL;\n"); + + if (gbl_main->flag & F_SmplInv) { + /* + * procedure main only has a simplified implementation if it + * takes either 0 or 1 argument. + */ + first = 1; + if (prc_main->nargs == 0) + fprintf(codefile, " P%s_main(", prc_main->prefix); + else { + fprintf(codefile, " P%s_main(&t.arg_lst", prc_main->prefix); + first = 0; + } + if (prc_main->ret_flag & (DoesRet | DoesSusp)) { + if (!first) + fprintf(codefile, ", "); + fprintf(codefile, "&trashcan"); + first = 0; + } + if (prc_main->ret_flag & DoesSusp) + fprintf(codefile, ", (continuation)NULL"); + fprintf(codefile, ");\n"); + } + else /* the main procedure uses standard calling conventions */ + fprintf(codefile, + " P%s_main(1, &t.arg_lst, &trashcan, (continuation)NULL);\n", + prc_main->prefix); + fprintf(codefile, " \n"); + fprintf(codefile, " c_exit(EXIT_SUCCESS);\n"); + fprintf(codefile, " }\n"); + + /* + * Output to header file definitions related to global and static + * variables. + */ + fprintf(inclfile, "\n"); + if (n_glob == 0) { + fprintf(inclfile, "#define NGlobals 1\n"); + fprintf(inclfile, "int n_globals = 0;\n"); + } + else { + fprintf(inclfile, "#define NGlobals %d\n", n_glob); + fprintf(inclfile, "int n_globals = NGlobals;\n"); + } + ++n_stat; + fprintf(inclfile, "\n"); + fprintf(inclfile, "int n_statics = %d;\n", n_stat); + fprintf(inclfile, "struct descrip statics[%d]", MinOne(n_stat)); + if (n_stat > 0) { + fprintf(inclfile, " = {\n"); + for (i = 0; i < n_stat; ++i) + fprintf(inclfile, " {D_Null},\n"); + fprintf(inclfile, " };\n"); + } + else + fprintf(inclfile, ";\n"); + } + +/* + * proc_blk - create procedure block and initialize global variable, also + * compute offsets for local procedure variables. + */ +static void proc_blk(gptr, init_glbl) +struct gentry *gptr; +int init_glbl; + { + struct pentry *p; + register char *name; + int nquals; + + name = gptr->name; + p = gptr->val.proc; + + /* + * If we don't initialize a global variable for this procedure, we + * need only compute offsets for variables. + */ + if (init_glbl) { + fprintf(codefile, "(union block *)&BP%s_%s},\n", p->prefix, name); + nquals = 1 + Abs(p->nargs) + p->ndynam + p->nstatic; + fprintf(inclfile, "\n"); + fprintf(inclfile, "static int P%s_%s (int r_nargs, dptr r_args,", + p->prefix, name); + fprintf(inclfile, "dptr r_rslt, continuation r_s_cont);\n"); + initpblk(inclfile, 'P', p->prefix, name, nquals, p->nargs, p->ndynam, + p->nstatic, n_stat + 1); + fprintf(inclfile, "\n {%d, \"%s\"},\n", strlen(name), name); + } + arg_nms(p->args, init_glbl); + p->tnd_loc = dyn_nms(p->dynams, init_glbl); + stat_nms(p->statics, init_glbl); + if (init_glbl) + fprintf(inclfile, " }};\n"); + } + +/* + * arg_nms - compute offsets of arguments and, if needed, output the + * initializer for a descriptor for the argument name. + */ +static int arg_nms(lptr, prt) +struct lentry *lptr; +int prt; + { + register int n; + + if (lptr == NULL) + return 0; + n = arg_nms(lptr->next, prt); + lptr->val.index = n; + if (prt) + fprintf(inclfile, " {%d, \"%s\"},\n", strlen(lptr->name), lptr->name); + return n + 1; + } + +/* + * dyn_nms - compute offsets of dynamic locals and, if needed, output the + * initializer for a descriptor for the variable name. + */ +static int dyn_nms(lptr, prt) +struct lentry *lptr; +int prt; + { + register int n; + + if (lptr == NULL) + return 0; + n = dyn_nms(lptr->next, prt); + lptr->val.index = n; + if (prt) + fprintf(inclfile, " {%d, \"%s\"},\n", strlen(lptr->name), lptr->name); + return n + 1; + } + +/* + * stat_nams - compute offsets of static locals and, if needed, output the + * initializer for a descriptor for the variable name. + */ +static void stat_nms(lptr, prt) +struct lentry *lptr; +int prt; + { + if (lptr == NULL) + return; + stat_nms(lptr->next, prt); + lptr->val.index = ++n_stat; + if (prt) + fprintf(inclfile, " {%d, \"%s\"},\n", strlen(lptr->name), lptr->name); + } + +/* + * is_builtin - check if a global names or hides a builtin, returning prefix. + * If it hides one, we must also generate the prototype and block here. + */ +static char *is_builtin(gptr) +struct gentry *gptr; + { + struct implement *iptr; + + if (!(gptr->flag & F_StrInv)) /* if not eligible for string invoc */ + return 0; + if (gptr->flag & F_Builtin) /* if global *is* a builtin */ + return gptr->val.builtin->prefix; + iptr = db_ilkup(gptr->name, bhash); + if (iptr == NULL) /* if no builtin by this name */ + return NULL; + bi_proc(gptr->name, iptr); /* output prototype and proc block */ + return iptr->prefix; + } + +/* + * fnc_blk - output vword of descriptor for a built-in function and its + * procedure block. + */ +static void fnc_blk(gptr) +struct gentry *gptr; + { + struct implement *iptr; + char *name, *pfx; + + name = gptr->name; + iptr = gptr->val.builtin; + pfx = iptr->prefix; + /* + * output prototype and procedure block to inclfile. + */ + bi_proc(name, iptr); + /* + * vword of descriptor references the procedure block. + */ + fprintf(codefile, "(union block *)&BF%c%c_%s}, \n", pfx[0], pfx[1], name); + } + +/* + * bi_proc - output prototype and procedure block for builtin function. + */ +static void bi_proc(name, ip) +char *name; + struct implement *ip; + { + int nargs; + char prefix[3]; + + prefix[0] = ip->prefix[0]; + prefix[1] = ip->prefix[1]; + prefix[2] = '\0'; + nargs = ip->nargs; + if (nargs > 0 && ip->arg_flgs[nargs - 1] & VarPrm) + nargs = -nargs; + fprintf(inclfile, "\n"); + implproto(ip); + initpblk(inclfile, 'F', prefix, name, 1, nargs, -1, 0, 0); + fprintf(inclfile, "{%d, \"%s\"}}};\n", strlen(name), name); + } + +/* + * rec_blk - if needed, output vword of descriptor for a record + * constructor and output its procedure block. + */ +static void rec_blk(gptr, init_glbl) +struct gentry *gptr; +int init_glbl; + { + struct rentry *r; + register char *name; + int nfields; + + name = gptr->name; + r = gptr->val.rec; + nfields = r->nfields; + + /* + * If the variable is not optimized away, output vword of descriptor. + */ + if (init_glbl) + fprintf(codefile, "(union block *)&BR%s_%s},\n", r->prefix, name); + + fprintf(inclfile, "\n"); + /* + * Prototype for C function implementing constructor. If no optimizations + * have been performed on the variable, the standard calling conventions + * are used and we need a continuation parameter. + */ + fprintf(inclfile, + "static int R%s_%s (int r_nargs, dptr r_args, dptr r_rslt", + r->prefix, name); + if (init_glbl) + fprintf(inclfile, ", continuation r_s_cont"); + fprintf(inclfile, ");\n"); + + /* + * Procedure block, including record name and field names. + */ + initpblk(inclfile, 'R', r->prefix, name, nfields + 1, nfields, -2, + r->rec_num, 1); + fprintf(inclfile, "\n {%d, \"%s\"},\n", strlen(name), name); + fldnames(r->fields); + fprintf(inclfile, " }};\n"); + } + + +/* + * fldnames - output the initializer for a descriptor for the field name. + */ +static void fldnames(fields) +struct fldname *fields; + { + register char *name; + + if (fields == NULL) + return; + fldnames(fields->next); + name = fields->name; + fprintf(inclfile, " {%d, \"%s\"},\n", strlen(name), name); + } + +/* + * implproto - print prototype for function implementing a run-time operation. + */ +void implproto(ip) +struct implement *ip; + { + if (ip->iconc_flgs & ProtoPrint) + return; /* only print prototype once */ + fprintf(inclfile, "int %c%c%c_%s ", ip->oper_typ, ip->prefix[0], + ip->prefix[1], ip->name); + fprintf(inclfile, "(int r_nargs, dptr r_args, dptr r_rslt, "); + fprintf(inclfile,"continuation r_s_cont);\n"); + ip->iconc_flgs |= ProtoPrint; + } + +/* + * const_blks - output blocks for cset and real constants. + */ +void const_blks() + { + register int i; + register struct centry *cptr; + + fprintf(inclfile, "\n"); + for (i = 0; i < CHSize; i++) + for (cptr = chash[i]; cptr != NULL; cptr = cptr->blink) { + switch (cptr->flag) { + case F_CsetLit: + nxt_pre(cptr->prefix, pre, PrfxSz); + cptr->prefix[PrfxSz] = '\0'; + fprintf(inclfile, "struct b_cset BDC%s = ", cptr->prefix); + cset_init(inclfile, cptr->u.cset); + break; + case F_RealLit: + nxt_pre(cptr->prefix, pre, PrfxSz); + cptr->prefix[PrfxSz] = '\0'; + fprintf(inclfile, "struct b_real BDR%s = {T_Real, %s};\n", + cptr->prefix, cptr->image); + break; + } + } + } + +/* + * reccnstr - output record constructors. + */ +void recconstr(r) +struct rentry *r; + { + register char *name; + int optim; + int nfields; + + if (r == NULL) + return; + recconstr(r->next); + + name = r->name; + nfields = r->nfields; + + /* + * Does this record constructor use optimized calling conventions? + */ + optim = glookup(name)->flag & F_SmplInv; + + fprintf(codefile, "\n"); + fprintf(codefile, "static int R%s_%s(r_nargs, r_args, r_rslt", r->prefix, + name); + if (!optim) + fprintf(codefile, ", r_s_cont"); /* continuation is passed */ + fprintf(codefile, ")\n"); + fprintf(codefile, "int r_nargs;\n"); + fprintf(codefile, "dptr r_args;\n"); + fprintf(codefile, "dptr r_rslt;\n"); + if (!optim) + fprintf(codefile, "continuation r_s_cont;\n"); + fprintf(codefile, " {\n"); + fprintf(codefile, " register int i;\n"); + fprintf(codefile, " register struct b_record *rp;\n"); + fprintf(codefile, "\n"); + fprintf(codefile, " rp = alcrecd(%d, (union block *)&BR%s_%s);\n", + nfields, r->prefix, name); + fprintf(codefile, " if (rp == NULL) {\n"); + fprintf(codefile, " err_msg(307, NULL);\n"); + if (err_conv) + fprintf(codefile, " return A_Resume;\n"); + fprintf(codefile, " }\n"); + fprintf(codefile, " for (i = %d; i >= 0; i--)\n", nfields - 1); + fprintf(codefile, " if (i < r_nargs)\n"); + fprintf(codefile, " deref(&r_args[i], &rp->fields[i]);\n"); + fprintf(codefile, " else\n"); + fprintf(codefile, " rp->fields[i] = nulldesc;\n"); + fprintf(codefile, " r_rslt->vword.bptr = (union block *)rp;\n"); + fprintf(codefile, " r_rslt->dword = D_Record;\n"); + fprintf(codefile, " return A_Continue;\n"); + fprintf(codefile, " }\n"); + } + +/* + * outerfnc - output code for the outer function implementing a procedure. + */ +void outerfnc(fnc) +struct c_fnc *fnc; + { + char *prefix; + char *name; + char *cnt_var; + char *sep; + int ntend; + int first_arg; + int nparms; + int optim; /* optimized interface: no arg list adjustment */ + int ret_flag; +#ifdef OptimizeLoop + int i; +#endif /* OptimizeLoop */ + + prefix = cur_proc->prefix; + name = cur_proc->name; + ntend = cur_proc->tnd_loc + num_tmp; + ChkPrefix(fnc->prefix); + optim = glookup(name)->flag & F_SmplInv; + nparms = Abs(cur_proc->nargs); + ret_flag = cur_proc->ret_flag; + + fprintf(codefile, "\n"); + if (optim) { + /* + * Arg list adjustment and dereferencing are done at call site. + * Use simplified interface. Output both function header and + * prototype. + */ + sep = ""; + fprintf(inclfile, "static int P%s_%s (", prefix, name); + fprintf(codefile, "static int P%s_%s(", prefix, name); + if (nparms != 0) { + fprintf(inclfile, "dptr r_args"); + fprintf(codefile, "r_args"); + sep = ", "; + } + if (ret_flag & (DoesRet | DoesSusp)) { + fprintf(inclfile, "%sdptr r_rslt", sep); + fprintf(codefile, "%sr_rslt", sep); + sep = ", "; + } + if (ret_flag & DoesSusp) { + fprintf(inclfile, "%scontinuation r_s_cont", sep); + fprintf(codefile, "%sr_s_cont", sep); + sep = ", "; + } + if (*sep == '\0') + fprintf(inclfile, "void"); + fprintf(inclfile, ");\n"); + fprintf(codefile, ")\n"); + if (nparms != 0) + fprintf(codefile, "dptr r_args;\n"); + if (ret_flag & (DoesRet | DoesSusp)) + fprintf(codefile, "dptr r_rslt;\n"); + if (ret_flag & DoesSusp) + fprintf(codefile, "continuation r_s_cont;\n"); + } + else { + /* + * General invocation interface. Output function header; prototype has + * already been produced. + */ + fprintf(codefile, + "static int P%s_%s(r_nargs, r_args, r_rslt, r_s_cont)\n", prefix, + name); + fprintf(codefile, "int r_nargs;\n"); + fprintf(codefile, "dptr r_args;\n"); + fprintf(codefile, "dptr r_rslt;\n"); + fprintf(codefile, "continuation r_s_cont;\n"); + } + + fprintf(codefile, "{\n"); + fprintf(codefile, " struct PF%s_%s r_frame;\n", prefix, name); + fprintf(codefile, " register int r_signal;\n"); + fprintf(codefile, " int i;\n"); + if (Type(Tree1(cur_proc->tree)) != N_Empty) + fprintf(codefile, " static int first_time = 1;"); + fprintf(codefile, "\n"); + fprintf(codefile, " r_frame.old_pfp = pfp;\n"); + fprintf(codefile, " pfp = (struct p_frame *)&r_frame;\n"); + fprintf(codefile, " r_frame.old_argp = glbl_argp;\n"); + if (!optim || ret_flag & (DoesRet | DoesSusp)) + fprintf(codefile, " r_frame.rslt = r_rslt;\n"); + else + fprintf(codefile, " r_frame.rslt = NULL;\n"); + if (!optim || ret_flag & DoesSusp) + fprintf(codefile, " r_frame.succ_cont = r_s_cont;\n"); + else + fprintf(codefile, " r_frame.succ_cont = NULL;\n"); + fprintf(codefile, "\n"); +#ifdef OptimizeLoop + if (ntend > 0) { + if (ntend < LoopThreshold) + for (i=0; i < ntend ;i++) + fprintf(codefile, " r_frame.tend.d[%d] = nulldesc;\n", i); + else { + fprintf(codefile, " for (i = 0; i < %d; ++i)\n", ntend); + fprintf(codefile, " r_frame.tend.d[i] = nulldesc;\n"); + } + } +#else /* OptimizeLoop */ + fprintf(codefile, " for (i = 0; i < %d; ++i)\n", ntend); + fprintf(codefile, " r_frame.tend.d[i] = nulldesc;\n"); +#endif /* OptimizeLoop */ + if (optim) { + /* + * Dereferencing and argument list adjustment is done at the call + * site. There is not much to do here. + */ + if (nparms == 0) + fprintf(codefile, " glbl_argp = NULL;\n"); + else + fprintf(codefile, " glbl_argp = r_args;\n"); + } + else { + /* + * Dereferencing and argument list adjustment must be done by + * the procedure itself. + */ + first_arg = ntend; + ntend += nparms; + if (cur_proc->nargs < 0) { + /* + * varargs - construct a list into the last argument. + */ + nparms -= 1; + if (nparms == 0) + cnt_var = "r_nargs"; + else { + fprintf(codefile, " i = r_nargs - %d;\n", nparms); + cnt_var = "i"; + } + fprintf(codefile," if (%s <= 0)\n", cnt_var); + fprintf(codefile," varargs(NULL, 0, &r_frame.tend.d[%d]);\n", + first_arg + nparms); + fprintf(codefile," else\n"); + fprintf(codefile, + " varargs(&r_args[%d], %s, &r_frame.tend.d[%d]);\n", nparms, + cnt_var, first_arg + nparms); + } + if (nparms > 0) { + /* + * Output code to dereference argument or supply default null + * value. + */ +#ifdef OptimizeLoop + fprintf(codefile, " for (i = 0; i < r_nargs ; ++i)\n"); + fprintf(codefile, " deref(&r_args[i], &r_frame.tend.d[i + %d]);\n", first_arg); + fprintf(codefile, " for(i = r_nargs; i < %d ; ++i)\n", nparms); + fprintf(codefile, " r_frame.tend.d[i + %d] = nulldesc;\n", + first_arg); +#else /* OptimizeLoop */ + fprintf(codefile, " for (i = 0; i < %d; ++i)\n", nparms); + fprintf(codefile, " if (i < r_nargs)\n"); + fprintf(codefile, + " deref(&r_args[i], &r_frame.tend.d[i + %d]);\n", + first_arg); + fprintf(codefile, " else\n"); + fprintf(codefile, " r_frame.tend.d[i + %d] = nulldesc;\n", + first_arg); +#endif /* OptimizeLoop */ + } + fprintf(codefile, " glbl_argp = &r_frame.tend.d[%d];\n", first_arg); + } + fprintf(codefile, " r_frame.tend.num = %d;\n", ntend); + fprintf(codefile, " r_frame.tend.previous = tend;\n"); + fprintf(codefile, " tend = (struct tend_desc *)&r_frame.tend;\n"); + if (line_info) { + fprintf(codefile, " r_frame.debug.old_line = line_num;\n"); + fprintf(codefile, " r_frame.debug.old_fname = file_name;\n"); + } + if (debug_info) { + fprintf(codefile, " r_frame.debug.proc = (struct b_proc *)&BP%s_%s;\n", + prefix, name); + fprintf(codefile, " if (k_trace) ctrace();\n"); + fprintf(codefile, " ++k_level;\n\n"); + } + fprintf(codefile, "\n"); + + /* + * Output definition for procedure frame. + */ + prt_frame(prefix, ntend, num_itmp, num_dtmp, num_sbuf, num_cbuf); + + /* + * Output code to implement procedure body. + */ + prtcode(&(fnc->cd), 1); + fprintf(codefile, " }\n"); + } + +/* + * prt_fnc - output C function that implements a continuation. + */ +void prt_fnc(fnc) +struct c_fnc *fnc; + { + struct code *sig; + char *name; + char *prefix; + + if (fnc->flag & CF_SigOnly) { + /* + * This function only returns a signal. A shared function is used in + * its place. Make sure that function has been printed. + */ + sig = fnc->cd.next->SigRef->sig; + if (sig->cd_id != C_Resume) { + sig = ChkBound(sig); + if (!(sig->LabFlg & FncPrtd)) { + ChkSeqNum(sig); + fprintf(inclfile, "static int sig_%d (void);\n", + sig->SeqNum); + + fprintf(codefile, "\n"); + fprintf(codefile, "static int sig_%d()\n", sig->SeqNum); + fprintf(codefile, " {\n"); + fprintf(codefile, " return %d; /* %s */\n", sig->SeqNum, + sig->Desc); + fprintf(codefile, " }\n"); + sig->LabFlg |= FncPrtd; + } + } + } + else { + ChkPrefix(fnc->prefix); + prefix = fnc->prefix; + name = cur_proc->name; + + fprintf(inclfile, "static int P%s_%s (void);\n", prefix, name); + + fprintf(codefile, "\n"); + fprintf(codefile, "static int P%s_%s()\n", prefix, name); + fprintf(codefile, " {\n"); + if (fnc->flag & CF_Coexpr) + fprintf(codefile, "#ifdef Coexpr\n"); + + prefix = fnc->frm_prfx; + + fprintf(codefile, " register int r_signal;\n"); + fprintf(codefile, " register struct PF%s_%s *r_pfp;\n", prefix, name); + fprintf(codefile, "\n"); + fprintf(codefile, " r_pfp = (struct PF%s_%s *)pfp;\n", prefix, name); + prtcode(&(fnc->cd), 0); + if (fnc->flag & CF_Coexpr) { + fprintf(codefile, "#else\t\t\t\t\t/* Coexpr */\n"); + fprintf(codefile, " fatalerr(401, NULL);\n"); + fprintf(codefile, "#endif\t\t\t\t\t/* Coexpr */\n"); + } + fprintf(codefile, " }\n"); + } + } + +/* + * prt_frame - output the definition for a procedure frame. + */ +void prt_frame(prefix, ntend, n_itmp, n_dtmp, n_sbuf, n_cbuf) +char *prefix; +int ntend; +int n_itmp; +int n_dtmp; +int n_sbuf; +int n_cbuf; + { + int i; + + /* + * Output standard part of procedure frame including tended + * descriptors. + */ + fprintf(inclfile, "\n"); + fprintf(inclfile, "struct PF%s_%s {\n", prefix, cur_proc->name); + fprintf(inclfile, " struct p_frame *old_pfp;\n"); + fprintf(inclfile, " dptr old_argp;\n"); + fprintf(inclfile, " dptr rslt;\n"); + fprintf(inclfile, " continuation succ_cont;\n"); + fprintf(inclfile, " struct {\n"); + fprintf(inclfile, " struct tend_desc *previous;\n"); + fprintf(inclfile, " int num;\n"); + fprintf(inclfile, " struct descrip d[%d];\n", MinOne(ntend)); + fprintf(inclfile, " } tend;\n"); + + if (line_info) { /* must be true if debug_info is true */ + fprintf(inclfile, " struct debug debug;\n"); + } + + /* + * Output declarations for the integer, double, string buffer, + * and cset buffer work areas of the frame. + */ + for (i = 0; i < n_itmp; ++i) + fprintf(inclfile, " word i%d;\n", i); + for (i = 0; i < n_dtmp; ++i) + fprintf(inclfile, " double d%d;\n", i); + if (n_sbuf > 0) + fprintf(inclfile, " char sbuf[%d][MaxCvtLen];", n_sbuf); + if (n_cbuf > 0) + fprintf(inclfile, " struct b_cset cbuf[%d];", n_cbuf); + fprintf(inclfile, " };\n"); + } + +/* + * prtcode - print a list of C code. + */ +static void prtcode(cd, outer) +struct code *cd; +int outer; + { + struct lentry *var; + struct centry *lit; + struct code *sig; + int n; + + for ( ; cd != NULL; cd = cd->next) { + switch (cd->cd_id) { + case C_Null: + break; + + case C_NamedVar: + /* + * Construct a reference to a named variable in a result + * location. + */ + var = cd->NamedVar; + fprintf(codefile, " "); + val_loc(cd->Rslt, outer); + fprintf(codefile, ".dword = D_Var;\n"); + fprintf(codefile, " "); + val_loc(cd->Rslt, outer); + fprintf(codefile, ".vword.descptr = &"); + prt_var(var, outer); + fprintf(codefile, ";\n"); + break; + + case C_CallSig: + /* + * Call to C function that returns a signal along with signal + * handling code. + */ + if (opt_sgnl) + good_clsg(cd, outer); + else + smpl_clsg(cd, outer); + break; + + case C_RetSig: + /* + * Return a signal. + */ + sig = cd->SigRef->sig; + if (sig->cd_id == C_Resume) + fprintf(codefile, " return A_Resume;\n"); + else { + sig = ChkBound(sig); + ChkSeqNum(sig); + fprintf(codefile, " return %d; /* %s */\n", sig->SeqNum, + sig->Desc); + } + break; + + case C_Goto: + /* + * goto label. + */ + ChkSeqNum(cd->Lbl); + fprintf(codefile, " goto L%d /* %s */;\n", cd->Lbl->SeqNum, + cd->Lbl->Desc); + break; + + case C_Label: + /* + * numbered label. + */ + if (cd->RefCnt > 0) { + ChkSeqNum(cd); + fprintf(codefile, "L%d: ; /* %s */\n", cd->SeqNum, cd->Desc); + } + break; + + case C_Lit: + /* + * Assign literal value to a result location. + */ + lit = cd->Literal; + fprintf(codefile, " "); + val_loc(cd->Rslt, outer); + switch (lit->flag) { + case F_CsetLit: + fprintf(codefile, ".dword = D_Cset;\n"); + fprintf(codefile, " "); + val_loc(cd->Rslt, outer); + fprintf(codefile, ".vword.bptr = (union block *)&BDC%s;\n", + lit->prefix); + break; + case F_IntLit: + if (lit->u.intgr == -1) { + /* + * Large integer literal - output string and convert + * to integer. + */ + fprintf(codefile, ".vword.sptr = \"%s\";\n", lit->image); + fprintf(codefile, " "); + val_loc(cd->Rslt, outer); + fprintf(codefile, ".dword = %d;\n", strlen(lit->image)); + fprintf(codefile, " cnv_int(&"); + val_loc(cd->Rslt, outer); + fprintf(codefile, ", &"); + val_loc(cd->Rslt, outer); + fprintf(codefile, ");\n"); + } + else { + /* + * Ordinary integer literal. + */ + fprintf(codefile, ".dword = D_Integer;\n"); + fprintf(codefile, " "); + val_loc(cd->Rslt, outer); + fprintf(codefile, ".vword.integr = %ld;\n", lit->u.intgr); + } + break; + case F_RealLit: + fprintf(codefile, ".dword = D_Real;\n"); + fprintf(codefile, " "); + val_loc(cd->Rslt, outer); + fprintf(codefile, ".vword.bptr = (union block *)&BDR%s;\n", + lit->prefix); + break; + case F_StrLit: + fprintf(codefile, ".vword.sptr = "); + if (lit->length == 0) { + /* + * Placing an empty string at the end of the string region + * allows some concatenation optimizations at run time. + */ + fprintf(codefile, "strfree;\n"); + n = 0; + } + else { + fprintf(codefile, "\""); + n = prt_i_str(codefile, lit->image, lit->length); + fprintf(codefile, "\";\n"); + } + fprintf(codefile, " "); + val_loc(cd->Rslt, outer); + fprintf(codefile, ".dword = %d;\n", n); + break; + } + break; + + case C_PFail: + /* + * Procedure failure - this code occurs once near the end of + * the procedure. + */ + if (debug_info) { + fprintf(codefile, " --k_level;\n"); + fprintf(codefile, " if (k_trace) failtrace();\n"); + } + fprintf(codefile, " tend = r_frame.tend.previous;\n"); + fprintf(codefile, " pfp = r_frame.old_pfp;\n"); + fprintf(codefile, " glbl_argp = r_frame.old_argp;\n"); + if (line_info) { + fprintf(codefile, " line_num = r_frame.debug.old_line;\n"); + fprintf(codefile, " file_name = r_frame.debug.old_fname;\n"); + } + fprintf(codefile, " return A_Resume;\n"); + break; + + case C_PRet: + /* + * Procedure return - this code occurs once near the end of + * the procedure. + */ + if (debug_info) { + fprintf(codefile, " --k_level;\n"); + fprintf(codefile, " if (k_trace) rtrace();\n"); + } + fprintf(codefile, " tend = r_frame.tend.previous;\n"); + fprintf(codefile, " pfp = r_frame.old_pfp;\n"); + fprintf(codefile, " glbl_argp = r_frame.old_argp;\n"); + if (line_info) { + fprintf(codefile, " line_num = r_frame.debug.old_line;\n"); + fprintf(codefile, " file_name = r_frame.debug.old_fname;\n"); + } + fprintf(codefile, " return A_Continue;\n"); + break; + + case C_PSusp: + /* + * Procedure suspend - call success continuation. + */ + prtpccall(outer); + break; + + case C_Break: + fprintf(codefile, " break;\n"); + break; + + case C_If: + /* + * C if statement. + */ + fprintf(codefile, " if ("); + prt_ary(cd->Cond, outer); + fprintf(codefile, ")\n "); + prtcode(cd->ThenStmt, outer); + break; + + case C_CdAry: + /* + * Array of code fragments. + */ + fprintf(codefile, " "); + prt_ary(cd, outer); + fprintf(codefile, "\n"); + break; + + case C_LBrack: + fprintf(codefile, " {\n"); + break; + + case C_RBrack: + fprintf(codefile, " }\n"); + break; + + case C_Create: + /* + * Code to create a co-expression and assign it to a result + * location. + */ + fprintf(codefile, " "); + val_loc(cd->Rslt, outer); + fprintf(codefile , ".vword.bptr = (union block *)create("); + prt_cont(cd->Cont); + fprintf(codefile, + ", (struct b_proc *)&BP%s_%s, %d, sizeof(word) * %d);\n", + cur_proc->prefix, cur_proc->name, cd->NTemps, cd->WrkSize); + fprintf(codefile, " "); + val_loc(cd->Rslt, outer); + fprintf(codefile, ".dword = D_Coexpr;\n"); + break; + + case C_SrcLoc: + /* + * Update file name and line number information. + */ + if (cd->FileName != NULL) { + fprintf(codefile, " file_name = \""); + prt_i_str(codefile, cd->FileName, strlen(cd->FileName)); + fprintf(codefile, "\";\n"); + } + if (cd->LineNum != 0) + fprintf(codefile, " line_num = %d;\n", cd->LineNum); + break; + } + } + } + +/* + * prt_var - output C code to reference an Icon named variable. + */ +static void prt_var(var, outer) +struct lentry *var; +int outer; + { + switch (var->flag) { + case F_Global: + fprintf(codefile, "globals[%d]", var->val.global->index); + break; + case F_Static: + fprintf(codefile, "statics[%d]", var->val.index); + break; + case F_Dynamic: + frame(outer); + fprintf(codefile, ".tend.d[%d]", var->val.index); + break; + case F_Argument: + fprintf(codefile, "glbl_argp[%d]", var->val.index); + } + + /* + * Include an identifying comment. + */ + fprintf(codefile, " /* %s */", var->name); + } + +/* + * prt_ary - print an array of code fragments. + */ +static void prt_ary(cd, outer) +struct code *cd; +int outer; + { + int i; + + for (i = 0; cd->ElemTyp(i) != A_End; ++i) + switch (cd->ElemTyp(i)) { + case A_Str: + /* + * Simple C code in a string. + */ + fprintf(codefile, "%s", cd->Str(i)); + break; + case A_ValLoc: + /* + * Value location (usually variable of some sort). + */ + val_loc(cd->ValLoc(i), outer); + break; + case A_Intgr: + /* + * Integer. + */ + fprintf(codefile, "%d", cd->Intgr(i)); + break; + case A_ProcCont: + /* + * Current procedure call's success continuation. + */ + if (outer) + fprintf(codefile, "r_s_cont"); + else + fprintf(codefile, "r_pfp->succ_cont"); + break; + case A_SBuf: + /* + * One of the string buffers. + */ + frame(outer); + fprintf(codefile, ".sbuf[%d]", cd->Intgr(i)); + break; + case A_CBuf: + /* + * One of the cset buffers. + */ + fprintf(codefile, "&("); + frame(outer); + fprintf(codefile, ".cbuf[%d])", cd->Intgr(i)); + break; + case A_Ary: + /* + * A subarray of code fragments. + */ + prt_ary(cd->Array(i), outer); + break; + } + } + +/* + * frame - access to the procedure frame. Access directly from outer function, + * but access through r_pfp from a continuation. + */ +static void frame(outer) +int outer; + { + if (outer) + fprintf(codefile, "r_frame"); + else + fprintf(codefile, "(*r_pfp)"); + } + +/* + * prtpccall - print procedure continuation call. + */ +static void prtpccall(outer) +int outer; + { + int first_arg; + int optim; /* optimized interface: no arg list adjustment */ + + first_arg = cur_proc->tnd_loc + num_tmp; + optim = glookup(cur_proc->name)->flag & F_SmplInv; + + /* + * The only signal to be handled in this procedure is + * resumption, the rest must be passed on. + */ + if (cur_proc->nargs != 0 && optim && !outer) { + fprintf(codefile, " {\n"); + fprintf(codefile, " dptr r_argp_sav;\n"); + fprintf(codefile, "\n"); + fprintf(codefile, " r_argp_sav = glbl_argp;\n"); + } + if (debug_info) { + fprintf(codefile, " --k_level;\n"); + fprintf(codefile, " if (k_trace) strace();\n"); + } + fprintf(codefile, " pfp = "); + frame(outer); + fprintf(codefile, ".old_pfp;\n"); + fprintf(codefile, " glbl_argp = "); + frame(outer); + fprintf(codefile, ".old_argp;\n"); + if (line_info) { + fprintf(codefile, " line_num = "); + frame(outer); + fprintf(codefile, ".debug.old_line;\n"); + fprintf(codefile, " file_name = "); + frame(outer); + fprintf(codefile , ".debug.old_fname;\n"); + } + fprintf(codefile, " r_signal = (*"); + if (outer) + fprintf(codefile, "r_s_cont)();\n"); + else + fprintf(codefile, "r_pfp->succ_cont)();\n"); + fprintf(codefile, " if (r_signal != A_Resume) {\n"); + if (outer) + fprintf(codefile, " tend = r_frame.tend.previous;\n"); + fprintf(codefile, " return r_signal;\n"); + fprintf(codefile, " }\n"); + fprintf(codefile, " pfp = (struct p_frame *)&"); + frame(outer); + fprintf(codefile, ";\n"); + if (cur_proc->nargs == 0) + fprintf(codefile, " glbl_argp = NULL;\n"); + else { + if (optim) { + if (outer) + fprintf(codefile, " glbl_argp = r_args;\n"); + else + fprintf(codefile, " glbl_argp = r_argp_sav;\n"); + } + else { + fprintf(codefile, " glbl_argp = &"); + if (outer) + fprintf(codefile, "r_frame."); + else + fprintf(codefile, "r_pfp->"); + fprintf(codefile, "tend.d[%d];\n", first_arg); + } + } + if (debug_info) { + fprintf(codefile, " if (k_trace) atrace();\n"); + fprintf(codefile, " ++k_level;\n"); + } + if (cur_proc->nargs != 0 && optim && !outer) + fprintf(codefile, " }\n"); + } + +/* + * smpl_clsg - print call and signal handling code, but nothing fancy. + */ +static void smpl_clsg(call, outer) +struct code *call; +int outer; + { + struct sig_act *sa; + + fprintf(codefile, " r_signal = "); + prtcall(call, outer); + fprintf(codefile, ";\n"); + if (call->Flags & ForeignSig) + chkforgn(outer); + fprintf(codefile, " switch (r_signal) {\n"); + for (sa = call->SigActs; sa != NULL; sa = sa->next) { + fprintf(codefile, " case "); + prt_cond(sa->sig); + fprintf(codefile, ":\n "); + prtcode(sa->cd, outer); + } + fprintf(codefile, " }\n"); + } + +/* + * chkforgn - produce code to see if the current signal belongs to a + * procedure higher up the call chain and pass it along if it does. + */ +static void chkforgn(outer) +int outer; + { + fprintf(codefile, " if (pfp != (struct p_frame *)"); + if (outer) { + fprintf(codefile, "&r_frame) {\n"); + fprintf(codefile, " tend = r_frame.tend.previous;\n"); + } + else + fprintf(codefile, "r_pfp) {\n"); + fprintf(codefile, " return r_signal;\n"); + fprintf(codefile, " }\n"); + } + +/* + * good_clsg - print call and signal handling code and do a good job. + */ +static void good_clsg(call, outer) +struct code *call; +int outer; + { + struct sig_act *sa, *sa1, *nxt_sa; + int ncases; /* the number of cases - each may have multiple case labels */ + int ncaselbl; /* the number of case labels */ + int nbreak; /* the number of cases that just break out of the switch */ + int nretsig; /* the number of cases that just pass along signal */ + int sig_var; + int dflt; + struct code *cond; + struct code *then_cd; + + /* + * Decide whether to use "break;", "return r_signal;", or nothing as + * the default case. + */ + nretsig = 0; + nbreak = 0; + for (sa = call->SigActs; sa != NULL; sa = sa->next) { + if (sa->cd->cd_id == C_RetSig && sa->sig == sa->cd->SigRef->sig) { + /* + * The action returns the same signal detected by this case. + */ + ++nretsig; + } + else if (sa->cd->cd_id == C_Break) { + cond = sa->sig; /* if there is only one break, we may want this */ + ++nbreak; + } + } + dflt = DfltNone; + ncases = 0; + if (nbreak > 0 && nbreak >= nretsig) { + /* + * There are at least as many "break;"s as "return r_signal;"s, so + * use "break;" for default clause. + */ + dflt = DfltBrk; + ncases = 1; + } + else if (nretsig > 1) { + /* + * There is more than one case that returns the same signal it + * detects and there are more of them than "break;"s, to make + * "return r_signal;" the default clause. + */ + dflt = DfltRetSig; + ncases = 1; + } + + /* + * Gather case labels together for each case, ignoring cases that + * fall under the default. This involves constructing a new + * improved call->SigActs list. + */ + ncaselbl = ncases; + sa = call->SigActs; + call->SigActs = NULL; + for ( ; sa != NULL; sa = nxt_sa) { + nxt_sa = sa->next; + /* + * See if we have already found a case with the same action. + */ + sa1 = call->SigActs; + switch (sa->cd->cd_id) { + case C_Break: + if (dflt == DfltBrk) + continue; + while (sa1 != NULL && sa1->cd->cd_id != C_Break) + sa1 = sa1->next; + break; + case C_RetSig: + if (dflt == DfltRetSig && sa->cd->SigRef->sig == sa->sig) + continue; + while (sa1 != NULL && (sa1->cd->cd_id != C_RetSig || + sa1->cd->SigRef->sig != sa->cd->SigRef->sig)) + sa1 = sa1->next; + break; + default: /* C_Goto */ + while (sa1 != NULL && (sa1->cd->cd_id != C_Goto || + sa1->cd->Lbl != sa->cd->Lbl)) + sa1 = sa1->next; + break; + } + ++ncaselbl; + if (sa1 == NULL) { + /* + * First time we have seen this action, create a new case. + */ + ++ncases; + sa->next = call->SigActs; + call->SigActs = sa; + } + else { + /* + * We can share the action of another case label. + */ + sa->shar_act = sa1->shar_act; + sa1->shar_act = sa; + } + } + + /* + * If we might receive a "foreign" signal that belongs to a procedure + * further down the call chain, put the signal in "r_signal" then + * check for this condition. + */ + sig_var = 0; + if (call->Flags & ForeignSig) { + fprintf(codefile, " r_signal = "); + prtcall(call, outer); + fprintf(codefile, ";\n"); + chkforgn(outer); + sig_var = 1; + } + + /* + * Determine the best way to handle the signal returned from the call. + */ + if (ncases == 0) { + /* + * Any further signal checking has been optimized away. Execution + * just falls through to subsequent code. If the call has not + * been done, do it. + */ + if (!sig_var) { + fprintf(codefile, " "); + prtcall(call, outer); + fprintf(codefile, ";\n"); + } + } + else if (ncases == 1) { + if (dflt == DfltRetSig || ncaselbl == nretsig) { + /* + * All this call does is pass the signal on. See if we have + * done the call yet. + */ + if (sig_var) + fprintf(codefile, " return r_signal;"); + else { + fprintf(codefile, " return "); + prtcall(call, outer); + fprintf(codefile, ";\n"); + } + } + else { + /* + * We know what to do without looking at the signal. Make sure + * we have done the call. If the action is not simply "break" + * out signal checking, execute it. + */ + if (!sig_var) { + fprintf(codefile, " "); + prtcall(call, outer); + fprintf(codefile, ";\n"); + } + if (dflt != DfltBrk) + prtcode(call->SigActs->cd, outer); + } + } + else { + /* + * We have at least two cases. If we have a default action of returning + * the signal without looking at it, make sure it is in "r_signal". + */ + if (!sig_var && dflt == DfltRetSig) { + fprintf(codefile, " r_signal = "); + prtcall(call, outer); + fprintf(codefile, ";\n"); + sig_var = 1; + } + + if (ncaselbl == 2) { + /* + * We can use an if statement. If we need the signal in "r_signal", + * it is already there. + */ + fprintf(codefile, " if ("); + if (sig_var) + fprintf(codefile, "r_signal"); + else + prtcall(call, outer); + + cond = call->SigActs->sig; + then_cd = call->SigActs->cd; + + /* + * If the "then" clause is a no-op ("break;" from a switch), + * prepare to eliminate it by reversing the test in the + * condition. + */ + if (then_cd->cd_id == C_Break) + fprintf(codefile, " != "); + else + fprintf(codefile, " == "); + + prt_cond(cond); + fprintf(codefile, ")\n "); + + if (then_cd->cd_id == C_Break) { + /* + * We have reversed the test, so we need to use the default + * code. However, because a "break;" exists and it is not + * default, "return r_signal;" must be the default. + */ + fprintf(codefile, " return r_signal;\n"); + } + else { + /* + * Print the "then" clause and determine what the "else" clause + * is. + */ + prtcode(then_cd, outer); + if (call->SigActs->next != NULL) { + fprintf(codefile, " else\n "); + prtcode(call->SigActs->next->cd, outer); + } + else if (dflt == DfltRetSig) { + fprintf(codefile, " else\n"); + fprintf(codefile, " return r_signal;\n"); + } + } + } + else if (ncases == 2 && nbreak == 1) { + /* + * We can use an if-then statement with a negated test. Note, + * the non-break case is not "return r_signal" or we would have + * ncaselbl = 2, making the last test true. This also means that + * break is the default (the break condition was saved). + */ + fprintf(codefile, " if ("); + if (sig_var) + fprintf(codefile, "r_signal"); + else + prtcall(call, outer); + fprintf(codefile, " != "); + prt_cond(cond); + fprintf(codefile, ") {\n "); + prtcode(call->SigActs->cd, outer); + fprintf(codefile, " }\n"); + } + else { + /* + * We must use a full case statement. If we need the signal in + * "r_signal", it is already there. + */ + fprintf(codefile, " switch ("); + if (sig_var) + fprintf(codefile, "r_signal"); + else + prtcall(call, outer); + fprintf(codefile, ") {\n"); + + /* + * Print the cases + */ + for (sa = call->SigActs; sa != NULL; sa = sa->next) { + for (sa1 = sa; sa1 != NULL; sa1 = sa1->shar_act) { + fprintf(codefile, " case "); + prt_cond(sa1->sig); + fprintf(codefile, ":\n"); + } + fprintf(codefile, " "); + prtcode(sa->cd, outer); + } + + /* + * If we have a default action and it is not break, print it. + */ + if (dflt == DfltRetSig) { + fprintf(codefile, " default:\n"); + fprintf(codefile, " return r_signal;\n"); + } + + fprintf(codefile, " }\n"); + } + } + } + +/* + * prtcall - print call. + */ +static void prtcall(call, outer) +struct code *call; +int outer; + { + /* + * Either the operation or the continuation may be missing, but not + * both. + */ + if (call->OperName == NULL) { + prt_cont(call->Cont); + fprintf(codefile, "()"); + } + else { + fprintf(codefile, "%s(", call->OperName); + if (call->ArgLst != NULL) + prt_ary(call->ArgLst, outer); + if (call->Cont == NULL) { + if (call->Flags & NeedCont) { + /* + * The operation requires a continuation argument even though + * this call does not include one, pass the NULL pointer. + */ + if (call->ArgLst != NULL) + fprintf(codefile, ", "); + fprintf(codefile, "(continuation)NULL"); + } + } + else { + /* + * Pass the success continuation. + */ + if (call->ArgLst != NULL) + fprintf(codefile, ", "); + prt_cont(call->Cont); + } + fprintf(codefile, ")"); + } + } + +/* + * prt_cont - print the name of a continuation. + */ +static void prt_cont(cont) +struct c_fnc *cont; + { + struct code *sig; + + if (cont->flag & CF_SigOnly) { + /* + * This continuation only returns a signal. All continuations + * returning the same signal are implemented by the same C function. + */ + sig = cont->cd.next->SigRef->sig; + if (sig->cd_id == C_Resume) + fprintf(codefile, "sig_rsm"); + else { + sig = ChkBound(sig); + ChkSeqNum(sig); + fprintf(codefile, "sig_%d", sig->SeqNum); + } + } + else { + /* + * Regular continuation. + */ + ChkPrefix(cont->prefix); + fprintf(codefile, "P%s_%s", cont->prefix, cur_proc->name); + } + } + +/* + * val_loc - output code referencing a value location (usually variable of + * some sort). + */ +static void val_loc(loc, outer) +struct val_loc *loc; +int outer; + { + /* + * See if we need to cast a block pointer to a specific block type + * or if we need to take the address of a location. + */ + if (loc->mod_access == M_BlkPtr && loc->blk_name != NULL) + fprintf(codefile, "(*(struct %s **)&", loc->blk_name); + if (loc->mod_access == M_Addr) + fprintf(codefile, "(&"); + + switch (loc->loc_type) { + case V_Ignore: + fprintf(codefile, "trashcan"); + break; + case V_Temp: + /* + * Temporary descriptor variable. + */ + frame(outer); + fprintf(codefile, ".tend.d[%d]", cur_proc->tnd_loc + loc->u.tmp); + break; + case V_ITemp: + /* + * Temporary C integer variable. + */ + frame(outer); + fprintf(codefile, ".i%d", loc->u.tmp); + break; + case V_DTemp: + /* + * Temporary C double variable. + */ + frame(outer); + fprintf(codefile, ".d%d", loc->u.tmp); + break; + case V_Const: + /* + * Integer constant (used for size of variable part of arg list). + */ + fprintf(codefile, "%d", loc->u.int_const); + break; + case V_NamedVar: + /* + * Icon named variable. + */ + prt_var(loc->u.nvar, outer); + break; + case V_CVar: + /* + * C variable from in-line code. + */ + fprintf(codefile, "%s", loc->u.name); + break; + case V_PRslt: + /* + * Procedure result location. + */ + if (!outer) + fprintf(codefile, "(*r_pfp->rslt)"); + else + fprintf(codefile, "(*r_rslt)"); + break; + } + + /* + * See if we are accessing the vword of a descriptor. + */ + switch (loc->mod_access) { + case M_CharPtr: + fprintf(codefile, ".vword.sptr"); + break; + case M_BlkPtr: + fprintf(codefile, ".vword.bptr"); + if (loc->blk_name != NULL) + fprintf(codefile, ")"); + break; + case M_CInt: + fprintf(codefile, ".vword.integr"); + break; + case M_Addr: + fprintf(codefile, ")"); + break; + } + } + +/* + * prt_cond - print a condition (signal number). + */ +static void prt_cond(cond) +struct code *cond; + { + if (cond == &resume) + fprintf(codefile, "A_Resume"); + else if (cond == &contin) + fprintf(codefile, "A_Continue"); + else if (cond == &fallthru) + fprintf(codefile, "A_FallThru"); + else { + cond = ChkBound(cond); + ChkSeqNum(cond); + fprintf(codefile, "%d /* %s */", cond->SeqNum, cond->Desc); + } + } + +/* + * initpblk - write a procedure block along with initialization up to the + * the array of qualifiers. + */ +static void initpblk(f, c, prefix, name, nquals, nparam, ndynam, nstatic, + frststat) +FILE *f; /* output file */ +int c; /* distinguishes procedures, functions, record constructors */ +char* prefix; /* prefix for name */ +char *name; /* name of routine */ +int nquals; /* number of qualifiers at end of block */ +int nparam; /* number of parameters */ +int ndynam; /* number of dynamic locals or function/record indicator */ +int nstatic; /* number of static locals or record number */ +int frststat; /* index into static array of first static local */ + { + fprintf(f, "B_IProc(%d) B%c%s_%s = ", nquals, c, prefix, name); + fprintf(f, "{T_Proc, %d, %c%s_%s, %d, %d, %d, %d, {", 9 + 2 * nquals, c, + prefix, name, nparam, ndynam, nstatic, frststat); + } + |