summaryrefslogtreecommitdiff
path: root/src/iconc/codegen.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/iconc/codegen.c')
-rw-r--r--src/iconc/codegen.c1918
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);
+ }
+