summaryrefslogtreecommitdiff
path: root/src/iconc
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2013-01-27 23:51:56 +0000
committerIgor Pashev <pashev.igor@gmail.com>2013-01-27 23:51:56 +0000
commit6ab0c0f5bf14ed9c15370407b9ee7e0b4b089ae1 (patch)
tree926065cf45450116098db664e3c61dced9e1f21a /src/iconc
downloadicon-upstream/9.4.3.tar.gz
Initial upstream version 9.4.3upstream/9.4.3
Diffstat (limited to 'src/iconc')
-rw-r--r--src/iconc/Makefile73
-rw-r--r--src/iconc/ccode.c4954
-rw-r--r--src/iconc/ccode.h252
-rw-r--r--src/iconc/ccomp.c130
-rw-r--r--src/iconc/cglobals.h50
-rw-r--r--src/iconc/cgrammar.c221
-rw-r--r--src/iconc/chkinv.c545
-rw-r--r--src/iconc/clex.c18
-rw-r--r--src/iconc/cmain.c424
-rw-r--r--src/iconc/cmem.c114
-rw-r--r--src/iconc/codegen.c1918
-rw-r--r--src/iconc/cparse.c1940
-rw-r--r--src/iconc/cproto.h165
-rw-r--r--src/iconc/csym.c853
-rw-r--r--src/iconc/csym.h380
-rw-r--r--src/iconc/ctoken.h111
-rw-r--r--src/iconc/ctrans.c184
-rw-r--r--src/iconc/ctrans.h47
-rw-r--r--src/iconc/ctree.c777
-rw-r--r--src/iconc/ctree.h200
-rw-r--r--src/iconc/dbase.c196
-rw-r--r--src/iconc/fixcode.c372
-rw-r--r--src/iconc/incheck.c802
-rw-r--r--src/iconc/inline.c2007
-rw-r--r--src/iconc/ivalues.c51
-rw-r--r--src/iconc/lifetime.c496
-rw-r--r--src/iconc/types.c893
-rw-r--r--src/iconc/typinfer.c5189
28 files changed, 23362 insertions, 0 deletions
diff --git a/src/iconc/Makefile b/src/iconc/Makefile
new file mode 100644
index 0000000..bce6aa8
--- /dev/null
+++ b/src/iconc/Makefile
@@ -0,0 +1,73 @@
+# Makefile for the Icon compiler, iconc.
+#
+# This is no longer supported and may not work.
+
+include ../../Makedefs
+
+
+OBJS = cmain.o ctrans.o dbase.o clex.o\
+ cparse.o csym.o cmem.o ctree.o ccode.o ccomp.o\
+ ivalues.o codegen.o fixcode.o inline.o chkinv.o\
+ typinfer.o types.o lifetime.o incheck.o
+
+COBJS = ../common/long.o ../common/getopt.o ../common/time.o\
+ ../common/filepart.o ../common/identify.o ../common/munix.o\
+ ../common/strtbl.o ../common/rtdb.o ../common/literals.o \
+ ../common/alloc.o ../common/ipp.o
+
+
+
+iconc: $(OBJS) $(COBJS)
+ $(CC) -o iconc $(OBJS) $(COBJS)
+ cp iconc ../../bin
+ strip ../../bin/iconc$(EXE)
+
+$(OBJS): ../h/config.h ../h/cpuconf.h ../h/cstructs.h ../h/define.h\
+ ../h/mproto.h ../h/typedefs.h ../h/gsupport.h \
+ ccode.h cglobals.h cproto.h csym.h ctrans.h ctree.h
+
+$(COBJS): ../h/mproto.h
+ cd ../common; $(MAKE); $(MAKE) xpm
+
+ccode.o: ../h/lexdef.h ctoken.h
+chkinv.o: ctoken.h
+clex.o: ../h/lexdef.h ../h/parserr.h ctoken.h \
+ ../common/lextab.h ../common/yylex.h ../common/error.h
+clocal.o: ../h/config.h
+cparse.o: ../h/lexdef.h
+ctrans.o: ctoken.h
+ctree.o: ../h/lexdef.h ctoken.h
+csym.o: ctoken.h
+dbase.o: ../h/lexdef.h
+lifetime.o: ../h/lexdef.h ctoken.h
+typinfer.o: ../h/lexdef.h ctoken.h
+types.o: ../h/lexdef.h ctoken.h
+
+
+
+# The following sections are commented out because they do not need to
+# be performed unless changes are made to cgrammar.c, ../h/grammar.h,
+# ../common/tokens.txt, or ../common/op.txt. Such changes involve
+# modifications to the syntax of Icon and are not part of the installation
+# process. However, if the distribution files are unloaded in a fashion
+# such that their dates are not set properly, the following sections would
+# be attempted.
+#
+# Note that if any changes are made to the files mentioned above, the comment
+# characters at the beginning of the following lines should be removed.
+# icont must be on your search path for these actions to work.
+#
+#../common/lextab.h ../common/yacctok.h ../common/fixgram ../common/pscript: \
+# ../common/tokens.txt ../common/op.txt
+# cd ../common; $(MAKE) gfiles
+#
+#cparse.c ctoken.h: cgram.g ../common/pscript
+## expect 218 shift/reduce conflicts
+# yacc -d cgram.g
+# ../common/pscript <y.tab.c >cparse.c
+# mv y.tab.h ctoken.h
+# rm -f y.tab.c
+#
+#cgram.g: cgrammar.c ../h/define.h ../h/grammar.h \
+# ../common/yacctok.h ../common/fixgram
+# $(CC) -E -C cgrammar.c | ../common/fixgram >cgram.g
diff --git a/src/iconc/ccode.c b/src/iconc/ccode.c
new file mode 100644
index 0000000..108cd15
--- /dev/null
+++ b/src/iconc/ccode.c
@@ -0,0 +1,4954 @@
+/*
+ * ccode.c - routines to produce internal representation of C code.
+ */
+#include "../h/gsupport.h"
+#include "../h/lexdef.h"
+#include "ctrans.h"
+#include "cglobals.h"
+#include "csym.h"
+#include "ccode.h"
+#include "ctree.h"
+#include "ctoken.h"
+#include "cproto.h"
+
+#ifdef OptimizeLit
+
+#define NO_LIMIT 0
+#define LIMITED 1
+#define LIMITED_TO_INT 2
+#define NO_TOUCH 3
+
+struct lit_tbl {
+ int modified;
+ int index;
+ int safe;
+ struct code *initial;
+ struct code *end;
+ struct val_loc *vloc;
+ struct centry *csym;
+ struct lit_tbl *prev;
+ struct lit_tbl *next;
+};
+#endif /* OptimizeLit */
+
+/*
+ * Prototypes for static functions.
+ */
+static struct c_fnc *alc_fnc (void);
+static struct tmplftm *alc_lftm (int num, union field *args);
+static int alc_tmp (int n, struct tmplftm *lifetm_ary);
+
+#ifdef OptimizePoll
+ static int analyze_poll (void);
+ static void remove_poll (void);
+#endif /* OptimizePoll */
+
+#ifdef OptimizeLit
+ static int instr (const char *str, int chr);
+ static void invalidate (struct val_loc *val,struct code *end,int code);
+ static void analyze_literals (struct code *start, struct code *top, int lvl);
+ static int eval_code (struct code *cd, struct lit_tbl *cur);
+ static void propagate_literals (void);
+ static void free_tbl (void);
+ static struct lit_tbl *alc_tbl (void);
+ static void tbl_add (truct lit_tbl *add);
+#endif /* OptimizeLit */
+
+static struct code *asgn_null (struct val_loc *loc1);
+static struct val_loc *bound (struct node *n, struct val_loc *rslt,
+ int catch_fail);
+static struct code *check_var (struct val_loc *d, struct code *lbl);
+static void deref_cd (struct val_loc *src, struct val_loc *dest);
+static void deref_ret (struct val_loc *src, struct val_loc *dest,
+ int subtypes);
+static void endlife (int kind, int indx, int old, nodeptr n);
+static struct val_loc *field_ref(struct node *n, struct val_loc *rslt);
+static struct val_loc *gen_act (nodeptr n, struct val_loc *rslt);
+static struct val_loc *gen_apply(struct node *n, struct val_loc *rslt);
+static struct val_loc *gen_args (struct node *n, int frst_arg, int nargs);
+static struct val_loc *gen_case (struct node *n, struct val_loc *rslt);
+static struct val_loc *gen_creat(struct node *n, struct val_loc *rslt);
+static struct val_loc *gen_lim (struct node *n, struct val_loc *rslt);
+static struct val_loc *gen_scan (struct node *n, struct val_loc *rslt);
+static struct val_loc *gencode (struct node *n, struct val_loc *rslt);
+static struct val_loc *genretval(struct node *n, struct node *expr,
+ struct val_loc *dest);
+static struct val_loc *inv_prc (nodeptr n, struct val_loc *rslt);
+static struct val_loc *inv_op (nodeptr n, struct val_loc *rslt);
+static nodeptr max_lftm (nodeptr n1, nodeptr n2);
+static void mk_callop (char *oper_nm, int ret_flag,
+ struct val_loc *arg1rslt, int nargs,
+ struct val_loc *rslt, int optim);
+static struct code *mk_cpyval (struct val_loc *loc1, struct val_loc *loc2);
+static struct code *new_call (void);
+static char *oper_name (struct implement *impl);
+static void restr_env (struct val_loc *sub_sav, struct val_loc *pos_sav);
+static void save_env (struct val_loc *sub_sav, struct val_loc *pos_sav);
+static void setloc (nodeptr n);
+static struct val_loc *tmp_loc (int n);
+static struct val_loc *var_ref (struct lentry *sym);
+static struct val_loc *vararg_sz(int n);
+
+#define FrstArg 2
+
+/*
+ * Information that must be passed between a loop and its next and break
+ * expressions.
+ */
+struct loop_info {
+ struct code *next_lbl; /* where to branch for a next expression */
+ struct code *end_loop; /* label at end of loop */
+ struct code *on_failure; /* where to go if the loop fails */
+ struct scan_info *scan_info; /* scanning environment upon entering loop */
+ struct val_loc *rslt; /* place to put result of loop */
+ struct c_fnc *succ_cont; /* the success continuation for the loop */
+ struct loop_info *prev; /* link to info for outer loop */
+ };
+
+/*
+ * The allocation status of a temporary variable can either be "in use",
+ * "not allocated", or reserved for use at a code position (indicated
+ * by a specific negative number).
+ */
+#define InUse 1
+#define NotAlc 0
+
+/*
+ * tmplftm is used to precompute lifetime information for use in allocating
+ * temporary variables.
+ */
+struct tmplftm {
+ int cur_status;
+ nodeptr lifetime;
+ };
+
+/*
+ * Places where &subject and &pos are saved during string scanning. "outer"
+ * values are saved when the scanning expression is executed. "inner"
+ * values are saved when the scanning expression suspends.
+ */
+struct scan_info {
+ struct val_loc *outer_sub;
+ struct val_loc *outer_pos;
+ struct val_loc *inner_sub;
+ struct val_loc *inner_pos;
+ struct scan_info *next;
+ };
+
+struct scan_info scan_base = {NULL, 0, NULL, 0, NULL};
+struct scan_info *nxt_scan = &scan_base;
+
+struct val_loc ignore; /* no values, just something to point at */
+static struct val_loc proc_rslt; /* result location for procedure */
+
+int *tmp_status = NULL; /* allocation status of temp descriptor vars */
+int *itmp_status = NULL; /* allocation status of temp C int vars*/
+int *dtmp_status = NULL; /* allocation status of temp C double vars */
+int *sbuf_status = NULL; /* allocation of string buffers */
+int *cbuf_status = NULL; /* allocation of cset buffers */
+int num_tmp; /* number of temp descriptors actually used */
+int num_itmp; /* number of temp C ints actually used */
+int num_dtmp; /* number of temp C doubles actually used */
+int num_sbuf; /* number of string buffers actually used */
+int num_cbuf; /* number of cset buffers actually used */
+int status_sz = 20; /* current size of tmp_status array */
+int istatus_sz = 20; /* current size of itmp_status array */
+int dstatus_sz = 20; /* current size of dtmp_status array */
+int sstatus_sz = 20; /* current size of sbuf_status array */
+int cstatus_sz = 20; /* current size of cbuf_status array */
+struct freetmp *freetmp_pool = NULL;
+
+static char frm_prfx[PrfxSz + 1];/* prefix for procedure frame */
+static char *lastfiln; /* last file name set in code */
+static int lastline; /* last line number set in code */
+
+#ifdef OptimizePoll
+static struct code *lastpoll;
+#endif /* OptimizePoll */
+
+#ifdef OptimizeLit
+static struct lit_tbl *tbl = NULL;
+static struct lit_tbl *free_lit_tbl = NULL;
+#endif /* OptimizeLit */
+
+static struct c_fnc *fnc_lst; /* list of C functions implementing proc */
+static struct c_fnc **flst_end; /* pointer to null pointer at end of fnc_lst */
+struct c_fnc *cur_fnc; /* C function currently being built */
+static int create_lvl = 0; /* co-expression create level */
+
+struct pentry *cur_proc; /* procedure currently being translated */
+
+struct code *on_failure; /* place to go on failure */
+
+static struct code *p_ret_lbl; /* label for procedure return */
+static struct code *p_fail_lbl; /* label for procedure fail */
+struct code *bound_sig; /* bounding signal for current procedure */
+
+/*
+ * statically declared "signals".
+ */
+struct code resume;
+struct code contin;
+struct code fallthru;
+struct code next_fail;
+
+int lbl_seq_num = 0; /* next label sequence number */
+
+#ifdef OptimizeLit
+static void print_tbl(struct lit_tbl *start) {
+ struct lit_tbl *ptr;
+
+ for (ptr=start; ptr != NULL ;ptr=ptr->next) {
+ printf("mod (%2d) strchr (%2d) ",ptr->modified,ptr->index);
+ if (ptr->csym != NULL) {
+ printf("image (%13s) ",ptr->csym->image);
+ }
+ if (ptr->vloc != NULL) {
+ printf("val (%6d) type (%d)",ptr->vloc->u.tmp,ptr->vloc->loc_type);
+ }
+ if (ptr->end == NULL)
+ printf(" END IS NULL");
+ printf("\n");
+ }
+}
+
+
+static void free_tbl() {
+/*
+ struct lit_tbl *ptr, *next;
+*/
+ free_lit_tbl = tbl;
+ tbl = NULL;
+/*
+ ptr = tbl;
+ while (ptr != NULL) {
+ next = ptr->next;
+ free(ptr);
+ ptr = next;
+ }
+ tbl = NULL;
+*/
+}
+
+
+static struct lit_tbl *alc_tbl() {
+ struct lit_tbl *new;
+ static int cnt=0;
+
+
+ if (free_lit_tbl != NULL) {
+ new = free_lit_tbl;
+ free_lit_tbl = new->next;
+ }
+ else
+ new = (struct lit_tbl *)alloc(sizeof(struct lit_tbl));
+ new->modified = NO_LIMIT;
+ new->index = -1;
+ new->safe = 1;
+ new->initial = NULL;
+ new->end = NULL;
+ new->vloc = NULL;
+ new->csym = NULL;
+ new->prev = NULL;
+ new->next = NULL;
+ return new;
+}
+#endif /* OptimizeLit */
+
+/*
+ * proccode - generate code for a procedure.
+ */
+void proccode(proc)
+struct pentry *proc;
+ {
+ struct c_fnc *fnc;
+ struct code *cd;
+ struct code *cd1;
+ struct code *lbl;
+ nodeptr n;
+ nodeptr failer;
+ int gen;
+ int i;
+#ifdef OptimizeLit
+ struct code *procstart;
+#endif /* OptimizeLit */
+
+ /*
+ * Initialize arrays used for allocating temporary variables.
+ */
+ if (tmp_status == NULL)
+ tmp_status = (int *)alloc((unsigned int)(status_sz * sizeof(int)));
+ if (itmp_status == NULL)
+ itmp_status = (int *)alloc((unsigned int)(istatus_sz * sizeof(int)));
+ if (dtmp_status == NULL)
+ dtmp_status = (int *)alloc((unsigned int)(dstatus_sz * sizeof(int)));
+ if (sbuf_status == NULL)
+ sbuf_status = (int *)alloc((unsigned int)(sstatus_sz * sizeof(int)));
+ if (cbuf_status == NULL)
+ cbuf_status = (int *)alloc((unsigned int)(cstatus_sz * sizeof(int)));
+ for (i = 0; i < status_sz; ++i)
+ tmp_status[i] = NotAlloc;
+ for (i = 0; i < istatus_sz; ++i)
+ itmp_status[i] = NotAlloc;
+ for (i = 0; i < dstatus_sz; ++i)
+ dtmp_status[i] = NotAlloc;
+ for (i = 0; i < sstatus_sz; ++i)
+ sbuf_status[i] = NotAlloc;
+ for (i = 0; i < cstatus_sz; ++i)
+ cbuf_status[i] = NotAlloc;
+ num_tmp = 0;
+ num_itmp = 0;
+ num_dtmp = 0;
+ num_sbuf = 0;
+ num_cbuf = 0;
+
+ /*
+ * Initialize standard signals.
+ */
+ resume.cd_id = C_Resume;
+ contin.cd_id = C_Continue;
+ fallthru.cd_id = C_FallThru;
+
+ /*
+ * Initialize procedure result and the transcan locations.
+ */
+ proc_rslt.loc_type = V_PRslt;
+ proc_rslt.mod_access = M_None;
+ ignore.loc_type = V_Ignore;
+ ignore.mod_access = M_None;
+
+ cur_proc = proc; /* current procedure */
+ lastfiln = NULL; /* file name */
+ lastline = 0; /* line number */
+
+#ifdef OptimizePoll
+ lastpoll = NULL;
+#endif /* OptimizePoll */
+
+ /*
+ * Procedure frame prefix is the procedure prefix.
+ */
+ for (i = 0; i < PrfxSz; ++i)
+ frm_prfx[i] = cur_proc->prefix[i];
+ frm_prfx[PrfxSz] = '\0';
+
+ /*
+ * Initialize the continuation list and allocate the outer function for
+ * this procedure.
+ */
+ fnc_lst = NULL;
+ flst_end = &fnc_lst;
+ cur_fnc = alc_fnc();
+
+#ifdef OptimizeLit
+ procstart = cur_fnc->cursor;
+#endif /* OptimizeLit */
+
+ /*
+ * If the procedure is not used anywhere don't generate code for it.
+ * This can happen when using libraries containing several procedures,
+ * but not all are needed. However, if there is a block for the
+ * procedure, we need at least a dummy function.
+ */
+ if (!cur_proc->reachable) {
+ if (!(glookup(cur_proc->name)->flag & F_SmplInv))
+ outerfnc(fnc_lst);
+ return;
+ }
+
+ /*
+ * Allocate labels for the code for procedure failure, procedure return,
+ * and allocate the bounding signal for this procedure (at this point
+ * signals and labels are not distinguished).
+ */
+ p_fail_lbl = alc_lbl("proc fail", 0);
+ p_ret_lbl = alc_lbl("proc return", 0);
+ bound_sig = alc_lbl("bound", 0);
+
+ n = proc->tree;
+ setloc(n);
+ if (Type(Tree1(n)) != N_Empty) {
+ /*
+ * initial clause.
+ */
+ Tree1(n)->lifetime = NULL;
+ liveness(Tree1(n), NULL, &failer, &gen);
+ if (tfatals > 0)
+ return;
+ lbl = alc_lbl("end initial", 0);
+ cd_add(lbl);
+ cur_fnc->cursor = lbl->prev; /* code goes before label */
+ cd = NewCode(2);
+ cd->cd_id = C_If;
+ cd1 = alc_ary(1);
+ cd1->ElemTyp(0) = A_Str;
+ cd1->Str(0) = "!first_time";
+ cd->Cond = cd1;
+ cd->ThenStmt = mk_goto(lbl);
+ cd_add(cd);
+ cd = alc_ary(1);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "first_time = 0;";
+ cd_add(cd);
+ bound(Tree1(n), &ignore, 1);
+ cur_fnc->cursor = lbl;
+ }
+ Tree2(n)->lifetime = NULL;
+ liveness(Tree2(n), NULL, &failer, &gen);
+ if (tfatals > 0)
+ return;
+ bound(Tree2(n), &ignore, 1);
+
+ /*
+ * Place code to perform procedure failure and return and the
+ * end of the outer function.
+ */
+ setloc(Tree3(n));
+ cd_add(p_fail_lbl);
+ cd = NewCode(0);
+ cd->cd_id = C_PFail;
+ cd_add(cd);
+ cd_add(p_ret_lbl);
+ cd = NewCode(0);
+ cd->cd_id = C_PRet;
+ cd_add(cd);
+
+ /*
+ * Fix up signal handling code and perform peephole optimizations.
+ */
+ fix_fncs(fnc_lst);
+
+#ifdef OptimizeLit
+ analyze_literals(procstart, NULL, 0);
+ propagate_literals();
+#endif /* OptimizeLit */
+
+ /*
+ * The outer function is the first one on the list. It has the
+ * procedure interface; the others are just continuations.
+ */
+ outerfnc(fnc_lst);
+ for (fnc = fnc_lst->next; fnc != NULL; fnc = fnc->next)
+ if (fnc->ref_cnt > 0)
+ prt_fnc(fnc);
+#ifdef OptimizeLit
+ free_tbl();
+#endif /* OptimizeLit */
+}
+
+/*
+ * gencode - generate code for a syntax tree.
+ */
+static struct val_loc *gencode(n, rslt)
+struct node *n;
+struct val_loc *rslt;
+ {
+ struct code *cd;
+ struct code *cd1;
+ struct code *fail_sav;
+ struct code *lbl1;
+ struct code *lbl2;
+ struct code *cursor_sav;
+ struct c_fnc *fnc_sav;
+ struct c_fnc *fnc;
+ struct implement *impl;
+ struct implement *impl1;
+ struct val_loc *r1[3];
+ struct val_loc *r2[2];
+ struct val_loc *frst_arg;
+ struct lentry *single;
+ struct freetmp *freetmp;
+ struct freetmp *ft;
+ struct tmplftm *lifetm_ary;
+ char *sbuf;
+ int i;
+ int tmp_indx;
+ int nargs;
+ static struct loop_info *loop_info = NULL;
+ struct loop_info *li_sav;
+
+ switch (n->n_type) {
+ case N_Activat:
+ rslt = gen_act(n, rslt);
+ break;
+
+ case N_Alt:
+ rslt = chk_alc(rslt, n->lifetime); /* insure a result location */
+
+ fail_sav = on_failure;
+ fnc_sav = cur_fnc;
+
+ /*
+ * If the first alternative fails, execution must go to the
+ * "alt" label.
+ */
+ lbl1 = alc_lbl("alt", 0);
+ on_failure = lbl1;
+
+ cd_add(lbl1);
+ cur_fnc->cursor = lbl1->prev; /* 1st alternative goes before label */
+ gencode(Tree0(n), rslt);
+
+ /*
+ * Each alternative must call the same success continuation.
+ */
+ fnc = alc_fnc();
+ callc_add(fnc);
+
+ cur_fnc = fnc_sav; /* return to the context of the label */
+ cur_fnc->cursor = lbl1; /* 2nd alternative goes after label */
+ on_failure = fail_sav; /* on failure, alternation fails */
+ gencode(Tree1(n), rslt);
+ callc_add(fnc); /* call continuation */
+
+ /*
+ * Code following the alternation goes in the continuation. If
+ * the code fails, the continuation returns the resume signal.
+ */
+ cur_fnc = fnc;
+ on_failure = &resume;
+ break;
+
+ case N_Apply:
+ rslt = gen_apply(n, rslt);
+ break;
+
+ case N_Augop:
+ impl = Impl0(n); /* assignment */
+ impl1 = Impl1(n); /* the operation */
+ if (impl == NULL || impl1 == NULL) {
+ rslt = &ignore; /* make sure code generation can continue */
+ break;
+ }
+
+ /*
+ * allocate an argument list for the operation.
+ */
+ lifetm_ary = alc_lftm(2, &n->n_field[2]);
+ tmp_indx = alc_tmp(2, lifetm_ary);
+ r1[0] = tmp_loc(tmp_indx);
+ r1[1] = tmp_loc(tmp_indx + 1);
+
+ gencode(Tree2(n), r1[0]); /* first argument */
+
+ /*
+ * allocate an argument list for the assignment and copy the
+ * value of the first argument into it.
+ */
+ lifetm_ary[0].cur_status = InUse;
+ lifetm_ary[1].cur_status = n->postn;
+ lifetm_ary[1].lifetime = n->intrnl_lftm;
+ tmp_indx = alc_tmp(2, lifetm_ary);
+ r2[0] = tmp_loc(tmp_indx++);
+ cd_add(mk_cpyval(r2[0], r1[0]));
+ r2[1] = tmp_loc(tmp_indx);
+
+ gencode(Tree3(n), r1[1]); /* second argument */
+
+ /*
+ * Produce code for the operation.
+ */
+ setloc(n);
+ implproto(impl1);
+ mk_callop(oper_name(impl1), impl1->ret_flag, r1[0], 2, r2[1], 0);
+
+ /*
+ * Produce code for the assignment.
+ */
+ implproto(impl);
+ if (impl->ret_flag & (DoesRet | DoesSusp))
+ rslt = chk_alc(rslt, n->lifetime);
+ mk_callop(oper_name(impl), impl->ret_flag, r2[0], 2, rslt, 0);
+
+ free((char *)lifetm_ary);
+ break;
+
+ case N_Bar: {
+ struct val_loc *fail_flg;
+
+ /*
+ * Allocate an integer variable to keep track of whether the
+ * repeated alternation should fail when execution reaches
+ * the top of its loop, and generate code to initialize the
+ * variable to 0.
+ */
+ fail_flg = itmp_loc(alc_itmp(n->intrnl_lftm));
+ cd = alc_ary(2);
+ cd->ElemTyp(0) = A_ValLoc;
+ cd->ValLoc(0) = fail_flg;
+ cd->ElemTyp(1) = A_Str;
+ cd->Str(1) = " = 0;";
+ cd_add(cd);
+
+ /*
+ * Code at the top of the repeated alternation loop checks
+ * the failure flag.
+ */
+ lbl1 = alc_lbl("rep alt", 0);
+ cd_add(lbl1);
+ cd = NewCode(2);
+ cd->cd_id = C_If;
+ cd1 = alc_ary(1);
+ cd1->ElemTyp(0) = A_ValLoc;
+ cd1->ValLoc(0) = fail_flg;
+ cd->Cond = cd1;
+ cd->ThenStmt = sig_cd(on_failure, cur_fnc);
+ cd_add(cd);
+
+ /*
+ * If the expression fails without producing a value, the
+ * repeated alternation must fail.
+ */
+ cd = alc_ary(2);
+ cd->ElemTyp(0) = A_ValLoc;
+ cd->ValLoc(0) = fail_flg;
+ cd->ElemTyp(1) = A_Str;
+ cd->Str(1) = " = 1;";
+ cd_add(cd);
+
+ /*
+ * Generate code for the repeated expression. If it produces
+ * a value before before backtracking occurs, the loop is
+ * repeated as indicated by the value of the failure flag.
+ */
+ on_failure = lbl1;
+ rslt = gencode(Tree0(n), rslt);
+ cd = alc_ary(2);
+ cd->ElemTyp(0) = A_ValLoc;
+ cd->ValLoc(0) = fail_flg;
+ cd->ElemTyp(1) = A_Str;
+ cd->Str(1) = " = 0;";
+ cd_add(cd);
+ }
+ break;
+
+ case N_Break:
+ if (loop_info == NULL) {
+ nfatal(n, "invalid context for a break expression", NULL);
+ rslt = &ignore;
+ break;
+ }
+
+ /*
+ * If the break is in a different string scanning context from the
+ * loop itself, generate code to restore the scanning environment.
+ */
+ if (nxt_scan != loop_info->scan_info)
+ restr_env(loop_info->scan_info->outer_sub,
+ loop_info->scan_info->outer_pos);
+
+
+ if (Tree0(n)->n_type == N_Empty && loop_info->rslt == &ignore) {
+ /*
+ * The break has no associated expression and the loop needs
+ * no value, so just branch out of the loop.
+ */
+ cd_add(sig_cd(loop_info->end_loop, cur_fnc));
+ }
+ else {
+ /*
+ * The code for the expression associated with the break is
+ * actually placed at the end of the loop. Go there and
+ * add a label to branch to.
+ */
+ cursor_sav = cur_fnc->cursor;
+ fnc_sav = cur_fnc;
+ fail_sav = on_failure;
+ cur_fnc = loop_info->end_loop->Container;
+ cur_fnc->cursor = loop_info->end_loop->prev;
+ on_failure = loop_info->on_failure;
+ lbl1 = alc_lbl("break", 0);
+ cd_add(lbl1);
+
+ /*
+ * Make sure a result location has been allocated for the
+ * loop, restore the loop information for the next outer
+ * loop, generate code for the break expression, then
+ * restore the loop information for this loop.
+ */
+ loop_info->rslt = chk_alc(loop_info->rslt, Tree0(n)->lifetime);
+ li_sav = loop_info;
+ loop_info = loop_info->prev;
+ gencode(Tree0(n), li_sav->rslt);
+ loop_info = li_sav;
+
+ /*
+ * If this or another break expression suspends so we cannot
+ * just branch to the end of the loop, all breaks must
+ * call a common continuation.
+ */
+ if (cur_fnc->cursor->next != loop_info->end_loop &&
+ loop_info->succ_cont == NULL)
+ loop_info->succ_cont = alc_fnc();
+ if (loop_info->succ_cont == NULL)
+ cd_add(mk_goto(loop_info->end_loop)); /* go to end of loop */
+ else
+ callc_add(loop_info->succ_cont); /* call continuation */
+
+ /*
+ * Return to the location of the break and generate a branch to
+ * the code for its associated expression.
+ */
+ cur_fnc = fnc_sav;
+ cur_fnc->cursor = cursor_sav;
+ on_failure = fail_sav;
+ cd_add(sig_cd(lbl1, cur_fnc));
+ }
+ rslt = &ignore; /* shouldn't be used but must be something valid */
+ break;
+
+ case N_Case:
+ rslt = gen_case(n, rslt);
+ break;
+
+ case N_Create:
+ rslt = gen_creat(n, rslt);
+ break;
+
+ case N_Cset:
+ case N_Int:
+ case N_Real:
+ case N_Str:
+ cd = NewCode(2);
+ cd->cd_id = C_Lit;
+ rslt = chk_alc(rslt, n->lifetime);
+ cd->Rslt = rslt;
+ cd->Literal = CSym0(n);
+ cd_add(cd);
+ break;
+
+ case N_Empty:
+ /*
+ * Assume null value is needed.
+ */
+ if (rslt == &ignore)
+ break;
+ rslt = chk_alc(rslt, n->lifetime);
+ cd_add(asgn_null(rslt));
+ break;
+
+ case N_Field:
+ rslt = field_ref(n, rslt);
+ break;
+
+ case N_Id:
+ /*
+ * If the variable reference is not going to be used, don't bother
+ * building it.
+ */
+ if (rslt == &ignore)
+ break;
+ cd = NewCode(2);
+ cd->cd_id = C_NamedVar;
+ rslt = chk_alc(rslt, n->lifetime);
+ cd->Rslt = rslt;
+ cd->NamedVar = LSym0(n);
+ cd_add(cd);
+ break;
+
+ case N_If:
+ if (Type(Tree2(n)) == N_Empty) {
+ /*
+ * if-then. Control clause is bounded, but otherwise trivial.
+ */
+ bound(Tree0(n), &ignore, 0); /* control clause */
+ rslt = gencode(Tree1(n), rslt); /* then clause */
+ }
+ else {
+ /*
+ * if-then-else. Establish an "else" label as the failure
+ * label of the bounded control clause.
+ */
+ fail_sav = on_failure;
+ fnc_sav = cur_fnc;
+ lbl1 = alc_lbl("else", 0);
+ on_failure = lbl1;
+
+ bound(Tree0(n), &ignore, 0); /* control clause */
+
+ cd_add(lbl1);
+ cur_fnc->cursor = lbl1->prev; /* then clause goes before else lbl */
+ on_failure = fail_sav;
+ rslt = chk_alc(rslt, n->lifetime);
+ gencode(Tree1(n), rslt); /* then clause */
+
+ /*
+ * If the then clause is not a generator, execution can
+ * just go to the end of the if-then-else expression. If it
+ * is a generator, the continuation for the expression must be
+ * in a separate function.
+ */
+ if (cur_fnc->cursor->next == lbl1) {
+ fnc = NULL;
+ lbl2 = alc_lbl("end if", 0);
+ cd_add(mk_goto(lbl2));
+ cur_fnc->cursor = lbl1;
+ cd_add(lbl2);
+ }
+ else {
+ lbl2 = NULL;
+ fnc = alc_fnc();
+ callc_add(fnc);
+ cur_fnc = fnc_sav;
+ }
+
+ cur_fnc->cursor = lbl1; /* else clause goes after label */
+ on_failure = fail_sav;
+ gencode(Tree2(n), rslt); /* else clause */
+
+ /*
+ * If the else clause is not a generator, execution is at
+ * the end of the if-then-else expression, but the if clause
+ * may have forced the continuation to be in a separate function.
+ * If the else clause is a generator, it forces the continuation
+ * to be in a separate function.
+ */
+ if (fnc == NULL) {
+ if (cur_fnc->cursor->next == lbl2)
+ cur_fnc->cursor = lbl2;
+ else {
+ fnc = alc_fnc();
+ callc_add(fnc);
+ /*
+ * The then clause is not a generator, so it has branched
+ * to lbl2. We must add a call to the continuation there.
+ */
+ cur_fnc = fnc_sav;
+ cur_fnc->cursor = lbl2;
+ on_failure = fail_sav;
+ callc_add(fnc);
+ }
+ }
+ else
+ callc_add(fnc);
+
+ if (fnc != NULL) {
+ /*
+ * We produced a continuation for the if-then-else, so code
+ * generation must proceed in it.
+ */
+ cur_fnc = fnc;
+ on_failure = &resume;
+ }
+ }
+ break;
+
+ case N_Invok:
+ /*
+ * General invocation.
+ */
+ nargs = Val0(n);
+ if (Tree1(n)->n_type == N_Empty) {
+ /*
+ * Mutual evaluation.
+ */
+ for (i = 2; i <= nargs; ++i)
+ gencode(n->n_field[i].n_ptr, &ignore); /* arg i - 1 */
+ rslt = chk_alc(rslt, n->lifetime);
+ gencode(n->n_field[nargs + 1].n_ptr, rslt); /* last argument */
+ }
+ else {
+ ++nargs; /* consider the procedure an argument to invoke() */
+ frst_arg = gen_args(n, 1, nargs);
+ setloc(n);
+ /*
+ * Assume this operation uses its result location as a work
+ * area. Give it a location that is tended, where the value
+ * is retained as long as the operation can be resumed.
+ */
+ if (rslt == &ignore)
+ rslt = NULL; /* force allocation of temporary */
+ rslt = chk_alc(rslt, max_lftm(n->lifetime, n->intrnl_lftm));
+ mk_callop( "invoke", DoesRet | DoesFail | DoesSusp, frst_arg, nargs,
+ rslt, 0);
+ }
+ break;
+
+ case N_InvOp:
+ rslt = inv_op(n, rslt);
+ break;
+
+ case N_InvProc:
+ rslt = inv_prc(n, rslt);
+ break;
+
+ case N_InvRec: {
+ /*
+ * Directly invoke a record constructor.
+ */
+ struct rentry *rec;
+
+ nargs = Val0(n); /* number of arguments */
+ frst_arg = gen_args(n, 2, nargs);
+ setloc(n);
+ rec = Rec1(n);
+
+ rslt = chk_alc(rslt, n->lifetime);
+
+ /*
+ * If error conversion can occur then the record constructor may
+ * fail and we must check the signal.
+ */
+ if (err_conv) {
+ sbuf = (char *)alloc((unsigned int)(strlen(rec->name) +
+ strlen("signal = R_") + PrfxSz + 1));
+ sprintf(sbuf, "signal = R%s_%s(", rec->prefix, rec->name);
+ }
+ else {
+ sbuf = (char *)alloc((unsigned int)(strlen(rec->name) + PrfxSz +4));
+ sprintf(sbuf, "R%s_%s(", rec->prefix, rec->name);
+ }
+ cd = alc_ary(9);
+ cd->ElemTyp(0) = A_Str; /* constructor name */
+ cd->Str(0) = sbuf;
+ cd->ElemTyp(1) = A_Intgr; /* number of arguments */
+ cd->Intgr(1) = nargs;
+ cd->ElemTyp(2) = A_Str; /* , */
+ cd->Str(2) = ", ";
+ if (frst_arg == NULL) { /* location of first argument */
+ cd->ElemTyp(3) = A_Str;
+ cd->Str(3) = "NULL";
+ cd->ElemTyp(4) = A_Str;
+ cd->Str(4) = "";
+ }
+ else {
+ cd->ElemTyp(3) = A_Str;
+ cd->Str(3) = "&";
+ cd->ElemTyp(4) = A_ValLoc;
+ cd->ValLoc(4) = frst_arg;
+ }
+ cd->ElemTyp(5) = A_Str; /* , */
+ cd->Str(5) = ", ";
+ cd->ElemTyp(6) = A_Str; /* location of result */
+ cd->Str(6) = "&";
+ cd->ElemTyp(7) = A_ValLoc;
+ cd->ValLoc(7) = rslt;
+ cd->ElemTyp(8) = A_Str;
+ cd->Str(8) = ");";
+ cd_add(cd);
+ if (err_conv) {
+ cd = NewCode(2);
+ cd->cd_id = C_If;
+ cd1 = alc_ary(1);
+ cd1->ElemTyp(0) = A_Str;
+ cd1->Str(0) = "signal == A_Resume";
+ cd->Cond = cd1;
+ cd->ThenStmt = sig_cd(on_failure, cur_fnc);
+ cd_add(cd);
+ }
+ }
+ break;
+
+ case N_Limit:
+ rslt = gen_lim(n, rslt);
+ break;
+
+ case N_Loop: {
+ struct loop_info li;
+
+ /*
+ * Set up loop information for use by break and next expressions.
+ */
+ li.end_loop = alc_lbl("end loop", 0);
+ cd_add(li.end_loop);
+ cur_fnc->cursor = li.end_loop->prev; /* loop goes before label */
+ li.rslt = rslt;
+ li.on_failure = on_failure;
+ li.scan_info = nxt_scan;
+ li.succ_cont = NULL;
+ li.prev = loop_info;
+ loop_info = &li;
+
+ switch ((int)Val0(Tree0(n))) {
+ case EVERY:
+ /*
+ * "next" in the control clause just fails.
+ */
+ li.next_lbl = &next_fail;
+ gencode(Tree1(n), &ignore); /* control clause */
+ /*
+ * "next" in the do clause transfers control to the
+ * statement at the end of the loop that resumes the
+ * control clause.
+ */
+ li.next_lbl = alc_lbl("next", 0);
+ bound(Tree2(n), &ignore, 1); /* do clause */
+ cd_add(li.next_lbl);
+ cd_add(sig_cd(on_failure, cur_fnc)); /* resume control clause */
+ break;
+
+ case REPEAT:
+ li.next_lbl = alc_lbl("repeat", 0);
+ cd_add(li.next_lbl);
+ bound(Tree1(n), &ignore, 1);
+ cd_add(mk_goto(li.next_lbl));
+ break;
+
+ case SUSPEND: /* suspension expression */
+ if (create_lvl > 0) {
+ nfatal(n, "invalid context for suspend", NULL);
+ return &ignore;
+ }
+ /*
+ * "next" in the control clause just fails. The result
+ * of the control clause goes in the procedure return
+ * location.
+ */
+ li.next_lbl = &next_fail;
+ genretval(n, Tree1(n), &proc_rslt);
+
+ /*
+ * If necessary, swap scanning environments before suspending.
+ * if there is no success continuation, just return.
+ */
+ if (nxt_scan != &scan_base) {
+ save_env(scan_base.inner_sub, scan_base.inner_pos);
+ restr_env(scan_base.outer_sub, scan_base.outer_pos);
+ }
+ cd = NewCode(2);
+ cd->cd_id = C_If;
+ cd1 = alc_ary(2);
+ cd1->ElemTyp(0) = A_ProcCont;
+ cd1->ElemTyp(1) = A_Str;
+ cd1->Str(1) = " == NULL";
+ cd->Cond = cd1;
+ cd->ThenStmt = sig_cd(p_ret_lbl, cur_fnc);
+ cd_add(cd);
+ cd = NewCode(0);
+ cd->cd_id = C_PSusp;
+ cd_add(cd);
+ cur_fnc->flag |= CF_ForeignSig;
+
+ /*
+ * Force updating file name and line number, and if needed,
+ * switch scanning environments before resuming.
+ */
+ lastfiln = NULL;
+ lastline = 0;
+ if (nxt_scan != &scan_base) {
+ save_env(scan_base.outer_sub, scan_base.outer_pos);
+ restr_env(scan_base.inner_sub, scan_base.inner_pos);
+ }
+
+ /*
+ * "next" in the do clause transfers control to the
+ * statement at the end of the loop that resumes the
+ * control clause.
+ */
+ li.next_lbl = alc_lbl("next", 0);
+ bound(Tree2(n), &ignore, 1); /* do clause */
+ cd_add(li.next_lbl);
+ cd_add(sig_cd(on_failure, cur_fnc));
+ break;
+
+ case WHILE:
+ li.next_lbl = alc_lbl("while", 0);
+ cd_add(li.next_lbl);
+ /*
+ * The control clause and do clause are both bounded expressions,
+ * but only the do clause establishes a new failure label.
+ */
+ bound(Tree1(n), &ignore, 0); /* control clause */
+ bound(Tree2(n), &ignore, 1); /* do clause */
+ cd_add(mk_goto(li.next_lbl));
+ break;
+
+ case UNTIL:
+ fail_sav = on_failure;
+ li.next_lbl = alc_lbl("until", 0);
+ cd_add(li.next_lbl);
+
+ /*
+ * If the control clause fails, execution continues in
+ * the loop.
+ */
+ if (Type(Tree2(n)) == N_Empty)
+ on_failure = li.next_lbl;
+ else {
+ lbl2 = alc_lbl("do", 0);
+ on_failure = lbl2;
+ cd_add(lbl2);
+ cur_fnc->cursor = lbl2->prev; /* control before label */
+ }
+ bound(Tree1(n), &ignore, 0); /* control clause */
+
+ /*
+ * If the control clause succeeds, the loop fails.
+ */
+ cd_add(sig_cd(fail_sav, cur_fnc));
+
+ if (Type(Tree2(n)) != N_Empty) {
+ /*
+ * Do clause goes after the label and the loop repeats.
+ */
+ cur_fnc->cursor = lbl2;
+ bound(Tree2(n), &ignore, 1); /* do clause */
+ cd_add(mk_goto(li.next_lbl));
+ }
+ break;
+ }
+
+ /*
+ * Go to the end of the loop and see if the loop's success continuation
+ * is in a separate function.
+ */
+ cur_fnc = li.end_loop->Container;
+ cur_fnc->cursor = li.end_loop;
+ if (li.succ_cont != NULL) {
+ callc_add(li.succ_cont);
+ cur_fnc = li.succ_cont;
+ on_failure = &resume;
+ }
+ if (li.rslt == NULL)
+ rslt = &ignore; /* shouldn't be used but must be something valid */
+ else
+ rslt = li.rslt;
+ loop_info = li.prev;
+ break;
+ }
+
+ case N_Next:
+ /*
+ * In some contexts "next" just fails. In other contexts it
+ * transfers control to a label, in which case it may have
+ * to restore a scanning environment.
+ */
+ if (loop_info == NULL)
+ nfatal(n, "invalid context for a next expression", NULL);
+ else if (loop_info->next_lbl == &next_fail)
+ cd_add(sig_cd(on_failure, cur_fnc));
+ else {
+ if (nxt_scan != loop_info->scan_info)
+ restr_env(loop_info->scan_info->outer_sub,
+ loop_info->scan_info->outer_pos);
+ cd_add(sig_cd(loop_info->next_lbl, cur_fnc));
+ }
+ rslt = &ignore; /* shouldn't be used but must be something valid */
+ break;
+
+ case N_Not:
+ lbl1 = alc_lbl("not", 0);
+ fail_sav = on_failure;
+ on_failure = lbl1;
+ cd_add(lbl1);
+ cur_fnc->cursor = lbl1->prev; /* code goes before label */
+ bound(Tree0(n), &ignore, 0);
+ on_failure = fail_sav;
+ cd_add(sig_cd(on_failure, cur_fnc)); /* convert success to failure */
+ cur_fnc->cursor = lbl1; /* convert failure to null */
+ if (rslt != &ignore) {
+ rslt = chk_alc(rslt, n->lifetime);
+ cd_add(asgn_null(rslt));
+ }
+ break;
+
+ case N_Ret:
+ if (create_lvl > 0) {
+ nfatal(n, "invalid context for return or fail", NULL);
+ return &ignore;
+ }
+ if (Val0(Tree0(n)) == RETURN) {
+ /*
+ * Set up the failure action of the return expression to do a
+ * procedure fail.
+ */
+ if (nxt_scan != &scan_base) {
+ /*
+ * we must switch scanning environments if the expression fails.
+ */
+ lbl1 = alc_lbl("return fail", 0);
+ cd_add(lbl1);
+ restr_env(scan_base.outer_sub, scan_base.outer_pos);
+ cd_add(sig_cd(p_fail_lbl, cur_fnc));
+ cur_fnc->cursor = lbl1->prev; /* code goes before label */
+ on_failure = lbl1;
+ }
+ else
+ on_failure = p_fail_lbl;
+
+ /*
+ * Produce code to place return value in procedure result location.
+ */
+ genretval(n, Tree1(n), &proc_rslt);
+
+ /*
+ * See if a scanning environment must be restored and
+ * transfer control to the procedure return code.
+ */
+ if (nxt_scan != &scan_base)
+ restr_env(scan_base.outer_sub, scan_base.outer_pos);
+ cd_add(sig_cd(p_ret_lbl, cur_fnc));
+ }
+ else {
+ /*
+ * fail. See if a scanning environment must be restored and
+ * transfer control to the procedure failure code.
+ */
+ if (nxt_scan != &scan_base)
+ restr_env(scan_base.outer_sub, scan_base.outer_pos);
+ cd_add(sig_cd(p_fail_lbl, cur_fnc));
+ }
+ rslt = &ignore; /* shouldn't be used but must be something valid */
+ break;
+
+ case N_Scan:
+ rslt = gen_scan(n, rslt);
+ break;
+
+ case N_Sect:
+ /*
+ * x[i+:j] or x[i-:j] (x[i:j] handled as ordinary operator)
+ */
+ impl1 = Impl0(n); /* sectioning */
+ if (impl1 == NULL) {
+ rslt = &ignore; /* make sure code generation can continue */
+ break;
+ }
+ implproto(impl1);
+
+ impl = Impl1(n); /* plus or minus */
+ /*
+ * Allocate work area of temporary variables for sectioning.
+ */
+ lifetm_ary = alc_lftm(3, NULL);
+ lifetm_ary[0].cur_status = Tree2(n)->postn;
+ lifetm_ary[0].lifetime = n->intrnl_lftm;
+ lifetm_ary[1].cur_status = Tree3(n)->postn;
+ lifetm_ary[1].lifetime = n->intrnl_lftm;
+ lifetm_ary[2].cur_status = n->postn;
+ lifetm_ary[2].lifetime = n->intrnl_lftm;
+ tmp_indx = alc_tmp(3, lifetm_ary);
+ for (i = 0; i < 3; ++i)
+ r1[i] = tmp_loc(tmp_indx++);
+ gencode(Tree2(n), r1[0]); /* generate code to compute x */
+ gencode(Tree3(n), r1[1]); /* generate code compute i */
+
+ /*
+ * Allocate work area of temporary variables for arithmetic.
+ */
+ lifetm_ary[0].cur_status = InUse;
+ lifetm_ary[0].lifetime = Tree3(n)->lifetime;
+ lifetm_ary[1].cur_status = Tree4(n)->postn;
+ lifetm_ary[1].lifetime = Tree4(n)->lifetime;
+ tmp_indx = alc_tmp(2, lifetm_ary);
+ for (i = 0; i < 2; ++i)
+ r2[i] = tmp_loc(tmp_indx++);
+ cd_add(mk_cpyval(r2[0], r1[1])); /* generate code to copy i */
+ gencode(Tree4(n), r2[1]); /* generate code to compute j */
+
+ /*
+ * generate code for i op j.
+ */
+ setloc(n);
+ implproto(impl);
+ mk_callop(oper_name(impl), impl->ret_flag, r2[0], 2, r1[2], 0);
+
+ /*
+ * generate code for x[i : (i op j)]
+ */
+ rslt = chk_alc(rslt, n->lifetime);
+ mk_callop(oper_name(impl1),impl1->ret_flag,r1[0],3,rslt,0);
+ free((char *)lifetm_ary);
+ break;
+
+ case N_Slist:
+ bound(Tree0(n), &ignore, 1);
+ rslt = gencode(Tree1(n), rslt);
+ break;
+
+ case N_SmplAsgn: {
+ struct val_loc *var, *val;
+
+ /*
+ * Optimized assignment to a named variable. Use information
+ * from type inferencing to determine if the right-hand-side
+ * is a variable.
+ */
+ var = var_ref(LSym0(Tree2(n)));
+ if (HasVar(varsubtyp(Tree3(n)->type, &single)))
+ Val0(n) = AsgnDeref;
+ if (single != NULL) {
+ /*
+ * Right-hand-side results in a named variable. Compute
+ * the expression but don't bother saving the result, we
+ * know what it is. Assignment just copies value from
+ * one variable to the other.
+ */
+ gencode(Tree3(n), &ignore);
+ val = var_ref(single);
+ cd_add(mk_cpyval(var, val));
+ }
+ else switch (Val0(n)) {
+ case AsgnDirect:
+ /*
+ * It is safe to compute the result directly into the variable.
+ */
+ gencode(Tree3(n), var);
+ break;
+ case AsgnCopy:
+ /*
+ * The result is not a variable reference, but it is not
+ * safe to compute it into the variable, we must use a
+ * temporary variable.
+ */
+ val = gencode(Tree3(n), NULL);
+ cd_add(mk_cpyval(var, val));
+ break;
+ case AsgnDeref:
+ /*
+ * We must dereference the result into the variable.
+ */
+ val = gencode(Tree3(n), NULL);
+ deref_cd(val, var);
+ break;
+ }
+
+ /*
+ * If the assignment has to produce a result, construct the
+ * variable reference.
+ */
+ if (rslt != &ignore)
+ rslt = gencode(Tree2(n), rslt);
+ }
+ break;
+
+ case N_SmplAug: {
+ /*
+ * Optimized augmented assignment to a named variable.
+ */
+ struct val_loc *var, *val;
+
+ impl = Impl1(n); /* the operation */
+ if (impl == NULL) {
+ rslt = &ignore; /* make sure code generation can continue */
+ break;
+ }
+
+ implproto(impl); /* insure prototype for operation */
+
+ /*
+ * Generate code to compute the arguments for the operation.
+ */
+ frst_arg = gen_args(n, 2, 2);
+ setloc(n);
+
+ /*
+ * Use information from type inferencing to determine if the
+ * operation produces a variable.
+ */
+ if (HasVar(varsubtyp(Typ4(n), &single)))
+ Val0(n) = AsgnDeref;
+ var = var_ref(LSym0(Tree2(n)));
+ if (single != NULL) {
+ /*
+ * The operation results in a named variable. Call the operation
+ * but don't bother saving the result, we know what it is.
+ * Assignment just copies value from one variable to the other.
+ */
+ mk_callop(oper_name(impl), impl->ret_flag, frst_arg, 2,
+ &ignore, 0);
+ val = var_ref(single);
+ cd_add(mk_cpyval(var, val));
+ }
+ else switch (Val0(n)) {
+ case AsgnDirect:
+ /*
+ * It is safe to compute the result directly into the variable.
+ */
+ mk_callop(oper_name(impl), impl->ret_flag, frst_arg, 2,
+ var, 0);
+ break;
+ case AsgnCopy:
+ /*
+ * The result is not a variable reference, but it is not
+ * safe to compute it into the variable, we must use a
+ * temporary variable.
+ */
+ val = chk_alc(NULL, n);
+ mk_callop(oper_name(impl), impl->ret_flag, frst_arg, 2, val, 0);
+ cd_add(mk_cpyval(var, val));
+ break;
+ case AsgnDeref:
+ /*
+ * We must dereference the result into the variable.
+ */
+ val = chk_alc(NULL, n);
+ mk_callop(oper_name(impl), impl->ret_flag, frst_arg, 2, val, 0);
+ deref_cd(val, var);
+ break;
+ }
+
+ /*
+ * If the assignment has to produce a result, construct the
+ * variable reference.
+ */
+ if (rslt != &ignore)
+ rslt = gencode(Tree2(n), rslt);
+ }
+ break;
+
+ default:
+ fprintf(stderr, "compiler error: node type %d unknown\n", n->n_type);
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * Free any temporaries whose lifetime ends at this node.
+ */
+ freetmp = n->freetmp;
+ while (freetmp != NULL) {
+ switch (freetmp->kind) {
+ case DescTmp:
+ tmp_status[freetmp->indx] = freetmp->old;
+ break;
+ case CIntTmp:
+ itmp_status[freetmp->indx] = freetmp->old;
+ break;
+ case CDblTmp:
+ dtmp_status[freetmp->indx] = freetmp->old;
+ break;
+ case SBuf:
+ sbuf_status[freetmp->indx] = freetmp->old;
+ break;
+ case CBuf:
+ cbuf_status[freetmp->indx] = freetmp->old;
+ break;
+ }
+ ft = freetmp->next;
+ freetmp->next = freetmp_pool;
+ freetmp_pool = freetmp;
+ freetmp = ft;
+ }
+ return rslt;
+ }
+
+/*
+ * chk_alc - make sure a result location has been allocated. If it is
+ * a temporary variable, indicate that it is now in use.
+ */
+struct val_loc *chk_alc(rslt, lifetime)
+struct val_loc *rslt;
+nodeptr lifetime;
+ {
+ struct tmplftm tmplftm;
+
+ if (rslt == NULL) {
+ if (lifetime == NULL)
+ rslt = &ignore;
+ else {
+ tmplftm.cur_status = InUse;
+ tmplftm.lifetime = lifetime;
+ rslt = tmp_loc(alc_tmp(1, &tmplftm));
+ }
+ }
+ else if (rslt->loc_type == V_Temp)
+ tmp_status[rslt->u.tmp] = InUse;
+ return rslt;
+ }
+
+/*
+ * mk_goto - make a code structure for goto label
+ */
+struct code *mk_goto(label)
+struct code *label;
+ {
+ register struct code *cd;
+
+ cd = NewCode(1); /* # fields == # fields of C_RetSig & C_Break */
+ cd->cd_id = C_Goto;
+ cd->next = NULL;
+ cd->prev = NULL;
+ cd->Lbl = label;
+ ++label->RefCnt;
+ return cd;
+ }
+
+/*
+ * mk_cpyval - make code to copy a value from one location to another.
+ */
+static struct code *mk_cpyval(loc1, loc2)
+struct val_loc *loc1;
+struct val_loc *loc2;
+ {
+ struct code *cd;
+
+ cd = alc_ary(4);
+ cd->ElemTyp(0) = A_ValLoc;
+ cd->ValLoc(0) = loc1;
+ cd->ElemTyp(1) = A_Str;
+ cd->Str(1) = " = ";
+ cd->ElemTyp(2) = A_ValLoc;
+ cd->ValLoc(2) = loc2;
+ cd->ElemTyp(3) = A_Str;
+ cd->Str(3) = ";";
+ return cd;
+ }
+
+/*
+ * asgn_null - make code to assign the null value to a location.
+ */
+static struct code *asgn_null(loc1)
+struct val_loc *loc1;
+ {
+ struct code *cd;
+
+ cd = alc_ary(2);
+ cd->ElemTyp(0) = A_ValLoc;
+ cd->ValLoc(0) = loc1;
+ cd->ElemTyp(1) = A_Str;
+ cd->Str(1) = " = nulldesc;";
+ return cd;
+ }
+
+/*
+ * oper_name - create the name for the most general implementation of an Icon
+ * operation.
+ */
+static char *oper_name(impl)
+struct implement *impl;
+ {
+ char *sbuf;
+
+ sbuf = (char *)alloc((unsigned int)(strlen(impl->name) + 5));
+ sprintf(sbuf, "%c%c%c_%s", impl->oper_typ, impl->prefix[0], impl->prefix[1],
+ impl->name);
+ return sbuf;
+ }
+
+/*
+ * gen_args - generate code to evaluate an argument list.
+ */
+static struct val_loc *gen_args(n, frst_arg, nargs)
+struct node *n;
+int frst_arg;
+int nargs;
+ {
+ struct tmplftm *lifetm_ary;
+ int i;
+ int tmp_indx;
+
+ if (nargs == 0)
+ return NULL;
+
+ lifetm_ary = alc_lftm(nargs, &n->n_field[frst_arg]);
+ tmp_indx = alc_tmp(nargs, lifetm_ary);
+ for (i = 0; i < nargs; ++i)
+ gencode(n->n_field[frst_arg + i].n_ptr, tmp_loc(tmp_indx + i));
+ free((char *)lifetm_ary);
+ return tmp_loc(tmp_indx);
+ }
+
+/*
+ * gen_case - generate code for a case expression.
+ */
+static struct val_loc *gen_case(n, rslt)
+struct node *n;
+struct val_loc *rslt;
+ {
+ struct node *control;
+ struct node *cases;
+ struct node *deflt;
+ struct node *clause;
+ struct val_loc *r1;
+ struct val_loc *r2;
+ struct val_loc *r3;
+ struct code *cd;
+ struct code *cd1;
+ struct code *fail_sav;
+ struct code *skp_lbl;
+ struct code *cd_lbl;
+ struct code *end_lbl;
+ struct c_fnc *fnc_sav;
+ struct c_fnc *succ_cont = NULL;
+
+ control = Tree0(n);
+ cases = Tree1(n);
+ deflt = Tree2(n);
+
+ /*
+ * The control clause is bounded.
+ */
+ r1 = chk_alc(NULL, n);
+ bound(control, r1, 0);
+
+ /*
+ * Remember the context in which the case expression occurs and
+ * establish a label at the end of the expression.
+ */
+ fail_sav = on_failure;
+ fnc_sav = cur_fnc;
+ end_lbl = alc_lbl("end case", 0);
+ cd_add(end_lbl);
+ cur_fnc->cursor = end_lbl->prev; /* generate code before the end label */
+
+ /*
+ * All cases share the result location of the case expression.
+ */
+ rslt = chk_alc(rslt, n->lifetime);
+ r2 = chk_alc(NULL, n); /* for result of selection clause */
+ r3 = chk_alc(NULL, n); /* for dereferenced result of control clause */
+
+ while (cases != NULL) {
+ /*
+ * See if we are at the end of the case clause list.
+ */
+ if (cases->n_type == N_Ccls) {
+ clause = cases;
+ cases = NULL;
+ }
+ else {
+ clause = Tree1(cases);
+ cases = Tree0(cases);
+ }
+
+ /*
+ * If the evaluation of the selection code or the comparison of
+ * its value to the control clause fail, execution will proceed
+ * to the "skip clause" label and on to the next case.
+ */
+ skp_lbl = alc_lbl("skip clause", 0);
+ on_failure = skp_lbl;
+ cd_add(skp_lbl);
+ cur_fnc->cursor = skp_lbl->prev; /* generate code before end label */
+
+ /*
+ * Bound the selection code for this clause.
+ */
+ cd_lbl = alc_lbl("selected code", Bounding);
+ cd_add(cd_lbl);
+ cur_fnc->cursor = cd_lbl->prev;
+ gencode(Tree0(clause), r2);
+
+ /*
+ * Dereference the results of the control clause and the selection
+ * clause and compare them.
+ */
+ setloc(clause);
+ deref_cd(r1, r3);
+ deref_cd(r2, r2);
+ cd = NewCode(2);
+ cd->cd_id = C_If;
+ cd1 = alc_ary(5);
+ cd1->ElemTyp(0) = A_Str;
+ cd1->Str(0) = "!equiv(&";
+ cd1->ElemTyp(1) = A_ValLoc;
+ cd1->ValLoc(1) = r3;
+ cd->Cond = cd1;
+ cd1->ElemTyp(2) = A_Str;
+ cd1->Str(2) = ", &";
+ cd1->ElemTyp(3) = A_ValLoc;
+ cd1->ValLoc(3) = r2;
+ cd1->ElemTyp(4) = A_Str;
+ cd1->Str(4) = ")";
+ cd->ThenStmt = sig_cd(on_failure, cur_fnc);
+ cd_add(cd);
+ cd_add(sig_cd(cd_lbl, cur_fnc)); /* transfer control to bounding label */
+
+ /*
+ * Generate code for the body of this clause after the bounding label.
+ */
+ cur_fnc = fnc_sav;
+ cur_fnc->cursor = cd_lbl;
+ on_failure = fail_sav;
+ gencode(Tree1(clause), rslt);
+
+ /*
+ * If this clause is a generator, call the success continuation
+ * for the case expression, otherwise branch to the end of the
+ * expression.
+ */
+ if (cur_fnc->cursor->next != skp_lbl) {
+ if (succ_cont == NULL)
+ succ_cont = alc_fnc(); /* allocate a continuation function */
+ callc_add(succ_cont);
+ cur_fnc = fnc_sav;
+ }
+ else
+ cd_add(mk_goto(end_lbl));
+
+ /*
+ * The code for the next clause goes after the "skip" label of
+ * this clause.
+ */
+ cur_fnc->cursor = skp_lbl;
+ }
+
+ if (deflt == NULL)
+ cd_add(sig_cd(fail_sav, cur_fnc)); /* default action is failure */
+ else {
+ /*
+ * There is an explicit default action.
+ */
+ on_failure = fail_sav;
+ gencode(deflt, rslt);
+ if (cur_fnc->cursor->next != end_lbl) {
+ if (succ_cont == NULL)
+ succ_cont = alc_fnc();
+ callc_add(succ_cont);
+ cur_fnc = fnc_sav;
+ }
+ }
+ cur_fnc->cursor = end_lbl;
+
+ /*
+ * If some clauses are generators but others have transferred control
+ * to here, we must call the success continuation of the case
+ * expression and generate subsequent code there.
+ */
+ if (succ_cont != NULL) {
+ on_failure = fail_sav;
+ callc_add(succ_cont);
+ cur_fnc = succ_cont;
+ on_failure = &resume;
+ }
+ return rslt;
+ }
+
+/*
+ * gen_creat - generate code to create a co-expression.
+ */
+static struct val_loc *gen_creat(n, rslt)
+struct node *n;
+struct val_loc *rslt;
+ {
+ struct code *cd;
+ struct code *fail_sav;
+ struct code *fail_lbl;
+ struct c_fnc *fnc_sav;
+ struct c_fnc *fnc;
+ struct val_loc *co_rslt;
+ struct freetmp *ft;
+ char sav_prfx[PrfxSz];
+ int *tmp_sv;
+ int *itmp_sv;
+ int *dtmp_sv;
+ int *sbuf_sv;
+ int *cbuf_sv;
+ int ntmp_sv;
+ int nitmp_sv;
+ int ndtmp_sv;
+ int nsbuf_sv;
+ int ncbuf_sv;
+ int stat_sz_sv;
+ int istat_sz_sv;
+ int dstat_sz_sv;
+ int sstat_sz_sv;
+ int cstat_sz_sv;
+ int i;
+
+
+ rslt = chk_alc(rslt, n->lifetime);
+
+ fail_sav = on_failure;
+ fnc_sav = cur_fnc;
+ for (i = 0; i < PrfxSz; ++i)
+ sav_prfx[i] = frm_prfx[i];
+
+ /*
+ * Temporary variables are allocated independently for the co-expression.
+ */
+ tmp_sv = tmp_status;
+ itmp_sv = itmp_status;
+ dtmp_sv = dtmp_status;
+ sbuf_sv = sbuf_status;
+ cbuf_sv = cbuf_status;
+ stat_sz_sv = status_sz;
+ istat_sz_sv = istatus_sz;
+ dstat_sz_sv = dstatus_sz;
+ sstat_sz_sv = sstatus_sz;
+ cstat_sz_sv = cstatus_sz;
+ ntmp_sv = num_tmp;
+ nitmp_sv = num_itmp;
+ ndtmp_sv = num_dtmp;
+ nsbuf_sv = num_sbuf;
+ ncbuf_sv = num_cbuf;
+ tmp_status = (int *)alloc((unsigned int)(status_sz * sizeof(int)));
+ itmp_status = (int *)alloc((unsigned int)(istatus_sz * sizeof(int)));
+ dtmp_status = (int *)alloc((unsigned int)(dstatus_sz * sizeof(int)));
+ sbuf_status = (int *)alloc((unsigned int)(sstatus_sz * sizeof(int)));
+ cbuf_status = (int *)alloc((unsigned int)(cstatus_sz * sizeof(int)));
+ for (i = 0; i < status_sz; ++i)
+ tmp_status[i] = NotAlloc;
+ for (i = 0; i < istatus_sz; ++i)
+ itmp_status[i] = NotAlloc;
+ for (i = 0; i < dstatus_sz; ++i)
+ dtmp_status[i] = NotAlloc;
+ for (i = 0; i < sstatus_sz; ++i)
+ sbuf_status[i] = NotAlloc;
+ for (i = 0; i < cstatus_sz; ++i)
+ cbuf_status[i] = NotAlloc;
+ num_tmp = 0;
+ num_itmp = 0;
+ num_dtmp = 0;
+ num_sbuf = 0;
+ num_cbuf = 0;
+
+ /*
+ * Put code for co-expression in separate function. We will need a new
+ * type of procedure frame which contains copies of local variables,
+ * copies of arguments, and temporaries for use by the co-expression.
+ */
+ fnc = alc_fnc();
+ fnc->ref_cnt = 1;
+ fnc->flag |= CF_Coexpr;
+ ChkPrefix(fnc->prefix);
+ for (i = 0; i < PrfxSz; ++i)
+ frm_prfx[i] = fnc->frm_prfx[i] = fnc->prefix[i];
+ cur_fnc = fnc;
+
+ /*
+ * Set up a co-expression failure label followed by a context switch
+ * and a branch back to the failure label.
+ */
+ fail_lbl = alc_lbl("co_fail", 0);
+ cd_add(fail_lbl);
+ lastline = 0; /* force setting line number so tracing matches interp */
+ setloc(n);
+ cd = alc_ary(2);
+ cd->ElemTyp(0) = A_Str;
+ cd->ElemTyp(1) = A_Str;
+ cd->Str(0) = "co_chng(popact((struct b_coexpr *)BlkLoc(k_current)),";
+ cd->Str(1) = "NULL, NULL, A_Cofail, 1);";
+ cd_add(cd);
+ cd_add(mk_goto(fail_lbl));
+ cur_fnc->cursor = fail_lbl->prev; /* code goes before failure label */
+ on_failure = fail_lbl;
+
+ /*
+ * Generate code for the co-expression body, using the same
+ * dereferencing rules as for procedure return.
+ */
+ lastfiln = ""; /* force setting of file name and line number */
+ lastline = 0;
+ setloc(n);
+ ++create_lvl;
+ co_rslt = genretval(n, Tree0(n), NULL);
+ --create_lvl;
+
+ /*
+ * If the co-expression might produce a result, generate a co-expression
+ * context switch.
+ */
+ if (co_rslt != NULL) {
+ cd = alc_ary(1);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "++BlkLoc(k_current)->coexpr.size;";
+ cd_add(cd);
+ cd = alc_ary(3);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "co_chng(popact((struct b_coexpr *)BlkLoc(k_current)), &";
+ cd->ElemTyp(1) = A_ValLoc;
+ cd->ValLoc(1) = co_rslt;
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = ", NULL, A_Coret, 1);";
+ cd_add(cd);
+ cd_add(sig_cd(on_failure, cur_fnc)); /* if reactivated, resume expr */
+ }
+
+ /*
+ * Output the new frame definition.
+ */
+ prt_frame(frm_prfx, cur_proc->tnd_loc + num_tmp + Abs(cur_proc->nargs),
+ num_itmp, num_dtmp, num_sbuf, num_cbuf);
+
+ /*
+ * Now return to original function and produce code to create the
+ * co-expression.
+ */
+ cur_fnc = fnc_sav;
+ for (i = 0; i < PrfxSz; ++i)
+ frm_prfx[i] = sav_prfx[i];
+ on_failure = fail_sav;
+
+ lastfiln = ""; /* force setting of file name and line number */
+ lastline = 0;
+ setloc(n);
+ cd = NewCode(5);
+ cd->cd_id = C_Create;
+ cd->Rslt = rslt;
+ cd->Cont = fnc;
+ cd->NTemps = num_tmp;
+ cd->WrkSize = num_itmp;
+ cd->NextCreat = cur_fnc->creatlst;
+ cur_fnc->creatlst = cd;
+ cd_add(cd);
+
+ /*
+ * Restore arrays for temporary variable allocation.
+ */
+ free((char *)tmp_status);
+ free((char *)itmp_status);
+ free((char *)dtmp_status);
+ free((char *)sbuf_status);
+ free((char *)cbuf_status);
+ tmp_status = tmp_sv;
+ itmp_status = itmp_sv;
+ dtmp_status = dtmp_sv;
+ sbuf_status = sbuf_sv;
+ cbuf_status = cbuf_sv;
+ status_sz = stat_sz_sv;
+ istatus_sz = istat_sz_sv;
+ dstatus_sz = dstat_sz_sv;
+ sstatus_sz = sstat_sz_sv;
+ cstatus_sz = cstat_sz_sv;
+ num_tmp = ntmp_sv;
+ num_itmp = nitmp_sv;
+ num_dtmp = ndtmp_sv;
+ num_sbuf = nsbuf_sv;
+ num_cbuf = ncbuf_sv;
+
+ /*
+ * Temporary variables that exist to the end of the co-expression
+ * have no meaning in the surrounding code and must not be
+ * deallocated there.
+ */
+ while (n->freetmp != NULL) {
+ ft = n->freetmp->next;
+ n->freetmp->next = freetmp_pool;
+ freetmp_pool = n->freetmp;
+ n->freetmp = ft;
+ }
+
+ return rslt;
+ }
+
+/*
+ * gen_lim - generate code for limitation.
+ */
+static struct val_loc *gen_lim(n, rslt)
+struct node *n;
+struct val_loc *rslt;
+ {
+ struct node *expr;
+ struct node *limit;
+ struct val_loc *lim_desc;
+ struct code *cd;
+ struct code *cd1;
+ struct code *lbl;
+ struct code *fail_sav;
+ struct c_fnc *fnc_sav;
+ struct c_fnc *succ_cont;
+ struct val_loc *lim_int;
+ struct lentry *single;
+ int deref;
+
+ expr = Tree0(n);
+ limit = Tree1(n);
+
+ /*
+ * Generate code to compute the limitation value and dereference it.
+ */
+ deref = HasVar(varsubtyp(limit->type, &single));
+ if (single != NULL) {
+ /*
+ * Limitation is in a named variable. Use value directly from
+ * the variable rather than saving the result of the expression.
+ */
+ gencode(limit, &ignore);
+ lim_desc = var_ref(single);
+ }
+ else {
+ lim_desc = gencode(limit, NULL);
+ if (deref)
+ deref_cd(lim_desc, lim_desc);
+ }
+
+ setloc(n);
+ fail_sav = on_failure;
+
+ /*
+ * Try to convert the limitation value into an integer.
+ */
+ lim_int = itmp_loc(alc_itmp(n->intrnl_lftm));
+ cur_symtyps = n->symtyps;
+ if (largeints || (eval_is(int_typ, 0) & MaybeFalse)) {
+ /*
+ * Must call the conversion routine.
+ */
+ lbl = alc_lbl("limit is int", 0);
+ cd_add(lbl);
+ cur_fnc->cursor = lbl->prev; /* conversion goes before label */
+ cd = NewCode(2);
+ cd->cd_id = C_If;
+ cd1 = alc_ary(5);
+ cd1->ElemTyp(0) = A_Str;
+ cd1->Str(0) = "cnv_c_int(&";
+ cd1->ElemTyp(1) = A_ValLoc;
+ cd1->ValLoc(1) = lim_desc;
+ cd1->ElemTyp(2) = A_Str;
+ cd1->Str(2) = ", &";
+ cd1->ElemTyp(3) = A_ValLoc;
+ cd1->ValLoc(3) = lim_int;
+ cd1->ElemTyp(4) = A_Str;
+ cd1->Str(4) = ")";
+ cd->Cond = cd1;
+ cd->ThenStmt = mk_goto(lbl);
+ cd_add(cd);
+ cd = alc_ary(3);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "err_msg(101, &";
+ cd->ElemTyp(1) = A_ValLoc;
+ cd->ValLoc(1) = lim_desc;
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = ");";
+ cd_add(cd);
+ if (err_conv)
+ cd_add(sig_cd(on_failure, cur_fnc));
+ cur_fnc->cursor = lbl;
+ }
+ else {
+ /*
+ * The C integer is in the vword.
+ */
+ cd = alc_ary(4);
+ cd->ElemTyp(0) = A_ValLoc;
+ cd->ValLoc(0) = lim_int;
+ cd->ElemTyp(1) = A_Str;
+ cd->Str(1) = " = IntVal(";
+ cd->ElemTyp(2) = A_ValLoc;
+ cd->ValLoc(2) = lim_desc;
+ cd->ElemTyp(3) = A_Str;
+ cd->Str(3) = ");";
+ cd_add(cd);
+ }
+
+ /*
+ * Make sure the limitation value is positive.
+ */
+ lbl = alc_lbl("limit positive", 0);
+ cd_add(lbl);
+ cur_fnc->cursor = lbl->prev; /* code goes before label */
+ cd = NewCode(2);
+ cd->cd_id = C_If;
+ cd1 = alc_ary(2);
+ cd1->ElemTyp(0) = A_ValLoc;
+ cd1->ValLoc(0) = lim_int;
+ cd1->ElemTyp(1) = A_Str;
+ cd1->Str(1) = " >= 0";
+ cd->Cond = cd1;
+ cd->ThenStmt = mk_goto(lbl);
+ cd_add(cd);
+ cd = alc_ary(3);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "err_msg(205, &";
+ cd->ElemTyp(1) = A_ValLoc;
+ cd->ValLoc(1) = lim_desc;
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = ");";
+ cd_add(cd);
+ if (err_conv)
+ cd_add(sig_cd(on_failure, cur_fnc));
+ cur_fnc->cursor = lbl;
+
+ /*
+ * If the limitation value is 0, fail immediately.
+ */
+ cd = NewCode(2);
+ cd->cd_id = C_If;
+ cd1 = alc_ary(2);
+ cd1->ElemTyp(0) = A_ValLoc;
+ cd1->ValLoc(0) = lim_int;
+ cd1->ElemTyp(1) = A_Str;
+ cd1->Str(1) = " == 0";
+ cd->Cond = cd1;
+ cd->ThenStmt = sig_cd(on_failure, cur_fnc);
+ cd_add(cd);
+
+ /*
+ * Establish where to go when limit has been reached.
+ */
+ fnc_sav = cur_fnc;
+ lbl = alc_lbl("limit", 0);
+ cd_add(lbl);
+ cur_fnc->cursor = lbl->prev; /* limited expression goes before label */
+
+ /*
+ * Generate code for limited expression and to check the limit value.
+ */
+ rslt = gencode(expr, rslt);
+ cd = NewCode(2);
+ cd->cd_id = C_If;
+ cd1 = alc_ary(3);
+ cd1->ElemTyp(0) = A_Str;
+ cd1->Str(0) = "--";
+ cd1->ElemTyp(1) = A_ValLoc;
+ cd1->ValLoc(1) = lim_int;
+ cd1->ElemTyp(2) = A_Str;
+ cd1->Str(2) = " == 0";
+ cd->Cond = cd1;
+ cd->ThenStmt = sig_cd(lbl, cur_fnc);
+ cd_add(cd);
+
+ /*
+ * Call the success continuation both here and after the limitation
+ * label.
+ */
+ succ_cont = alc_fnc();
+ callc_add(succ_cont);
+ cur_fnc = fnc_sav;
+ cur_fnc->cursor = lbl;
+ on_failure = fail_sav;
+ callc_add(succ_cont);
+ cur_fnc = succ_cont;
+ on_failure = &resume;
+
+ return rslt;
+ }
+
+/*
+ * gen_apply - generate code for the apply operator, !.
+ */
+static struct val_loc *gen_apply(n, rslt)
+struct node *n;
+struct val_loc *rslt;
+ {
+ struct val_loc *callee;
+ struct val_loc *lst;
+ struct code *arg_lst;
+ struct code *on_ret;
+ struct c_fnc *fnc;
+
+ /*
+ * Generate code to compute the two operands.
+ */
+ callee = gencode(Tree0(n), NULL);
+ lst = gencode(Tree1(n), NULL);
+ rslt = chk_alc(rslt, n->lifetime);
+ setloc(n);
+
+ /*
+ * Construct argument list for apply().
+ */
+ arg_lst = alc_ary(6);
+ arg_lst->ElemTyp(0) = A_Str;
+ arg_lst->Str(0) = "&";
+ arg_lst->ElemTyp(1) = A_ValLoc;
+ arg_lst->ValLoc(1) = callee;
+ arg_lst->ElemTyp(2) = A_Str;
+ arg_lst->Str(2) = ", &";
+ arg_lst->ElemTyp(3) = A_ValLoc;
+ arg_lst->ValLoc(3) = lst;
+ arg_lst->ElemTyp(4) = A_Str;
+ arg_lst->Str(4) = ", &";
+ arg_lst->ElemTyp(5) = A_ValLoc;
+ arg_lst->ValLoc(5) = rslt;
+
+ /*
+ * Generate code to call apply(). Assume the operation can suspend and
+ * allocate a continuation. If it returns a "continue" signal,
+ * just break out of the signal handling code and fall into a call
+ * to the continuation.
+ */
+ on_ret = NewCode(1); /* #fields for C_Break == #fields for C_Goto */
+ on_ret->cd_id = C_Break;
+ on_ret->next = NULL;
+ on_ret->prev = NULL;
+ fnc = alc_fnc(); /* success continuation */
+ callo_add("apply", DoesFail | DoesRet | DoesSusp, fnc, 1, arg_lst, on_ret);
+ callc_add(fnc);
+ cur_fnc = fnc; /* subsequent code goes in the continuation */
+ on_failure = &resume;
+
+ return rslt;
+ }
+
+
+/*
+ * gen_scan - generate code for string scanning.
+ */
+static struct val_loc *gen_scan(n, rslt)
+nodeptr n;
+struct val_loc *rslt;
+ {
+ struct node *op;
+ struct node *subj;
+ struct node *body;
+ struct scan_info *scanp;
+ struct val_loc *asgn_var;
+ struct val_loc *new_subj;
+ struct val_loc *scan_rslt;
+ struct tmplftm *lifetm_ary;
+ struct lentry *subj_single;
+ struct lentry *body_single;
+ struct code *cd;
+ struct code *cd1;
+ struct code *lbl;
+ struct implement *impl;
+ int subj_deref;
+ int body_deref;
+ int op_tok;
+ int tmp_indx;
+
+ op = Tree0(n); /* operator node '?' or '?:=' */
+ subj = Tree1(n); /* subject expression */
+ body = Tree2(n); /* scanning expression */
+ op_tok = optab[Val0(op)].tok.t_type;
+
+ /*
+ * The location of the save areas for scanning environments is stored
+ * in list so they can be accessed by expressions that transfer
+ * control out of string scanning. Get the next list element and
+ * allocate the save areas in the procedure frame.
+ */
+ scanp = nxt_scan;
+ if (nxt_scan->next == NULL)
+ nxt_scan->next = NewStruct(scan_info);
+ nxt_scan = nxt_scan->next;
+ scanp->outer_sub = chk_alc(NULL, n->intrnl_lftm);
+ scanp->outer_pos = itmp_loc(alc_itmp(n->intrnl_lftm));
+ scanp->inner_sub = chk_alc(NULL, n->intrnl_lftm);
+ scanp->inner_pos = itmp_loc(alc_itmp(n->intrnl_lftm));
+
+ subj_deref = HasVar(varsubtyp(subj->type, &subj_single));
+ if (subj_single != NULL) {
+ /*
+ * The subject value is in a named variable. Use value directly from
+ * the variable rather than saving the result of the expression.
+ */
+ gencode(subj, &ignore);
+ new_subj = var_ref(subj_single);
+
+ if (op_tok == AUGQMARK) {
+ body_deref = HasVar(varsubtyp(body->type, &body_single));
+ if (body_single != NULL)
+ scan_rslt = &ignore; /* we know where the value will be */
+ else
+ scan_rslt = chk_alc(NULL, n->intrnl_lftm);
+ }
+ else
+ scan_rslt = rslt; /* result of 2nd operand is result of scanning */
+ }
+ else if (op_tok == AUGQMARK) {
+ /*
+ * Augmented string scanning using general assignment. The operands
+ * must be in consecutive locations.
+ */
+ lifetm_ary = alc_lftm(2, &n->n_field[1]);
+ tmp_indx = alc_tmp(2, lifetm_ary);
+ asgn_var = tmp_loc(tmp_indx++);
+ scan_rslt = tmp_loc(tmp_indx);
+ free((char *)lifetm_ary);
+
+ gencode(subj, asgn_var);
+ new_subj = chk_alc(NULL, n->intrnl_lftm);
+ deref_cd(asgn_var, new_subj);
+ }
+ else {
+ new_subj = gencode(subj, NULL);
+ if (subj_deref)
+ deref_cd(new_subj, new_subj);
+ scan_rslt = rslt; /* result of 2nd operand is result of scanning */
+ }
+
+ /*
+ * Produce code to save the old scanning environment.
+ */
+ setloc(op);
+ save_env(scanp->outer_sub, scanp->outer_pos);
+
+ /*
+ * Produce code to handle failure of the body of string scanning.
+ */
+ lbl = alc_lbl("scan fail", 0);
+ cd_add(lbl);
+ restr_env(scanp->outer_sub, scanp->outer_pos);
+ cd_add(sig_cd(on_failure, cur_fnc)); /* fail */
+ cur_fnc->cursor = lbl->prev; /* body goes before label */
+ on_failure = lbl;
+
+ /*
+ * If necessary, try to convert the subject to a string. Note that if
+ * error conversion occurs, backtracking will restore old subject.
+ */
+ cur_symtyps = n->symtyps;
+ if (eval_is(str_typ, 0) & MaybeFalse) {
+ lbl = alc_lbl("&subject is string", 0);
+ cd_add(lbl);
+ cur_fnc->cursor = lbl->prev; /* code goes before label */
+ cd = NewCode(2);
+ cd->cd_id = C_If;
+ cd1 = alc_ary(3);
+ cd1->ElemTyp(0) = A_Str;
+ cd1->Str(0) = "cnv_str(&";
+ cd1->ElemTyp(1) = A_ValLoc;
+ cd1->ValLoc(1) = new_subj;
+ cd1->ElemTyp(2) = A_Str;
+ cd1->Str(2) = ", &k_subject)";
+ cd->Cond = cd1;
+ cd->ThenStmt = mk_goto(lbl);
+ cd_add(cd);
+ cd = alc_ary(3);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "err_msg(103, &";
+ cd->ElemTyp(1) = A_ValLoc;
+ cd->ValLoc(1) = new_subj;
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = ");";
+ cd_add(cd);
+ if (err_conv)
+ cd_add(sig_cd(on_failure, cur_fnc));
+ cur_fnc->cursor = lbl;
+ }
+ else {
+ cd = alc_ary(3);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "k_subject = ";
+ cd->ElemTyp(1) = A_ValLoc;
+ cd->ValLoc(1) = new_subj;
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = ";";
+ cd_add(cd);
+ }
+ cd = alc_ary(1);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "k_pos = 1;";
+ cd_add(cd);
+
+ scan_rslt = gencode(body, scan_rslt);
+
+ setloc(op);
+ if (op_tok == AUGQMARK) {
+ /*
+ * '?:=' - perform assignment.
+ */
+ if (subj_single != NULL) {
+ /*
+ * Assignment to a named variable.
+ */
+ if (body_single != NULL)
+ cd_add(mk_cpyval(new_subj, var_ref(body_single)));
+ else if (body_deref)
+ deref_cd(scan_rslt, new_subj);
+ else
+ cd_add(mk_cpyval(new_subj, scan_rslt));
+ }
+ else {
+ /*
+ * Use general assignment.
+ */
+ impl = optab[asgn_loc].binary;
+ if (impl == NULL) {
+ nfatal(op, "assignment not implemented", NULL);
+ rslt = &ignore; /* make sure code generation can continue */
+ }
+ else {
+ implproto(impl);
+ rslt = chk_alc(rslt, n->lifetime);
+ mk_callop(oper_name(impl), impl->ret_flag, asgn_var, 2, rslt,0);
+ }
+ }
+ }
+ else {
+ /*
+ * '?'
+ */
+ rslt = scan_rslt;
+ }
+
+ /*
+ * Produce code restore subject and pos when the body of the
+ * scanning expression succeeds. The new subject and pos must
+ * be saved in case of resumption.
+ */
+ save_env(scanp->inner_sub, scanp->inner_pos);
+ restr_env(scanp->outer_sub, scanp->outer_pos);
+
+ /*
+ * Produce code to handle resumption of string scanning.
+ */
+ lbl = alc_lbl("scan resume", 0);
+ cd_add(lbl);
+ save_env(scanp->outer_sub, scanp->outer_pos);
+ restr_env(scanp->inner_sub, scanp->inner_pos);
+ cd_add(sig_cd(on_failure, cur_fnc)); /* fail */
+ cur_fnc->cursor = lbl->prev; /* success continuation goes before label */
+ on_failure = lbl;
+
+ nxt_scan = scanp;
+ return rslt;
+ }
+
+/*
+ * gen_act - generate code for co-expression activation.
+ */
+static struct val_loc *gen_act(n, rslt)
+nodeptr n;
+struct val_loc *rslt;
+ {
+ struct node *op;
+ struct node *transmit;
+ struct node *coexpr;
+ struct tmplftm *lifetm_ary;
+ struct val_loc *trans_loc;
+ struct val_loc *coexpr_loc;
+ struct val_loc *asgn1;
+ struct val_loc *asgn2;
+ struct val_loc *act_rslt;
+ struct lentry *c_single;
+ struct code *cd;
+ struct code *cd1;
+ struct code *lbl;
+ struct implement *impl;
+ int c_deref;
+ int op_tok;
+ int tmp_indx;
+
+ op = Tree0(n); /* operator node for '@' or '@:=' */
+ transmit = Tree1(n); /* expression for value to transmit */
+ coexpr = Tree2(n); /* expression for co-expression */
+ op_tok = optab[Val0(op)].tok.t_type;
+
+ /*
+ * Produce code for the value to be transmitted.
+ */
+ if (op_tok == AUGAT) {
+ /*
+ * Augmented activation. This is seldom used so don't try too
+ * hard to optimize it. Allocate contiguous temporaries for
+ * the operands to the assignment.
+ */
+ lifetm_ary = alc_lftm(2, &n->n_field[1]);
+ tmp_indx = alc_tmp(2, lifetm_ary);
+ asgn1 = tmp_loc(tmp_indx++);
+ asgn2 = tmp_loc(tmp_indx);
+ free((char *)lifetm_ary);
+
+ /*
+ * Generate code to produce the left-hand-side of the assignment.
+ * This is also the transmitted value. Activation may need a
+ * dereferenced value, so this must be in a different location.
+ */
+ gencode(transmit, asgn1);
+ trans_loc = chk_alc(NULL, n->intrnl_lftm);
+ setloc(op);
+ deref_ret(asgn1, trans_loc, varsubtyp(transmit->type, NULL));
+ }
+ else
+ trans_loc = genretval(op, transmit, NULL); /* ordinary activation */
+
+ /*
+ * Determine if the value to be activated needs dereferencing, and
+ * see if it can only come from a single named variable.
+ */
+ c_deref = HasVar(varsubtyp(coexpr->type, &c_single));
+ if (c_single == NULL) {
+ /*
+ * The value is something other than a single named variable.
+ */
+ coexpr_loc = gencode(coexpr, NULL);
+ if (c_deref)
+ deref_cd(coexpr_loc, coexpr_loc);
+ }
+ else {
+ /*
+ * The value is in a named variable. Use it directly from the
+ * variable rather than saving the result of the expression.
+ */
+ gencode(coexpr, &ignore);
+ coexpr_loc = var_ref(c_single);
+ }
+
+ /*
+ * Make sure the value to be activated is a co-expression. Perform
+ * run-time checking if necessary.
+ */
+ cur_symtyps = n->symtyps;
+ if (eval_is(coexp_typ, 1) & MaybeFalse) {
+ lbl = alc_lbl("is co-expression", 0);
+ cd_add(lbl);
+ cur_fnc->cursor = lbl->prev; /* code goes before label */
+ cd = NewCode(2);
+ cd->cd_id = C_If;
+ cd1 = alc_ary(3);
+ cd1->ElemTyp(0) = A_Str;
+ cd1->Str(0) = "(";
+ cd1->ElemTyp(1) = A_ValLoc;
+ cd1->ValLoc(1) = coexpr_loc;
+ cd1->ElemTyp(2) = A_Str;
+ cd1->Str(2) = ").dword == D_Coexpr";
+ cd->Cond = cd1;
+ cd->ThenStmt = mk_goto(lbl);
+ cd_add(cd);
+ cd = alc_ary(3);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "err_msg(118, &(";
+ cd->ElemTyp(1) = A_ValLoc;
+ cd->ValLoc(1) = coexpr_loc;
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = "));";
+ cd_add(cd);
+ if (err_conv)
+ cd_add(sig_cd(on_failure, cur_fnc));
+ cur_fnc->cursor = lbl;
+ }
+
+ /*
+ * Make sure a result location has been allocated. For ordinary
+ * activation, this is where activate() puts its result. For
+ * augmented activation, this is where assignment puts its result.
+ */
+ rslt = chk_alc(rslt, n->lifetime);
+ if (op_tok == AUGAT)
+ act_rslt = asgn2;
+ else
+ act_rslt = rslt;
+
+ /*
+ * Generate code to call activate().
+ */
+ setloc(n);
+ cd = NewCode(2);
+ cd->cd_id = C_If;
+ cd1 = alc_ary(7);
+ cd1->ElemTyp(0) = A_Str;
+ cd1->Str(0) = "activate(&";
+ cd1->ElemTyp(1) = A_ValLoc;
+ cd1->ValLoc(1) = trans_loc;
+ cd1->ElemTyp(2) = A_Str;
+ cd1->Str(2) = ", (struct b_coexpr *)BlkLoc(";
+ cd1->ElemTyp(3) = A_ValLoc;
+ cd1->ValLoc(3) = coexpr_loc;
+ cd1->ElemTyp(4) = A_Str;
+ cd1->Str(4) = "), &";
+ cd1->ElemTyp(5) = A_ValLoc;
+ cd1->ValLoc(5) = act_rslt;
+ cd1->ElemTyp(6) = A_Str;
+ cd1->Str(6) = ") == A_Resume";
+ cd->Cond = cd1;
+ cd->ThenStmt = sig_cd(on_failure, cur_fnc);
+ cd_add(cd);
+
+ /*
+ * For augmented activation, generate code to call assignment.
+ */
+ if (op_tok == AUGAT) {
+ impl = optab[asgn_loc].binary;
+ if (impl == NULL) {
+ nfatal(op, "assignment not implemented", NULL);
+ rslt = &ignore; /* make sure code generation can continue */
+ }
+ else {
+ implproto(impl);
+ mk_callop(oper_name(impl), impl->ret_flag, asgn1, 2, rslt, 0);
+ }
+ }
+
+ return rslt;
+ }
+
+/*
+ * save_env - generate code to save scanning environment.
+ */
+static void save_env(sub_sav, pos_sav)
+struct val_loc *sub_sav;
+struct val_loc *pos_sav;
+ {
+ struct code *cd;
+
+ cd = alc_ary(2);
+ cd->ElemTyp(0) = A_ValLoc;
+ cd->ValLoc(0) = sub_sav;
+ cd->ElemTyp(1) = A_Str;
+ cd->Str(1) = " = k_subject;";
+ cd_add(cd);
+ cd = alc_ary(2);
+ cd->ElemTyp(0) = A_ValLoc;
+ cd->ValLoc(0) = pos_sav;
+ cd->ElemTyp(1) = A_Str;
+ cd->Str(1) = " = k_pos;";
+ cd_add(cd);
+ }
+
+/*
+ * restr_env - generate code to restore scanning environment.
+ */
+static void restr_env(sub_sav, pos_sav)
+struct val_loc *sub_sav;
+struct val_loc *pos_sav;
+ {
+ struct code *cd;
+
+ cd = alc_ary(3);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "k_subject = ";
+ cd->ElemTyp(1) = A_ValLoc;
+ cd->ValLoc(1) = sub_sav;
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = ";";
+ cd_add(cd);
+ cd = alc_ary(3);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "k_pos = ";
+ cd->ElemTyp(1) = A_ValLoc;
+ cd->ValLoc(1) = pos_sav;
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = ";";
+ cd_add(cd);
+ }
+
+/*
+ * mk_callop - produce the code to directly call an operation.
+ */
+static void mk_callop(oper_nm, ret_flag, arg1rslt, nargs, rslt, optim)
+char *oper_nm;
+int ret_flag;
+struct val_loc *arg1rslt;
+int nargs;
+struct val_loc *rslt;
+int optim;
+ {
+ struct code *arg_lst;
+ struct code *on_ret;
+ struct c_fnc *fnc;
+ int n;
+ int need_cont;
+
+ /*
+ * If this operation can return an "continue" signal, we will need
+ * a break statement in the signal switch to handle it.
+ */
+ if (ret_flag & DoesRet) {
+ on_ret = NewCode(1); /* #fields == #fields C_Goto */
+ on_ret->cd_id = C_Break;
+ on_ret->next = NULL;
+ on_ret->prev = NULL;
+ }
+ else
+ on_ret = NULL;
+
+ /*
+ * Construct argument list for the C function implementing the
+ * operation. First compute the size of the code array for the
+ * argument list; this varies if we are using an optimized calling
+ * interface.
+ */
+ if (optim) {
+ n = 0;
+ if (arg1rslt != NULL)
+ n += 2;
+ if (ret_flag & (DoesRet | DoesSusp)) {
+ if (n > 0)
+ ++n;
+ n += 2;
+ }
+ }
+ else
+ n = 7;
+ if (n == 0)
+ arg_lst = NULL;
+ else {
+ arg_lst = alc_ary(n);
+ n = 0;
+ if (!optim) {
+ arg_lst->ElemTyp(n) = A_Intgr; /* number of arguments */
+ arg_lst->Intgr(n) = nargs;
+ ++n;
+ arg_lst->ElemTyp(n) = A_Str; /* , */
+ arg_lst->Str(n) = ", ";
+ ++n;
+ }
+ if (arg1rslt == NULL) { /* location of first argument */
+ if (!optim) {
+ arg_lst->ElemTyp(n) = A_Str;
+ arg_lst->Str(n) = "NULL";
+ ++n;
+ arg_lst->ElemTyp(n) = A_Str;
+ arg_lst->Str(n) = ""; /* nothing, but must fill slot */
+ ++n;
+ }
+ }
+ else {
+ arg_lst->ElemTyp(n) = A_Str;
+ arg_lst->Str(n) = "&";
+ ++n;
+ arg_lst->ElemTyp(n) = A_ValLoc;
+ arg_lst->ValLoc(n) = arg1rslt;
+ ++n;
+ }
+ if (!optim || ret_flag & (DoesRet | DoesSusp)) {
+ if (n > 0) {
+ arg_lst->ElemTyp(n) = A_Str; /* , */
+ arg_lst->Str(n) = ", ";
+ ++n;
+ }
+ arg_lst->ElemTyp(n) = A_Str; /* location of result */
+ arg_lst->Str(n) = "&";
+ ++n;
+ arg_lst->ElemTyp(n) = A_ValLoc;
+ arg_lst->ValLoc(n) = rslt;
+ }
+ }
+
+ /*
+ * Generate code to call the operation and handle returned signals.
+ */
+ if (ret_flag & DoesSusp) {
+ /*
+ * The operation suspends, so call it with a continuation, then
+ * proceed to generate code in the continuation.
+ */
+ fnc = alc_fnc();
+ callo_add(oper_nm, ret_flag, fnc, 1, arg_lst, on_ret);
+ if (ret_flag & DoesRet)
+ callc_add(fnc);
+ cur_fnc = fnc;
+ on_failure = &resume;
+ }
+ else {
+ /*
+ * No continuation is needed, but if standard calling conventions
+ * are used, a NULL continuation argument is required.
+ */
+ if (optim)
+ need_cont = 0;
+ else
+ need_cont = 1;
+ callo_add(oper_nm, ret_flag, NULL, need_cont, arg_lst, on_ret);
+ }
+}
+
+/*
+ * genretval - generate code for the expression in a return/suspend or
+ * for the expression for the value to be transmitted in a co-expression
+ * context switch.
+ */
+static struct val_loc *genretval(n, expr, dest)
+struct node *n;
+struct node *expr;
+struct val_loc *dest;
+ {
+ int subtypes;
+ struct lentry *single;
+ struct val_loc *val;
+
+ subtypes = varsubtyp(expr->type, &single);
+
+ /*
+ * If we have a single local or argument, we don't need to construct
+ * a variable reference; we need the value and we know where it is.
+ */
+ if (single != NULL && (subtypes & (HasLcl | HasPrm))) {
+ gencode(expr, &ignore);
+ val = var_ref(single);
+ if (dest == NULL)
+ dest = val;
+ else
+ cd_add(mk_cpyval(dest, val));
+ }
+ else {
+ dest = gencode(expr, dest);
+ setloc(n);
+ deref_ret(dest, dest, subtypes);
+ }
+
+ return dest;
+ }
+
+/*
+ * deref_ret - produced dereferencing code for values returned from
+ * procedures or transmitted to co-expressions.
+ */
+static void deref_ret(src, dest, subtypes)
+struct val_loc *src;
+struct val_loc *dest;
+int subtypes;
+ {
+ struct code *cd;
+ struct code *lbl;
+
+ if (src == NULL)
+ return; /* no value to dereference */
+
+ /*
+ * If there may be values that do not need dereferencing, insure that the
+ * values are in the destination and make it the source of dereferencing.
+ */
+ if ((subtypes & (HasVal | HasGlb)) && (src != dest)) {
+ cd_add(mk_cpyval(dest, src));
+ src = dest;
+ }
+
+ if (subtypes & (HasLcl | HasPrm)) {
+ /*
+ * Some values may need to be dereferenced.
+ */
+ lbl = NULL;
+ if (subtypes & HasVal) {
+ /*
+ * We may have a non-variable and must check at run time.
+ */
+ lbl = check_var(dest, NULL);
+ }
+
+ if (subtypes & HasGlb) {
+ /*
+ * Make sure we don't dereference any globals, use retderef().
+ */
+ if (subtypes & HasLcl) {
+ /*
+ * We must dereference any locals.
+ */
+ cd = alc_ary(3);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "retderef(&";
+ cd->ElemTyp(1) = A_ValLoc;
+ cd->ValLoc(1) = dest;
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) =
+ ", (word *)pfp->tend.d, (word *)(pfp->tend.d + pfp->tend.num));";
+ cd_add(cd);
+ /*
+ * We may now have a value. We must check at run-time and skip
+ * any attempt to dereference an argument.
+ */
+ lbl = check_var(dest, lbl);
+ }
+
+ if (subtypes & HasPrm) {
+ /*
+ * We must dereference any arguments.
+ */
+ cd = alc_ary(5);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "retderef(&";
+ cd->ElemTyp(1) = A_ValLoc;
+ cd->ValLoc(1) = dest;
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = ", (word *)glbl_argp, (word *)(glbl_argp + ";
+ cd->ElemTyp(3) = A_Intgr;
+ cd->Intgr(3) = Abs(cur_proc->nargs);
+ cd->ElemTyp(4) = A_Str;
+ cd->Str(4) = "));";
+ cd_add(cd);
+ }
+ }
+ else /* No globals */
+ deref_cd(src, dest);
+
+ if (lbl != NULL)
+ cur_fnc->cursor = lbl; /* continue after label */
+ }
+ }
+
+/*
+ * check_var - generate code to make sure a descriptor contains a variable
+ * reference. If no label is given to jump to for a non-variable, allocate
+ * one and generate code before it.
+ */
+static struct code *check_var(d, lbl)
+struct val_loc *d;
+struct code *lbl;
+ {
+ struct code *cd, *cd1;
+
+ if (lbl == NULL) {
+ lbl = alc_lbl("not variable", 0);
+ cd_add(lbl);
+ cur_fnc->cursor = lbl->prev; /* code goes before label */
+ }
+
+ cd = NewCode(2);
+ cd->cd_id = C_If;
+ cd1 = alc_ary(3);
+ cd1->ElemTyp(0) = A_Str;
+ cd1->Str(0) = "!Var(";
+ cd1->ElemTyp(1) = A_ValLoc;
+ cd1->ValLoc(1) = d;
+ cd1->ElemTyp(2) = A_Str;
+ cd1->Str(2) = ")";
+ cd->Cond = cd1;
+ cd->ThenStmt = mk_goto(lbl);
+ cd_add(cd);
+
+ return lbl;
+ }
+
+/*
+ * field_ref - generate code for a field reference.
+ */
+static struct val_loc *field_ref(n, rslt)
+struct node *n;
+struct val_loc *rslt;
+ {
+ struct node *rec;
+ struct node *fld;
+ struct fentry *fp;
+ struct par_rec *rp;
+ struct val_loc *rec_loc;
+ struct code *cd;
+ struct code *cd1;
+ struct code *lbl;
+ struct lentry *single;
+ int deref;
+ int num_offsets;
+ int offset;
+ int bad_recs;
+
+ rec = Tree0(n);
+ fld = Tree1(n);
+
+ /*
+ * Generate code to compute the record value and dereference it.
+ */
+ deref = HasVar(varsubtyp(rec->type, &single));
+ if (single != NULL) {
+ /*
+ * The record is in a named variable. Use value directly from
+ * the variable rather than saving the result of the expression.
+ */
+ gencode(rec, &ignore);
+ rec_loc = var_ref(single);
+ }
+ else {
+ rec_loc = gencode(rec, NULL);
+ if (deref)
+ deref_cd(rec_loc, rec_loc);
+ }
+
+ setloc(fld);
+
+ /*
+ * Make sure the operand is a record.
+ */
+ cur_symtyps = n->symtyps;
+ if (eval_is(rec_typ, 0) & MaybeFalse) {
+ lbl = alc_lbl("is record", 0);
+ cd_add(lbl);
+ cur_fnc->cursor = lbl->prev; /* code goes before label */
+ cd = NewCode(2);
+ cd->cd_id = C_If;
+ cd1 = alc_ary(3);
+ cd1->ElemTyp(0) = A_Str;
+ cd1->Str(0) = "(";
+ cd1->ElemTyp(1) = A_ValLoc;
+ cd1->ValLoc(1) = rec_loc;
+ cd1->ElemTyp(2) = A_Str;
+ cd1->Str(2) = ").dword == D_Record";
+ cd->Cond = cd1;
+ cd->ThenStmt = mk_goto(lbl);
+ cd_add(cd);
+ cd = alc_ary(3);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "err_msg(107, &";
+ cd->ElemTyp(1) = A_ValLoc;
+ cd->ValLoc(1) = rec_loc;
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = ");";
+ cd_add(cd);
+ if (err_conv)
+ cd_add(sig_cd(on_failure, cur_fnc));
+ cur_fnc->cursor = lbl;
+ }
+
+ rslt = chk_alc(rslt, n->lifetime);
+
+ /*
+ * Find the list of records containing this field.
+ */
+ if ((fp = flookup(Str0(fld))) == NULL) {
+ nfatal(n, "invalid field", Str0(fld));
+ return rslt;
+ }
+
+ /*
+ * Generate code for declarations and to get the record block pointer.
+ */
+ cd = alc_ary(1);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "{";
+ cd_add(cd);
+ cd = alc_ary(3);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "struct b_record *r_rp = (struct b_record *) BlkLoc(";
+ cd->ElemTyp(1) = A_ValLoc;
+ cd->ValLoc(1) = rec_loc;
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = ");";
+ cd_add(cd);
+ if (err_conv) {
+ cd = alc_ary(1);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "int r_must_fail = 0;";
+ cd_add(cd);
+ }
+
+ /*
+ * Determine which records are in the record type.
+ */
+ mark_recs(fp, cur_symtyps->types[0], &num_offsets, &offset, &bad_recs);
+
+ /*
+ * Generate code to insure that the field belongs to the record
+ * and to index into the record block.
+ */
+ if (num_offsets == 1 && !bad_recs) {
+ /*
+ * We already know the offset of the field.
+ */
+ cd = alc_ary(4);
+ cd->ElemTyp(0) = A_ValLoc;
+ cd->ValLoc(0) = rslt;
+ cd->ElemTyp(1) = A_Str;
+ cd->Str(1) = ".dword = D_Var + ((word *)&r_rp->fields[";
+ cd->ElemTyp(2) = A_Intgr;
+ cd->Intgr(2) = offset;
+ cd->ElemTyp(3) = A_Str;
+ cd->Str(3) = "] - (word *)r_rp);";
+ cd_add(cd);
+ cd = alc_ary(3);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "VarLoc(";
+ cd->ElemTyp(1) = A_ValLoc;
+ cd->ValLoc(1) = rslt;
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = ") = (dptr)r_rp;";
+ cd_add(cd);
+ for (rp = fp->rlist; rp != NULL; rp = rp->next)
+ rp->mark = 0;
+ }
+ else {
+ /*
+ * The field appears in several records. generate code to determine
+ * which one it is.
+ */
+
+ cd = alc_ary(1);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "dptr r_dp;";
+ cd_add(cd);
+ cd = alc_ary(1);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "switch (r_rp->recdesc->proc.recnum) {";
+ cd_add(cd);
+
+ rp = fp->rlist;
+ while (rp != NULL) {
+ offset = rp->offset;
+ while (rp != NULL && rp->offset == offset) {
+ if (rp->mark) {
+ rp->mark = 0;
+ cd = alc_ary(3);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = " case ";
+ cd->ElemTyp(1) = A_Intgr;
+ cd->Intgr(1) = rp->rec->rec_num;
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = ":";
+ cd_add(cd);
+ }
+ rp = rp->next;
+ }
+
+ cd = alc_ary(3);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = " r_dp = &r_rp->fields[";
+ cd->ElemTyp(1) = A_Intgr;
+ cd->Intgr(1) = offset;
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = "];";
+ cd_add(cd);
+ cd = alc_ary(1);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = " break;";
+ cd_add(cd);
+ }
+
+ cd = alc_ary(1);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = " default:";
+ cd_add(cd);
+ cd = alc_ary(3);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = " err_msg(207, &";
+ cd->ElemTyp(1) = A_ValLoc;
+ cd->ValLoc(1) = rec_loc;
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = ");";
+ cd_add(cd);
+ if (err_conv) {
+ /*
+ * The peephole analyzer doesn't know how to handle a goto or return
+ * in a switch statement, so just set a flag here.
+ */
+ cd = alc_ary(1);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = " r_must_fail = 1;";
+ cd_add(cd);
+ }
+ cd = alc_ary(1);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = " }";
+ cd_add(cd);
+ if (err_conv) {
+ /*
+ * Now that we are out of the switch statement, see if the flag
+ * was set to indicate error conversion.
+ */
+ cd = NewCode(2);
+ cd->cd_id = C_If;
+ cd1 = alc_ary(1);
+ cd1->ElemTyp(0) = A_Str;
+ cd1->Str(0) = "r_must_fail";
+ cd->Cond = cd1;
+ cd->ThenStmt = sig_cd(on_failure, cur_fnc);
+ cd_add(cd);
+ }
+ cd = alc_ary(2);
+ cd->ElemTyp(0) = A_ValLoc;
+ cd->ValLoc(0) = rslt;
+ cd->ElemTyp(1) = A_Str;
+ cd->Str(1) = ".dword = D_Var + ((word *)r_dp - (word *)r_rp);";
+ cd_add(cd);
+ cd = alc_ary(3);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "VarLoc(";
+ cd->ElemTyp(1) = A_ValLoc;
+ cd->ValLoc(1) = rslt;
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = ") = (dptr)r_rp;";
+ cd_add(cd);
+ }
+
+ cd = alc_ary(1);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "}";
+ cd_add(cd);
+ return rslt;
+ }
+
+/*
+ * bound - bound the code for the given sub-tree. If catch_fail is true,
+ * direct failure to the bounding label.
+ */
+static struct val_loc *bound(n, rslt, catch_fail)
+struct node *n;
+struct val_loc *rslt;
+int catch_fail;
+ {
+ struct code *lbl1;
+ struct code *fail_sav;
+ struct c_fnc *fnc_sav;
+
+ fnc_sav = cur_fnc;
+ fail_sav = on_failure;
+
+ lbl1 = alc_lbl("bound", Bounding);
+ cd_add(lbl1);
+ cur_fnc->cursor = lbl1->prev; /* code goes before label */
+ if (catch_fail)
+ on_failure = lbl1;
+
+ rslt = gencode(n, rslt);
+
+ cd_add(sig_cd(lbl1, cur_fnc)); /* transfer control to bounding label */
+ cur_fnc = fnc_sav;
+ cur_fnc->cursor = lbl1;
+
+ on_failure = fail_sav;
+ return rslt;
+ }
+
+/*
+ * cd_add - add a code struct at the cursor in the current function.
+ */
+void cd_add(cd)
+struct code *cd;
+ {
+ register struct code *cursor;
+
+ cursor = cur_fnc->cursor;
+
+ cd->next = cursor->next;
+ cd->prev = cursor;
+ if (cursor->next != NULL)
+ cursor->next->prev = cd;
+ cursor->next = cd;
+ cur_fnc->cursor = cd;
+ }
+
+/*
+ * sig_cd - convert a signal/label into a goto or return signal in
+ * the context of the given function.
+ */
+struct code *sig_cd(sig, fnc)
+struct code *sig;
+struct c_fnc *fnc;
+ {
+ struct code *cd;
+
+ if (sig->cd_id == C_Label && sig->Container == fnc)
+ return mk_goto(sig);
+ else {
+ cd = NewCode(1); /* # fields <= # fields of C_Goto */
+ cd->cd_id = C_RetSig;
+ cd->next = NULL;
+ cd->prev = NULL;
+ cd->SigRef = add_sig(sig, fnc);
+ return cd;
+ }
+ }
+
+/*
+ * add_sig - add signal to list of signals returned by function.
+ */
+struct sig_lst *add_sig(sig, fnc)
+struct code *sig;
+struct c_fnc *fnc;
+ {
+ struct sig_lst *sl;
+
+ for (sl = fnc->sig_lst; sl != NULL && sl->sig != sig; sl = sl->next)
+ ;
+ if (sl == NULL) {
+ sl = NewStruct(sig_lst);
+ sl->sig = sig;
+ sl->ref_cnt = 1;
+ sl->next = fnc->sig_lst;
+ fnc->sig_lst = sl;
+ }
+ else
+ ++sl->ref_cnt;
+ return sl;
+ }
+
+/*
+ * callc_add - add code to call a continuation. Note the action to be
+ * taken if the continuation returns resumption. The actual list
+ * signals returned and actions to take will be figured out after
+ * the continuation has been optimized.
+ */
+void callc_add(cont)
+struct c_fnc *cont;
+ {
+ struct code *cd;
+
+ cd = new_call();
+ cd->OperName = NULL;
+ cd->Cont = cont;
+ cd->ArgLst = NULL;
+ cd->ContFail = on_failure;
+ cd->SigActs = NULL;
+ ++cont->ref_cnt;
+ }
+
+/*
+ * callo_add - add code to call an operation.
+ */
+void callo_add(oper_nm, ret_flag, cont, need_cont, arglist, on_ret)
+char *oper_nm;
+int ret_flag;
+struct c_fnc *cont;
+int need_cont;
+struct code *arglist;
+struct code *on_ret;
+ {
+ struct code *cd;
+ struct code *cd1;
+
+ cd = new_call();
+ cd->OperName = oper_nm;
+ cd->Cont = cont;
+ if (need_cont)
+ cd->Flags = NeedCont;
+ cd->ArgLst = arglist;
+ cd->ContFail = NULL; /* operation handles failure from the continuation */
+ /*
+ * Decide how to handle the signals produced by the operation. (Those
+ * produced by the continuation will be examined after the continuation
+ * is optimized.)
+ */
+ cd->SigActs = NULL;
+ if (MightFail(ret_flag))
+ cd->SigActs = new_sgact(&resume, sig_cd(on_failure,cur_fnc), cd->SigActs);
+ if (ret_flag & DoesRet)
+ cd->SigActs = new_sgact(&contin, on_ret, cd->SigActs);
+ if (ret_flag & DoesFThru) {
+ cd1 = NewCode(1); /* #fields == #fields C_Goto */
+ cd1->cd_id = C_Break;
+ cd1->next = NULL;
+ cd1->prev = NULL;
+ cd->SigActs = new_sgact(&fallthru, cd1, cd->SigActs);
+ }
+ if (cont != NULL)
+ ++cont->ref_cnt; /* increment reference count */
+}
+
+/*
+ * Create a call, add it to the code for the current function, and
+ * add it to the list of calls from the current function.
+ */
+static struct code *new_call()
+ {
+ struct code *cd;
+
+ cd = NewCode(7);
+ cd->cd_id = C_CallSig;
+ cd_add(cd);
+ cd->Flags = 0;
+ cd->NextCall = cur_fnc->call_lst;
+ cur_fnc->call_lst = cd;
+ return cd;
+ }
+
+/*
+ * sig_act - create a new binding of an action to a signal.
+ */
+struct sig_act *new_sgact(sig, cd, next)
+struct code *sig;
+struct code *cd;
+struct sig_act *next;
+ {
+ struct sig_act *sa;
+
+ sa = NewStruct(sig_act);
+ sa->sig = sig;
+ sa->cd = cd;
+ sa->shar_act = NULL;
+ sa->next = next;
+ return sa;
+ }
+
+
+#ifdef OptimizeLit
+static int instr(const char *str, int chr) {
+ int i, found, go;
+
+ found = 0; go = 1;
+ for(i=0; ((str[i] != '\0') && go) ;i++) {
+ if (str[i] == chr) {
+ go = 0;
+ found = 1;
+ if ((str[i+1] != '\0') && (chr == '='))
+ if (str[i+1] == '=')
+ found = 0;
+ if ((chr == '=') && (i > 0)) {
+ if (str[i-1] == '>')
+ found = 0;
+ else if (str[i-1] == '<')
+ found = 0;
+ else if (str[i-1] == '!')
+ found = 0;
+ }
+ }
+ }
+ return found;
+}
+
+static void tbl_add(struct lit_tbl *add) {
+ struct lit_tbl *ins;
+ static struct lit_tbl *ptr = NULL;
+ int go = 1;
+
+ if (tbl == NULL) {
+ tbl = add;
+ ptr = add;
+ }
+ else {
+ ins = ptr;
+ while ((ins != NULL) && go) {
+ if (add->index != ins->index)
+ ins = ins->prev;
+ else
+ go = 0;
+ }
+ if (ins != NULL) {
+ if (ins->end == NULL)
+ ins->end = add->initial;
+ }
+ ptr->next = add;
+ add->prev = ptr;
+ ptr = add;
+ }
+}
+
+
+static void invalidate(struct val_loc *val, struct code *end, int code) {
+ struct lit_tbl *ptr, *back;
+ int index, go = 1;
+
+ if (val == NULL)
+ return;
+ if (val->loc_type == V_NamedVar) {
+ index = val->u.nvar->val.index;
+ return;
+ }
+ else if (val->loc_type == V_Temp)
+ index = val->u.tmp + cur_proc->tnd_loc;
+ else
+ return;
+ if (tbl == NULL)
+ return;
+ back = tbl;
+ while (back->next != NULL)
+ back = back->next;
+ go = 1;
+ for(ptr=back; ((ptr != NULL) && go) ; ptr=ptr->prev) {
+ if ((ptr->index == index) && (ptr->modified != NO_TOUCH)) {
+ ptr->modified = code;
+ if ((code != LIMITED_TO_INT) && (ptr->safe)) {
+ ptr->end = end;
+ ptr->safe = 0;
+ }
+ go = 0;
+ }
+ else if ((ptr->index == index) && (ptr->modified == NO_TOUCH)) {
+ if ((code != LIMITED_TO_INT) && (ptr->safe)) {
+ ptr->end = end;
+ ptr->safe = 0;
+ }
+ go = 0;
+ }
+ else if (ptr->index == index)
+ go = 0;
+ }
+}
+
+
+static int eval_code(struct code *cd, struct lit_tbl *cur) {
+ struct code *tmp;
+ struct lit_tbl *tmp_tbl;
+ int i, j;
+ char *str;
+
+ for (i=0; cd->ElemTyp(i) != A_End ;i++) {
+ switch(cd->ElemTyp(i)) {
+ case A_ValLoc:
+ if (cd->ValLoc(i)->mod_access != M_CInt)
+ break;
+ if ((cd->ValLoc(i)->u.tmp + cur_proc->tnd_loc) == cur->index) {
+ switch (cd->ValLoc(i)->loc_type) {
+ case V_Temp:
+ if (cur->csym->flag == F_StrLit) {
+#if 0
+ cd->ElemTyp(i) = A_Str;
+ str = (char *)alloc(strlen(cur->csym->image)+8);
+ sprintf(str, "\"%s\"/*Z*/", cur->csym->image);
+ cd->Str(i) = str;
+#endif
+ }
+ else if (cur->csym->flag == F_IntLit) {
+ cd->ElemTyp(i) = A_Str;
+ cd->Str(i) = cur->csym->image;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case A_Ary:
+ for(tmp=cd->Array(i); tmp != NULL ;tmp=tmp->next)
+ eval_code(tmp, cur);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void propagate_literals() {
+ struct lit_tbl *ptr;
+ struct code *cd, *arg;
+ int ret;
+
+ for(ptr=tbl; ptr != NULL ;ptr=ptr->next) {
+ if (ptr->modified != NO_TOUCH) {
+ for(cd=ptr->initial; cd != ptr->end ;cd=cd->next) {
+ switch (cd->cd_id) {
+ case C_If:
+ for(arg=cd->Cond; arg != NULL ;arg=arg->next)
+ ret = eval_code(arg, ptr);
+ /*
+ * Again, don't take the 'then' portion.
+ * It might lead to infinite loops.
+ * for(arg=cd->ThenStmt; arg != NULL ;arg=arg->next)
+ * ret = eval_code(arg, ptr);
+ */
+ break;
+ case C_CdAry:
+ ret = eval_code(cd, ptr);
+ break;
+ case C_CallSig:
+ for(arg=cd->ArgLst; arg != NULL ;arg=arg->next)
+ ret = eval_code(arg, ptr);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+}
+
+/*
+ * analyze_literals - analyzes the generated code to replace
+ * complex record dereferences with C
+ * literals.
+ */
+static void analyze_literals(struct code *start, struct code *top, int lvl) {
+ struct code *ptr, *tmp, *not_null;
+ struct lit_tbl *new_tbl;
+ struct lbl_tbl *new_lbl;
+ struct val_loc *prev = NULL;
+ int i, inc=0, addr=0, assgn=0, equal = 0;
+
+ for (ptr = start; ptr != NULL ; ptr = ptr->next) {
+ if (!lvl)
+ not_null = ptr;
+ else
+ not_null = top;
+ switch (ptr->cd_id) {
+ case C_NamedVar:
+ break;
+ case C_CallSig:
+ analyze_literals(ptr->ArgLst, not_null, lvl+1);
+ break;
+ case C_Goto:
+ break;
+ case C_Label:
+ break;
+ case C_Lit:
+ new_tbl = alc_tbl();
+ new_tbl->initial = ptr;
+ new_tbl->vloc = ptr->Rslt;
+ new_tbl->csym = ptr->Literal;
+ switch (ptr->Rslt->loc_type) {
+ case V_NamedVar:
+ new_tbl->index = ptr->Rslt->u.nvar->val.index;
+ tbl_add(new_tbl);
+ break;
+ case V_Temp:
+ new_tbl->index = ptr->Rslt->u.tmp + cur_proc->tnd_loc;
+ tbl_add(new_tbl);
+ break;
+ default:
+ new_tbl->index = -1;
+ free(new_tbl);
+ break;
+ }
+ break;
+ case C_If:
+ analyze_literals(ptr->Cond, not_null, lvl+1);
+ /*
+ * Don't analyze the 'then' portion such as in:
+ * analyze_literals(ptr->ThenStmt, not_null, lvl+1);
+ * Apparently, all the intermediate code does is maintain
+ * a pointer to where the flow of execution jumps to in
+ * case the 'then' is taken. These are all goto statments
+ * and can result in infinite loops of analyzation.
+ */
+ break;
+ case C_CdAry:
+ for(i=0; ptr->ElemTyp(i) != A_End ;i++) {
+ switch(ptr->ElemTyp(i)) {
+ case A_Str:
+ if (ptr->Str(i) != NULL) {
+ if ( (strstr(ptr->Str(i), "-=")) ||
+ (strstr(ptr->Str(i), "+=")) ||
+ (strstr(ptr->Str(i), "*=")) ||
+ (strstr(ptr->Str(i), "/=")) )
+ invalidate(prev, not_null, NO_TOUCH);
+ else if (instr(ptr->Str(i), '=')) {
+ invalidate(prev, not_null, LIMITED);
+ assgn = 1;
+ }
+ else if ( (strstr(ptr->Str(i), "++")) ||
+ (strstr(ptr->Str(i), "--")) )
+ inc = 1;
+ else if (instr(ptr->Str(i), '&'))
+ addr = 1;
+ else if (strstr(ptr->Str(i), "=="))
+ equal = 1;
+ }
+ break;
+ case A_ValLoc:
+ if (inc) {
+ invalidate(ptr->ValLoc(i), not_null, NO_TOUCH);
+ inc = 0;
+ }
+ if (addr) {
+ invalidate(ptr->ValLoc(i), not_null, LIMITED);
+ addr = 0;
+ }
+ if ((assgn) && (ptr->ValLoc(i)->mod_access == M_None)) {
+ invalidate(ptr->ValLoc(i), not_null, LIMITED);
+ assgn = 0;
+ }
+ else if (assgn)
+ assgn = 0;
+ if (equal) {
+ invalidate(ptr->ValLoc(i), not_null, LIMITED_TO_INT);
+ equal = 0;
+ }
+ prev = ptr->ValLoc(i);
+ break;
+ case A_Intgr:
+ break;
+ case A_SBuf:
+ break;
+ case A_Ary:
+ for(tmp=ptr->Array(i); tmp != NULL ;tmp=tmp->next)
+ analyze_literals(tmp, not_null, lvl+1);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+#endif /* OptimizeLit */
+
+/*
+ * analyze_poll - analyzes the internal C code representation from
+ * the position of the last Poll() function call to
+ * the current position in the code.
+ * Returns a 0 if the last Poll() function should not
+ * be removed.
+ */
+#ifdef OptimizePoll
+static int analyze_poll(void) {
+ struct code *cursor, *ptr;
+ int cont = 1;
+
+ ptr = lastpoll;
+ if (ptr == NULL)
+ return 0;
+ cursor = cur_fnc->cursor;
+ while ((cursor != ptr) && (ptr != NULL) && (cont)) {
+ switch (ptr->cd_id) {
+ case C_Null :
+ case C_NamedVar :
+ case C_Label :
+ case C_Lit :
+ case C_Resume :
+ case C_Continue :
+ case C_FallThru :
+ case C_PFail :
+ case C_Goto :
+ case C_Create :
+ case C_If :
+ case C_SrcLoc :
+ case C_CdAry :
+ break;
+ case C_CallSig :
+ case C_RetSig :
+ case C_LBrack :
+ case C_RBrack :
+ case C_PRet :
+ case C_PSusp :
+ case C_Break :
+ cont = 0;
+ break;
+ }
+ ptr = ptr->next;
+ }
+ return cont;
+}
+
+/*
+ * remove_poll - removes the ccode structure that represents the last
+ * call to the "Poll()" function by simply changing the code ID to
+ * C_Null code.
+ */
+static void remove_poll(void) {
+
+ if (lastpoll == NULL)
+ return;
+ lastpoll->cd_id = C_Null;
+}
+#endif /* OptimizePoll */
+
+/*
+ * setloc produces code to set the file name and line number to the
+ * source location of node n. Code is only produced if the corresponding
+ * value has changed since the last time setloc was called.
+ */
+static void setloc(n)
+nodeptr n;
+ {
+ struct code *cd;
+ static int count=0;
+
+ if (n == NULL || File(n) == NULL || Line(n) == 0)
+ return;
+
+ if (File(n) != lastfiln || Line(n) != lastline) {
+#ifdef OptimizePoll
+ if (analyze_poll())
+ remove_poll();
+ cd = alc_ary(1);
+ lastpoll = cd;
+#else /* OptimizePoll */
+ cd = alc_ary(1);
+#endif /* OptimizePoll */
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "Poll();";
+ cd_add(cd);
+
+ if (line_info) {
+ cd = NewCode(2);
+ cd->cd_id = C_SrcLoc;
+
+ if (File(n) == lastfiln)
+ cd->FileName = NULL;
+ else {
+ lastfiln = File(n);
+ cd->FileName = lastfiln;
+ }
+
+ if (Line(n) == lastline)
+ cd->LineNum = 0;
+ else {
+ lastline = Line(n);
+ cd->LineNum = lastline;
+ }
+
+ cd_add(cd);
+ }
+ }
+ }
+
+/*
+ * alc_ary - create an array for a sequence of code fragments.
+ */
+struct code *alc_ary(n)
+int n;
+ {
+ struct code *cd;
+ static cnt=1;
+
+ cd = NewCode(2 * n + 1);
+ cd->cd_id = C_CdAry;
+ cd->next = NULL;
+ cd->prev = NULL;
+ cd->ElemTyp(n) = A_End;
+ return cd;
+ }
+
+
+/*
+ * alc_lbl - create a label.
+ */
+struct code *alc_lbl(desc, flag)
+char *desc;
+int flag;
+ {
+ register struct code *cd;
+
+ cd = NewCode(5);
+ cd->cd_id = C_Label;
+ cd->next = NULL;
+ cd->prev = NULL;
+ cd->Container = cur_fnc; /* function containing label */
+ cd->SeqNum = 0; /* sequence number is allocated later */
+ cd->Desc = desc; /* identifying comment */
+ cd->RefCnt = 0; /* reference count */
+ cd->LabFlg = flag;
+ return cd;
+ }
+
+/*
+ * alc_fnc - allocate a function structure;
+ */
+static struct c_fnc *alc_fnc()
+ {
+ register struct c_fnc *cf;
+ int i;
+
+ cf = NewStruct(c_fnc);
+ cf->prefix[0] = '\0'; /* prefix is allocated later */
+ cf->prefix[PrfxSz] = '\0'; /* terminate prefix for printing */
+ cf->flag = 0;
+ for (i = 0; i < PrfxSz; ++i)
+ cf->frm_prfx[i] = frm_prfx[i]; /* note procedure frame prefix */
+ cf->frm_prfx[PrfxSz] = '\0'; /* terminate prefix for printing */
+ cf->cd.cd_id = C_Null; /* base of code sequence in function */
+ cf->cd.next = NULL;
+ cf->cursor = &cf->cd; /* current place to insert code */
+ cf->call_lst = NULL; /* functions called by this function */
+ cf->creatlst = NULL; /* creates within this function */
+ cf->sig_lst = NULL; /* signals returned by this function */
+ cf->ref_cnt = 0;
+ cf->next = NULL;
+ *flst_end = cf; /* link entry onto global list */
+ flst_end = &(cf->next);
+ return cf;
+ }
+
+/*
+ * tmp_loc - allocate a value location structure for nth temporary descriptor
+ * variable in procedure frame.
+ */
+static struct val_loc *tmp_loc(n)
+int n;
+ {
+ register struct val_loc *r;
+
+ r = NewStruct(val_loc);
+ r->loc_type = V_Temp;
+ r->mod_access = M_None;
+ r->u.tmp = n;
+ return r;
+ }
+
+/*
+ * itmp_loc - allocate a value location structure for nth temporary integer
+ * variable in procedure frame.
+ */
+struct val_loc *itmp_loc(n)
+int n;
+ {
+ register struct val_loc *r;
+
+ r = NewStruct(val_loc);
+ r->loc_type = V_ITemp;
+ r->mod_access = M_None;
+ r->u.tmp = n;
+ return r;
+ }
+
+/*
+ * dtmp_loc - allocate a value location structure for nth temporary double
+ * variable in procedure frame.
+ */
+struct val_loc *dtmp_loc(n)
+int n;
+ {
+ register struct val_loc *r;
+
+ r = NewStruct(val_loc);
+ r->loc_type = V_DTemp;
+ r->mod_access = M_None;
+ r->u.tmp = n;
+ return r;
+ }
+
+/*
+ * vararg_sz - allocate a value location structure that refers to the size
+ * of the variable part of an argument list.
+ */
+static struct val_loc *vararg_sz(n)
+int n;
+ {
+ register struct val_loc *r;
+
+ r = NewStruct(val_loc);
+ r->loc_type = V_Const;
+ r->mod_access = M_None;
+ r->u.int_const = n;
+ return r;
+ }
+
+/*
+ * cvar_loc - allocate a value location structure for a C variable.
+ */
+struct val_loc *cvar_loc(name)
+char *name;
+ {
+ register struct val_loc *r;
+
+ r = NewStruct(val_loc);
+ r->loc_type = V_CVar;
+ r->mod_access = M_None;
+ r->u.name = name;
+ return r;
+ }
+
+/*
+ * var_ref - allocate a value location structure for an Icon named variable.
+ */
+static struct val_loc *var_ref(sym)
+struct lentry *sym;
+ {
+ struct val_loc *loc;
+
+ loc = NewStruct(val_loc);
+ loc->loc_type = V_NamedVar;
+ loc->mod_access = M_None;
+ loc->u.nvar = sym;
+ return loc;
+ }
+
+/*
+ * deref_cd - generate code to dereference a descriptor.
+ */
+static void deref_cd(src, dest)
+struct val_loc *src;
+struct val_loc *dest;
+ {
+ struct code *cd;
+
+ cd = alc_ary(5);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "deref(&";
+ cd->ElemTyp(1) = A_ValLoc;
+ cd->ValLoc(1) = src;
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = ", &";
+ cd->ElemTyp(3) = A_ValLoc;
+ cd->ValLoc(3) = dest;
+ cd->ElemTyp(4) = A_Str;
+ cd->Str(4) = ");";
+ cd_add(cd);
+ }
+
+/*
+ * inv_op - directly invoke a run-time operation, in-lining it if possible.
+ */
+static struct val_loc *inv_op(n, rslt)
+nodeptr n;
+struct val_loc *rslt;
+ {
+ struct implement *impl;
+ struct code *scont_strt;
+ struct code *scont_fail;
+ struct c_fnc *fnc;
+ struct val_loc *frst_arg;
+ struct val_loc *arg_rslt;
+ struct val_loc *r;
+ struct val_loc **varg_rslt;
+ struct op_symentry *symtab;
+ struct lentry **single;
+ struct tmplftm *lifetm_ary;
+ nodeptr rslt_lftm;
+ char *sbuf;
+ int *maybe_var;
+ int may_mod;
+ int nsyms;
+ int nargs;
+ int nparms;
+ int cont_loc;
+ int flag;
+ int refs;
+ int var_args;
+ int n_varargs;
+ int arg_loc;
+ int dcl_var;
+ int i;
+ int j;
+ int v;
+
+ nargs = Val0(n);
+ impl = Impl1(n);
+ if (impl == NULL) {
+ /*
+ * We have already printed an error, just make sure we can
+ * continue.
+ */
+ return &ignore;
+ }
+
+ /*
+ * If this operation uses its result location as a work area, it must
+ * be given a tended result location and the value must be retained
+ * as long as the operation can be resumed.
+ */
+ rslt_lftm = n->lifetime;
+ if (impl->use_rslt) {
+ rslt_lftm = max_lftm(rslt_lftm, n->intrnl_lftm);
+ if (rslt == &ignore)
+ rslt = NULL; /* force allocation of temporary */
+ }
+
+ /*
+ * Determine if this operation takes a variable number of arguments
+ * and determine the size of the variable part of the arg list.
+ */
+ nparms = impl->nargs;
+ if (nparms > 0 && impl->arg_flgs[nparms - 1] & VarPrm) {
+ var_args = 1;
+ n_varargs = nargs - nparms + 1;
+ if (n_varargs < 0)
+ n_varargs = 0;
+ }
+ else {
+ var_args = 0;
+ n_varargs = 0;
+ }
+
+ /*
+ * Construct a symbol table (implemented as an array) for the operation.
+ * The symbol table includes parameters, and both the tended and
+ * ordinary variables from the RTL declare statement.
+ */
+ nsyms = (n->symtyps == NULL ? 0 : n->symtyps->nsyms);
+ if (var_args)
+ ++nsyms;
+ nsyms += impl->ntnds + impl->nvars;
+ if (nsyms > 0)
+ symtab = (struct op_symentry *)alloc((unsigned int)(nsyms *
+ sizeof(struct op_symentry)));
+ else
+ symtab = NULL;
+ for (i = 0; i < nsyms; ++i) {
+ symtab[i].n_refs = 0; /* number of non-modifying references */
+ symtab[i].n_mods = 0; /* number of modifying references */
+ symtab[i].n_rets = 0; /* number of times returned directly */
+ symtab[i].var_safe = 0; /* Icon variable arg can be passed directly */
+ symtab[i].adjust = 0; /* adjustments needed to "dereference" */
+ symtab[i].itmp_indx = -1; /* loc after "in-place" convert to C integer */
+ symtab[i].dtmp_indx = -1; /* loc after "in-place" convert to C double */
+ symtab[i].loc = NULL; /* location as a descriptor */
+ }
+
+ /*
+ * If in-lining has not been disabled or the operation is a keyword,
+ * check to see if it can reasonably be in-lined and gather information
+ * needed to in-line it.
+ */
+ if ((allow_inline || impl->oper_typ == 'K') &&
+ do_inlin(impl, n, &cont_loc, symtab, n_varargs)) {
+ /*
+ * In-line the operation.
+ */
+
+ if (impl->ret_flag & DoesRet || impl->ret_flag & DoesSusp)
+ rslt = chk_alc(rslt, rslt_lftm); /* operation produces a result */
+
+ /*
+ * Allocate arrays to hold information from type inferencing about
+ * whether arguments are variables. This is used to optimize
+ * dereferencing.
+ */
+ if (nargs > 0) {
+ maybe_var = (int *)alloc((unsigned int)(nargs * sizeof(int)));
+ single = (struct lentry **)alloc((unsigned int)(nargs *
+ sizeof(struct lentry *)));
+ }
+
+ if (var_args)
+ --nparms; /* don't deal with varargs parameter yet. */
+
+ /*
+ * Match arguments with parameters and generate code for the
+ * arguments. The type of code generated depends on the kinds
+ * of dereferencing optimizations that are possible, though
+ * in general, dereferencing must wait until all arguments are
+ * computed. Because there may be both dereferenced and undereferenced
+ * parameters for an argument, the symbol table index does not always
+ * match the argument index.
+ */
+ i = 0; /* symbol table index */
+ for (j = 0; j < nparms && j < nargs; ++j) {
+ /*
+ * Use information from type inferencing to determine if the
+ * argument might me a variable and whether it is a single
+ * known named variable.
+ */
+ maybe_var[j] = HasVar(varsubtyp(n->n_field[FrstArg + j].n_ptr->type,
+ &(single[j])));
+
+ /*
+ * Determine how many times the argument is referenced. If we
+ * optimize away return statements because we don't need the
+ * result, those references don't count. Take into account
+ * that there may be both dereferenced and undereferenced
+ * parameters for this argument.
+ */
+ if (rslt == &ignore)
+ symtab[i].n_refs -= symtab[i].n_rets;
+ refs = symtab[i].n_refs + symtab[i].n_mods;
+ flag = impl->arg_flgs[j] & (RtParm | DrfPrm);
+ if (flag == (RtParm | DrfPrm))
+ refs += symtab[i + 1].n_refs + symtab[i + 1].n_mods;
+ if (refs == 0) {
+ /*
+ * Indicate that we don't need the argument value (we must
+ * still perform the computation in case it has side effects).
+ */
+ arg_rslt = &ignore;
+ symtab[i].adjust = AdjNone;
+ }
+ else {
+ /*
+ * Decide whether the result location for the argument can be
+ * used directly as the parameter.
+ */
+ if (flag == (RtParm | DrfPrm) && symtab[i].n_refs +
+ symtab[i].n_mods == 0) {
+ /*
+ * We have both dereferenced and undereferenced parameters,
+ * but don't use the undereferenced one so ignore it.
+ */
+ symtab[i].adjust = AdjNone;
+ ++i;
+ flag = DrfPrm;
+ }
+ if (flag == DrfPrm && single[j] != NULL) {
+ /*
+ * We need only a dereferenced value, but know what variable
+ * it is in. We don't need the computed argument value, we will
+ * get it directly from the variable. If it is safe to do
+ * so, we will pass a pointer to the variable as the argument
+ * to the operation.
+ */
+ arg_rslt = &ignore;
+ symtab[i].loc = var_ref(single[j]);
+ if (symtab[i].var_safe)
+ symtab[i].adjust = AdjNone;
+ else
+ symtab[i].adjust = AdjCpy;
+ }
+ else {
+ /*
+ * Determine if the argument descriptor is modified by the
+ * operation; dereferencing a variable is a modification.
+ */
+ may_mod = (symtab[i].n_mods != 0);
+ if (flag == DrfPrm)
+ may_mod |= maybe_var[j];
+ if (n->n_field[FrstArg + j].n_ptr->reuse && may_mod) {
+ /*
+ * The parameter may be reused without recomputing
+ * the argument and the value may be modified. The
+ * argument result location and the parameter location
+ * must be separate so the parameter is reloaded upon
+ * each invocation.
+ */
+ arg_rslt = chk_alc(NULL,
+ n->n_field[FrstArg + j].n_ptr->lifetime);
+ if (flag == DrfPrm && maybe_var[j])
+ symtab[i].adjust = AdjNDrf; /* var: must dereference */
+ else
+ symtab[i].adjust = AdjCpy; /* value only: just copy */
+ }
+ else {
+ /*
+ * Argument result location will act as parameter location.
+ * Its lifetime must be as long as both that of the
+ * the argument and the parameter (operation internal
+ * lifetime).
+ */
+ arg_rslt = chk_alc(NULL, max_lftm(n->intrnl_lftm,
+ n->n_field[FrstArg + j].n_ptr->lifetime));
+ if (flag == DrfPrm && maybe_var[j])
+ symtab[i].adjust = AdjDrf; /* var: must dereference */
+ else
+ symtab[i].adjust = AdjNone;
+ }
+ symtab[i].loc = arg_rslt;
+ }
+ }
+
+ /*
+ * Generate the code for the argument.
+ */
+ gencode(n->n_field[FrstArg + j].n_ptr, arg_rslt);
+
+ if (flag == (RtParm | DrfPrm)) {
+ /*
+ * We have computed the value for the undereferenced parameter,
+ * decide how to get the dereferenced value.
+ */
+ ++i;
+ if (symtab[i].n_refs + symtab[i].n_mods == 0)
+ symtab[i].adjust = AdjNone; /* not needed, ignore */
+ else {
+ if (single[j] != NULL) {
+ /*
+ * The value is in a specific Icon variable, get it from
+ * there. If is is safe to pass the variable directly
+ * to the operation, do so.
+ */
+ symtab[i].loc = var_ref(single[j]);
+ if (symtab[i].var_safe)
+ symtab[i].adjust = AdjNone;
+ else
+ symtab[i].adjust = AdjCpy;
+ }
+ else {
+ /*
+ * If there might be a variable reference, note that it
+ * must be dereferenced. Otherwise decide whether the
+ * argument location can be used for both the dereferenced
+ * and undereferenced parameter.
+ */
+ symtab[i].loc = arg_rslt;
+ if (maybe_var[j])
+ symtab[i].adjust = AdjNDrf;
+ else if (symtab[i - 1].n_mods + symtab[i].n_mods == 0)
+ symtab[i].adjust = AdjNone;
+ else
+ symtab[i].adjust = AdjCpy;
+ }
+ }
+ }
+ ++i;
+ }
+
+ /*
+ * Fill out parameter list with null values.
+ */
+ while (j < nparms) {
+ int k, kn;
+ kn = 0;
+ if (impl->arg_flgs[j] & RtParm)
+ ++kn;
+ if (impl->arg_flgs[j] & DrfPrm)
+ ++kn;
+ for (k = 0; k < kn; ++k) {
+ if (symtab[i].n_refs + symtab[i].n_mods > 0) {
+ arg_rslt = chk_alc(NULL, n->intrnl_lftm);
+ cd_add(asgn_null(arg_rslt));
+ symtab[i].loc = arg_rslt;
+ }
+ symtab[i].adjust = AdjNone;
+ ++i;
+ }
+ ++j;
+ }
+
+ if (var_args) {
+ /*
+ * Compute variable part of argument list.
+ */
+ ++nparms; /* add varargs parameter back into parameter list */
+
+ /*
+ * The variable part of the parameter list must be in contiguous
+ * descriptors. Create location and lifetime arrays for use in
+ * allocating the descriptors.
+ */
+ if (n_varargs > 0) {
+ varg_rslt = (struct val_loc **)alloc((unsigned int)(n_varargs *
+ sizeof(struct val_loc *)));
+ lifetm_ary = alc_lftm(n_varargs, NULL);
+ }
+
+ flag = impl->arg_flgs[j] & (RtParm | DrfPrm);
+
+ /*
+ * Compute the lifetime of the elements of the varargs parameter array.
+ */
+ for (v = 0; v < n_varargs; ++v) {
+ /*
+ * Use information from type inferencing to determine if the
+ * argument might me a variable and whether it is a single
+ * known named variable.
+ */
+ maybe_var[j + v] = HasVar(varsubtyp(
+ n->n_field[FrstArg+j+v].n_ptr->type, &(single[j + v])));
+
+ /*
+ * Determine if the elements of the vararg parameter array
+ * might be modified. If it is a variable, dereferencing
+ * modifies it.
+ */
+ may_mod = (symtab[j].n_mods != 0);
+ if (flag == DrfPrm)
+ may_mod |= maybe_var[j + v];
+
+ if ((flag == DrfPrm && single[j + v] != NULL) ||
+ (n->n_field[FrstArg + j + v].n_ptr->reuse && may_mod)) {
+ /*
+ * The argument value is only placed in the vararg parameter
+ * array during "dereferencing". So the lifetime of the array
+ * element is the lifetime of the parameter and the element
+ * is not used until dereferencing.
+ */
+ lifetm_ary[v].lifetime = n->intrnl_lftm;
+ lifetm_ary[v].cur_status = n->postn;
+ }
+ else {
+ /*
+ * The argument is computed into the vararg parameter array.
+ * The lifetime of the array element encompasses both
+ * the lifetime of the argument and the parameter. The
+ * element is used as soon as the argument is computed.
+ */
+ lifetm_ary[v].lifetime = max_lftm(n->intrnl_lftm,
+ n->n_field[FrstArg+j+v].n_ptr->lifetime);
+ lifetm_ary[v].cur_status = n->n_field[FrstArg+j+v].n_ptr->postn;
+ }
+ }
+
+ /*
+ * Allocate (reserve) the array of temporary variables for the
+ * vararg list.
+ */
+ if (n_varargs > 0) {
+ arg_loc = alc_tmp(n_varargs, lifetm_ary);
+ free((char *)lifetm_ary);
+ }
+
+ /*
+ * Generate code to compute arguments.
+ */
+ for (v = 0; v < n_varargs; ++v) {
+ may_mod = (symtab[j].n_mods != 0);
+ if (flag == DrfPrm)
+ may_mod |= maybe_var[j + v];
+ if (flag == DrfPrm && single[j + v] != NULL) {
+ /*
+ * We need a dereferenced value and it is in a known place: a
+ * named variable; don't bother saving the result of the
+ * argument computation.
+ */
+ r = &ignore;
+ }
+ else if (n->n_field[FrstArg + j + v].n_ptr->reuse && may_mod) {
+ /*
+ * The argument can be reused without being recomputed and
+ * the parameter may be modified, so we cannot safely
+ * compute the argument into the vararg parameter array; we
+ * must compute it elsewhere and copy (dereference) it at the
+ * beginning of the operation. Let gencode allocate an argument
+ * result location.
+ */
+ r = NULL;
+ }
+ else {
+ /*
+ * We can compute the argument directly into the vararg
+ * parameter array.
+ */
+ r = tmp_loc(arg_loc + v);
+ }
+ varg_rslt[v] = gencode(n->n_field[FrstArg + j + v].n_ptr, r);
+ }
+
+ setloc(n);
+ /*
+ * Dereference or copy argument values that are not already in vararg
+ * parameter list. Preceding arguments are dereferenced later, but
+ * it is okay if dereferencing is out-of-order.
+ */
+ for (v = 0; v < n_varargs; ++v) {
+ if (flag == DrfPrm && single[j + v] != NULL) {
+ /*
+ * Copy the value from the known named variable into the
+ * parameter list.
+ */
+ varg_rslt[v] = var_ref(single[j + v]);
+ cd_add(mk_cpyval(tmp_loc(arg_loc + v), varg_rslt[v]));
+ }
+ else if (flag == DrfPrm && maybe_var[j + v]) {
+ /*
+ * Dereference the argument into the parameter list.
+ */
+ deref_cd(varg_rslt[v], tmp_loc(arg_loc + v));
+ }
+ else if (arg_loc + v != varg_rslt[v]->u.tmp) {
+ /*
+ * The argument is a dereferenced value, but is not yet
+ * in the parameter list; copy it there.
+ */
+ cd_add(mk_cpyval(tmp_loc(arg_loc + v), varg_rslt[v]));
+ }
+ tmp_status[arg_loc + v] = InUse; /* parameter location in use */
+ }
+
+ /*
+ * The vararg parameter gets the address of the first element
+ * in the variable part of the argument list and the size
+ * parameter gets the number of elements in the list.
+ */
+ if (n_varargs > 0) {
+ free((char *)varg_rslt);
+ symtab[i].loc = tmp_loc(arg_loc);
+ }
+ else
+ symtab[i].loc = chk_alc(NULL, n); /* dummy arg location */
+ symtab[i].loc->mod_access = M_Addr;
+ ++i;
+ symtab[i].loc = vararg_sz(n_varargs);
+ ++i;
+ }
+ else {
+ /*
+ * Compute extra arguments, but discard the results.
+ */
+ while (j < nargs) {
+ gencode(n->n_field[FrstArg + j].n_ptr, &ignore);
+ ++j;
+ }
+ }
+
+ if (nargs > 0) {
+ free((char *)maybe_var);
+ free((char *)single);
+ }
+
+ /*
+ * If execution does not continue through the parameter evaluation,
+ * don't try to generate in-line code. A lack of parameter types
+ * will cause problems with some in-line type conversions.
+ */
+ if (!past_prms(n))
+ return rslt;
+
+ setloc(n);
+
+ dcl_var = i;
+
+ /*
+ * Perform any needed copying or dereferencing.
+ */
+ for (i = 0; i < nsyms; ++i) {
+ switch (symtab[i].adjust) {
+ case AdjNDrf:
+ /*
+ * Dereference into a new temporary which is used as the
+ * parameter.
+ */
+ arg_rslt = chk_alc(NULL, n->intrnl_lftm);
+ deref_cd(symtab[i].loc, arg_rslt);
+ symtab[i].loc = arg_rslt;
+ break;
+ case AdjDrf:
+ /*
+ * Dereference in place.
+ */
+ deref_cd(symtab[i].loc, symtab[i].loc);
+ break;
+ case AdjCpy:
+ /*
+ * Copy into a new temporary which is used as the
+ * parameter.
+ */
+ arg_rslt = chk_alc(NULL, n->intrnl_lftm);
+ cd_add(mk_cpyval(arg_rslt, symtab[i].loc));
+ symtab[i].loc = arg_rslt;
+ break;
+ case AdjNone:
+ break; /* nothing need be done */
+ }
+ }
+
+ switch (cont_loc) {
+ case SepFnc:
+ /*
+ * success continuation must be in a separate function.
+ */
+ fnc = alc_fnc();
+ sbuf = (char *)alloc((unsigned int)(strlen(impl->name) + 5));
+ sprintf(sbuf, "end %s", impl->name);
+ scont_strt = alc_lbl(sbuf, 0);
+ cd_add(scont_strt);
+ cur_fnc->cursor = scont_strt->prev; /* put oper before label */
+ gen_inlin(impl->in_line, rslt, &scont_strt, NULL, fnc, impl,
+ nsyms, symtab, n, dcl_var, n_varargs);
+ cur_fnc->cursor = scont_strt;
+ callc_add(fnc);
+ cur_fnc = fnc;
+ on_failure = &resume;
+ break;
+ case SContIL:
+ /*
+ * one suspend an no return: success continuation is put in-line.
+ */
+ gen_inlin(impl->in_line, rslt, &scont_strt, &scont_fail, NULL, impl,
+ nsyms, symtab, n, dcl_var, n_varargs);
+ cur_fnc->cursor = scont_strt;
+ on_failure = scont_fail;
+ break;
+ case EndOper:
+ /*
+ * no suspends: success continuation goes at end of operation.
+ */
+
+ sbuf = (char *)alloc((unsigned int)(strlen(impl->name) + 5));
+ sprintf(sbuf, "end %s", impl->name);
+ scont_strt = alc_lbl(sbuf, 0);
+ cd_add(scont_strt);
+ cur_fnc->cursor = scont_strt->prev; /* put operation before lbl */
+ gen_inlin(impl->in_line, rslt, &scont_strt, NULL, NULL, impl,
+ nsyms, symtab, n, dcl_var, n_varargs);
+ cur_fnc->cursor = scont_strt;
+ break;
+ }
+ }
+ else {
+ /*
+ * Do not in-line operation.
+ */
+ implproto(impl);
+ frst_arg = gen_args(n, 2, nargs);
+ setloc(n);
+ if (impl->ret_flag & (DoesRet | DoesSusp))
+ rslt = chk_alc(rslt, rslt_lftm);
+ mk_callop(oper_name(impl), impl->ret_flag, frst_arg, nargs, rslt,
+ 0);
+ }
+ if (symtab != NULL)
+ free((char *)symtab);
+ return rslt;
+ }
+
+/*
+ * max_lftm - given two lifetimes (in the form of nodes) return the
+ * maximum one.
+ */
+static nodeptr max_lftm(n1, n2)
+nodeptr n1;
+nodeptr n2;
+ {
+ if (n1 == NULL)
+ return n2;
+ else if (n2 == NULL)
+ return n1;
+ else if (n1->postn > n2->postn)
+ return n1;
+ else
+ return n2;
+ }
+
+/*
+ * inv_prc - directly invoke a procedure.
+ */
+static struct val_loc *inv_prc(n, rslt)
+nodeptr n;
+struct val_loc *rslt;
+ {
+ struct pentry *proc;
+ struct val_loc *r;
+ struct val_loc *arg1rslt;
+ struct val_loc *var_part;
+ int *must_deref;
+ struct lentry **single;
+ struct val_loc **arg_rslt;
+ struct code *cd;
+ struct tmplftm *lifetm_ary;
+ char *sbuf;
+ int nargs;
+ int nparms;
+ int i, j;
+ int arg_loc;
+ int var_sz;
+ int var_loc;
+
+ /*
+ * This procedure is implemented without argument list adjustment or
+ * dereferencing, so they must be done before the call.
+ */
+ nargs = Val0(n); /* number of arguments */
+ proc = Proc1(n);
+ nparms = Abs(proc->nargs);
+
+ if (nparms > 0) {
+ must_deref = (int *)alloc((unsigned int)(nparms * sizeof(int)));
+ single = (struct lentry **)alloc((unsigned int)(nparms *
+ sizeof(struct lentry *)));
+ arg_rslt = (struct val_loc **)alloc((unsigned int)(nparms *
+ sizeof(struct val_loc *)));
+ }
+
+ /*
+ * Allocate a work area of temporaries to use as argument list. If
+ * an argument can be reused without being recomputed, it must not
+ * be computed directly into the work area. It will be copied or
+ * dereferenced into the work area when execution reaches the
+ * operation. If an argument is a single named variable, it can
+ * be dereferenced directly into the argument location. These
+ * conditions affect when the temporary will receive a value.
+ */
+ if (nparms > 0)
+ lifetm_ary = alc_lftm(nparms, NULL);
+ for (i = 0; i < nparms; ++i)
+ lifetm_ary[i].lifetime = n->intrnl_lftm;
+ for (i = 0; i < nparms && i < nargs; ++i) {
+ must_deref[i] = HasVar(varsubtyp(n->n_field[FrstArg + i].n_ptr->type,
+ &(single[i])));
+ if (single[i] != NULL || n->n_field[FrstArg + i].n_ptr->reuse)
+ lifetm_ary[i].cur_status = n->postn;
+ else
+ lifetm_ary[i].cur_status = n->n_field[FrstArg + i].n_ptr->postn;
+ }
+ while (i < nparms) {
+ lifetm_ary[i].cur_status = n->postn; /* arg list extension */
+ ++i;
+ }
+ if (proc->nargs < 0)
+ lifetm_ary[nparms - 1].cur_status = n->postn; /* variable part */
+
+ if (nparms > 0) {
+ arg_loc = alc_tmp(nparms, lifetm_ary);
+ free((char *)lifetm_ary);
+ }
+ if (proc->nargs < 0)
+ --nparms; /* treat variable part specially */
+ for (i = 0; i < nparms && i < nargs; ++i) {
+ if (single[i] != NULL)
+ r = &ignore; /* we know where the dereferenced value is */
+ else if (n->n_field[FrstArg + i].n_ptr->reuse)
+ r = NULL; /* let gencode allocate a new temporary */
+ else
+ r = tmp_loc(arg_loc + i);
+ arg_rslt[i] = gencode(n->n_field[FrstArg + i].n_ptr, r);
+ }
+
+ /*
+ * If necessary, fill out argument list with nulls.
+ */
+ while (i < nparms) {
+ cd_add(asgn_null(tmp_loc(arg_loc + i)));
+ tmp_status[arg_loc + i] = InUse;
+ ++i;
+ }
+
+ if (proc->nargs < 0) {
+ /*
+ * handle variable part of list.
+ */
+ var_sz = nargs - nparms;
+
+ if (var_sz > 0) {
+ lifetm_ary = alc_lftm(var_sz, &n->n_field[FrstArg + nparms]);
+ var_loc = alc_tmp(var_sz, lifetm_ary);
+ free((char *)lifetm_ary);
+ for (j = 0; j < var_sz; ++j) {
+ gencode(n->n_field[FrstArg + nparms + j].n_ptr,
+ tmp_loc(var_loc + j));
+ }
+ }
+ }
+ else {
+ /*
+ * If there are extra arguments, compute them, but discard the
+ * results.
+ */
+ while (i < nargs) {
+ gencode(n->n_field[FrstArg + i].n_ptr, &ignore);
+ ++i;
+ }
+ }
+
+ setloc(n);
+ /*
+ * Dereference or copy argument values that are not already in argument
+ * list as dereferenced values.
+ */
+ for (i = 0; i < nparms && i < nargs; ++i) {
+ if (must_deref[i]) {
+ if (single[i] == NULL) {
+ deref_cd(arg_rslt[i], tmp_loc(arg_loc + i));
+ }
+ else {
+ arg_rslt[i] = var_ref(single[i]);
+ cd_add(mk_cpyval(tmp_loc(arg_loc + i), arg_rslt[i]));
+ }
+ }
+ else if (n->n_field[FrstArg + i].n_ptr->reuse)
+ cd_add(mk_cpyval(tmp_loc(arg_loc + i), arg_rslt[i]));
+ tmp_status[arg_loc + i] = InUse;
+ }
+
+ if (proc->nargs < 0) {
+ var_part = tmp_loc(arg_loc + nparms);
+ tmp_status[arg_loc + nparms] = InUse;
+ if (var_sz <= 0) {
+ cd = alc_ary(3);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "varargs(NULL, 0, &";
+ cd->ElemTyp(1) = A_ValLoc;
+ cd->ValLoc(1) = var_part;
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = ");";
+ }
+ else {
+ cd = alc_ary(7);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "varargs(&";
+ cd->ElemTyp(1) = A_ValLoc;
+ cd->ValLoc(1) = tmp_loc(var_loc);
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = ", ";
+ cd->ElemTyp(3) = A_Intgr;
+ cd->Intgr(3) = var_sz;
+ cd->ElemTyp(4) = A_Str;
+ cd->Str(4) = ", &";
+ cd->ElemTyp(5) = A_ValLoc;
+ cd->ValLoc(5) = var_part;
+ cd->ElemTyp(6) = A_Str;
+ cd->Str(6) = ");";
+ }
+ cd_add(cd);
+ ++nparms; /* include variable part in call */
+ }
+
+ if (nparms > 0) {
+ free((char *)must_deref);
+ free((char *)single);
+ free((char *)arg_rslt);
+ }
+
+ sbuf = (char *)alloc((unsigned int)(strlen(proc->name) + PrfxSz + 3));
+ sprintf(sbuf, "P%s_%s", proc->prefix, proc->name);
+ if (nparms > 0)
+ arg1rslt = tmp_loc(arg_loc);
+ else
+ arg1rslt = NULL;
+ if (proc->ret_flag & (DoesRet | DoesSusp))
+ rslt = chk_alc(rslt, n->lifetime);
+ mk_callop(sbuf, proc->ret_flag, arg1rslt, nargs, rslt, 1);
+ return rslt;
+ }
+
+/*
+ * endlife - link a temporary variable onto the list to be freed when
+ * execution reaches a node.
+ */
+static void endlife(kind, indx, old, n)
+int kind;
+int indx;
+int old;
+nodeptr n;
+ {
+ struct freetmp *freetmp;
+
+ if ((freetmp = freetmp_pool) == NULL)
+ freetmp = NewStruct(freetmp);
+ else
+ freetmp_pool = freetmp_pool->next;
+ freetmp->kind = kind;
+ freetmp->indx = indx;
+ freetmp->old = old;
+ freetmp->next = n->freetmp;
+ n->freetmp = freetmp;
+ }
+
+/*
+ * alc_tmp - allocate a block of temporary variables with the given lifetimes.
+ */
+static int alc_tmp(num, lifetm_ary)
+int num;
+struct tmplftm *lifetm_ary;
+ {
+ int i, j, k;
+ register int status;
+ int *new_status;
+ int new_size;
+
+ i = 0;
+ for (;;) {
+ if (i + num > status_sz) {
+ /*
+ * The status array is too small, expand it.
+ */
+ new_size = status_sz + Max(num, status_sz);
+ new_status = (int *)alloc((unsigned int)(new_size * sizeof(int)));
+ k = 0;
+ while (k < status_sz) {
+ new_status[k] = tmp_status[k];
+ ++k;
+ }
+ while (k < new_size) {
+ new_status[k] = NotAlloc;
+ ++k;
+ }
+ free((char *)tmp_status);
+ tmp_status = new_status;
+ status_sz = new_size;
+ }
+ for (j = 0; j < num; ++j) {
+ status = tmp_status[i + j];
+ if (status != NotAlloc &&
+ (status == InUse || status <= lifetm_ary[j].lifetime->postn))
+ break;
+ }
+ /*
+ * Did we find a block of temporaries that we can use?
+ */
+ if (j == num) {
+ while (--j >= 0) {
+ endlife(DescTmp, i + j, tmp_status[i + j], lifetm_ary[j].lifetime);
+ tmp_status[i + j] = lifetm_ary[j].cur_status;
+ }
+ if (i + num > num_tmp)
+ num_tmp = i + num;
+ return i;
+ }
+ ++i;
+ }
+ }
+
+/*
+ * alc_lftm - allocate an array of lifetime information for an argument
+ * list.
+ */
+static struct tmplftm *alc_lftm(num, args)
+int num;
+union field *args;
+ {
+ struct tmplftm *lifetm_ary;
+ int i;
+
+ lifetm_ary = (struct tmplftm *)alloc((unsigned int)(num *
+ sizeof(struct tmplftm)));
+ if (args != NULL)
+ for (i = 0; i < num; ++i) {
+ lifetm_ary[i].cur_status = args[i].n_ptr->postn; /* reserved for arg */
+ lifetm_ary[i].lifetime = args[i].n_ptr->lifetime;
+ }
+ return lifetm_ary;
+ }
+
+/*
+ * alc_itmp - allocate a temporary C integer variable.
+ */
+int alc_itmp(lifetime)
+nodeptr lifetime;
+ {
+ int i, j;
+ int new_size;
+
+ i = 0;
+ while (i < istatus_sz && itmp_status[i] == InUse)
+ ++i;
+ if (i >= istatus_sz) {
+ /*
+ * The status array is too small, expand it.
+ */
+ free((char *)itmp_status);
+ new_size = istatus_sz * 2;
+ itmp_status = (int *)alloc((unsigned int)(new_size * sizeof(int)));
+ j = 0;
+ while (j < istatus_sz)
+ itmp_status[j++] = InUse;
+ while (j < new_size)
+ itmp_status[j++] = NotAlloc;
+ istatus_sz = new_size;
+ }
+ endlife(CIntTmp, i, NotAlloc, lifetime);
+ itmp_status[i] = InUse;
+ if (num_itmp < i + 1)
+ num_itmp = i + 1;
+ return i;
+ }
+
+/*
+ * alc_dtmp - allocate a temporary C integer variable.
+ */
+int alc_dtmp(lifetime)
+nodeptr lifetime;
+ {
+ int i, j;
+ int new_size;
+
+ i = 0;
+ while (i < dstatus_sz && dtmp_status[i] == InUse)
+ ++i;
+ if (i >= dstatus_sz) {
+ /*
+ * The status array is too small, expand it.
+ */
+ free((char *)dtmp_status);
+ new_size = dstatus_sz * 2;
+ dtmp_status = (int *)alloc((unsigned int)(new_size * sizeof(int)));
+ j = 0;
+ while (j < dstatus_sz)
+ dtmp_status[j++] = InUse;
+ while (j < new_size)
+ dtmp_status[j++] = NotAlloc;
+ dstatus_sz = new_size;
+ }
+ endlife(CDblTmp, i, NotAlloc, lifetime);
+ dtmp_status[i] = InUse;
+ if (num_dtmp < i + 1)
+ num_dtmp = i + 1;
+ return i;
+ }
+
+/*
+ * alc_sbufs - allocate a block of string buffers with the given lifetime.
+ */
+int alc_sbufs(num, lifetime)
+int num;
+nodeptr lifetime;
+ {
+ int i, j, k;
+ int *new_status;
+ int new_size;
+
+ i = 0;
+ for (;;) {
+ if (i + num > sstatus_sz) {
+ /*
+ * The status array is too small, expand it.
+ */
+ new_size = sstatus_sz + Max(num, sstatus_sz);
+ new_status = (int *)alloc((unsigned int)(new_size * sizeof(int)));
+ k = 0;
+ while (k < sstatus_sz) {
+ new_status[k] = sbuf_status[k];
+ ++k;
+ }
+ while (k < new_size) {
+ new_status[k] = NotAlloc;
+ ++k;
+ }
+ free((char *)sbuf_status);
+ sbuf_status = new_status;
+ sstatus_sz = new_size;
+ }
+ for (j = 0; j < num && sbuf_status[i + j] == NotAlloc; ++j)
+ ;
+ /*
+ * Did we find a block of buffers that we can use?
+ */
+ if (j == num) {
+ while (--j >= 0) {
+ endlife(SBuf, i + j, sbuf_status[i + j], lifetime);
+ sbuf_status[i + j] = InUse;
+ }
+ if (i + num > num_sbuf)
+ num_sbuf = i + num;
+ return i;
+ }
+ ++i;
+ }
+ }
+
+/*
+ * alc_cbufs - allocate a block of cset buffers with the given lifetime.
+ */
+int alc_cbufs(num, lifetime)
+int num;
+nodeptr lifetime;
+ {
+ int i, j, k;
+ int *new_status;
+ int new_size;
+
+ i = 0;
+ for (;;) {
+ if (i + num > cstatus_sz) {
+ /*
+ * The status array is too small, expand it.
+ */
+ new_size = cstatus_sz + Max(num, cstatus_sz);
+ new_status = (int *)alloc((unsigned int)(new_size * sizeof(int)));
+ k = 0;
+ while (k < cstatus_sz) {
+ new_status[k] = cbuf_status[k];
+ ++k;
+ }
+ while (k < new_size) {
+ new_status[k] = NotAlloc;
+ ++k;
+ }
+ free((char *)cbuf_status);
+ cbuf_status = new_status;
+ cstatus_sz = new_size;
+ }
+ for (j = 0; j < num && cbuf_status[i + j] == NotAlloc; ++j)
+ ;
+ /*
+ * Did we find a block of buffers that we can use?
+ */
+ if (j == num) {
+ while (--j >= 0) {
+ endlife(CBuf, i + j, cbuf_status[i + j], lifetime);
+ cbuf_status[i + j] = InUse;
+ }
+ if (i + num > num_cbuf)
+ num_cbuf = i + num;
+ return i;
+ }
+ ++i;
+ }
+ }
diff --git a/src/iconc/ccode.h b/src/iconc/ccode.h
new file mode 100644
index 0000000..2d0cb6f
--- /dev/null
+++ b/src/iconc/ccode.h
@@ -0,0 +1,252 @@
+/*
+ * ccode.h - definitions used in code generation.
+ */
+
+/*
+ * ChkPrefix - allocate a prefix to x if it has not already been done.
+ */
+#define ChkPrefix(x) if ((x)[0] == '\0') nxt_pre(x, pre, PrfxSz);
+
+/*
+ * sig_act - list of possible signals returned by a call and the action to be
+ * to be taken when the signal is returned: in effect a switch statement.
+ */
+struct sig_act {
+ struct code *sig; /* signal */
+ struct code *cd; /* action to be taken: goto, return, break */
+ struct sig_act *shar_act; /* signals that share this action */
+ struct sig_act *next;
+ };
+
+/*
+ * val_loc - location of a value. Used for intermediate and final results
+ * of expressions.
+ */
+#define V_NamedVar 1 /* Icon named variable indicated by nvar */
+#define V_Temp 2 /* temporary variable indicated by tmp */
+#define V_ITemp 3 /* C integer temporary variable indicated by tmp */
+#define V_DTemp 4 /* C double temporary variable indicated by tmp */
+#define V_PRslt 5 /* procedure result location */
+#define V_Const 6 /* integer constant - used for size of varargs */
+#define V_CVar 7 /* C named variable */
+#define V_Ignore 8 /* "trashcan" - a write-only location */
+
+#define M_None 0 /* access simply as descriptor */
+#define M_CharPtr 1 /* access v-word as "char *" */
+#define M_BlkPtr 2 /* access v-word as block pointer using blk_name */
+#define M_CInt 3 /* access v-word as C integer */
+#define M_Addr 4 /* address of descriptor for varargs */
+
+struct val_loc {
+ int loc_type; /* manifest constants V_* */
+ int mod_access; /* manifest constants M_* */
+ char *blk_name; /* used with M_BlkPtr */
+ union {
+ struct lentry *nvar; /* Icon named variable */
+ int tmp; /* index of temporary variable */
+ int int_const; /* integer constant value */
+ char *name; /* C named variable */
+ } u;
+ };
+
+/*
+ * "code" contains the information needed to print a piece of C code.
+ * C_... manifest constants are cd_id's. These are followed by
+ * corresponding field access expressions.
+ */
+#define Rslt fld[0].vloc /* place to put result of expression */
+#define Cont fld[1].fnc /* continuation function or null */
+
+#define C_Null 0 /* no code */
+
+#define C_NamedVar 1 /* reference to a named variable */
+/* uses Rslt */
+#define NamedVar fld[1].nvar
+
+#define C_CallSig 2 /* call and handling of returned signal */
+#define OperName fld[0].oper_nm /* run-time routine name or null */
+/* uses Cont */
+#define Flags fld[2].n /* flag: NeedCont, ForeignSig */
+#define ArgLst fld[3].cd /* argument list */
+#define ContFail fld[4].cd /* label/signal to goto/return on failure */
+#define SigActs fld[5].sa /* actions to take for returned signals */
+#define NextCall fld[6].cd /* for chaining calls within a continuation*/
+#define NeedCont 1 /* pass NULL continuation if Cont == NULL */
+#define ForeignSig 2 /* may get foreign signal from a suspend */
+
+#define C_RetSig 3 /* return signal */
+#define SigRef fld[0].sigref /* pointer to func's reference to signal */
+
+#define C_Goto 4 /* goto label */
+#define Lbl fld[0].cd /* label */
+
+#define C_Label 5 /* statment label "Ln:" and signal "n" */
+#define Container fld[0].fnc /* continuation containing label */
+#define SeqNum fld[1].n /* sequence number, n */
+#define Desc fld[2].s /* description of how label/signal is used */
+#define RefCnt fld[3].n /* reference count for label */
+#define LabFlg fld[4].n /* flag: FncPtrd, BndSig */
+#define FncPrtd 1 /* function sig_n has been printed */
+#define Bounding 2 /* this is a bounding label */
+
+#define C_Lit 6 /* literal (integer, real, string, cset) */
+/* uses Rslt */
+#define Literal fld[1].lit
+
+#define C_Resume 7 /* resume signal */
+#define C_Continue 8 /* continue signal */
+#define C_FallThru 9 /* fall through signal */
+#define C_PFail 10 /* procedure failure */
+#define C_PRet 11 /* procedure return (result already set) */
+#define C_PSusp 12 /* procedure suspend */
+#define C_Break 13 /* break out of signal handling switch */
+#define C_LBrack 14 /* '{' */
+#define C_RBrack 15 /* '}' */
+
+#define C_Create 16 /* call of create() for create expression */
+/* uses Rslt */
+/* uses Cont */
+#define NTemps fld[2].n /* number of temporary descriptors needed */
+#define WrkSize fld[3].n /* size of non-descriptor work area */
+#define NextCreat fld[4].cd /* for chaining creates in a continuation */
+
+
+#define C_If 17 /* conditional (goto or return) */
+#define Cond fld[0].cd /* condition */
+#define ThenStmt fld[1].cd /* what to do if condition is true */
+
+#define C_SrcLoc 18
+#define FileName fld[0].s /* name of source file */
+#define LineNum fld[1].n /* line number within source file */
+
+#define C_CdAry 19 /* array of code pieces, each with type code*/
+#define A_Str 0 /* code represented as a string */
+#define A_ValLoc 1 /* value location */
+#define A_Intgr 2 /* integer */
+#define A_ProcCont 3 /* procedure continuation */
+#define A_SBuf 4 /* string buffer (integer index) */
+#define A_CBuf 5 /* cset buffer (integer index) */
+#define A_Ary 6 /* pointer to subarray of code pieces */
+#define A_End 7 /* marker for end of array */
+#define ElemTyp(i) fld[2*i].n /* type of element i (A_* codes) */
+#define Str(i) fld[2*i+1].s /* string in element i */
+#define ValLoc(i) fld[2*i+1].vloc /* value location in element i */
+#define Intgr(i) fld[2*i+1].n /* integer in element i */
+#define Array(i) fld[2*i+1].cd /* pointer to subarray in element i */
+
+/*
+ * union cd_fld - fields within a code struct.
+ */
+union cd_fld {
+ int n; /* various integer values */
+ char *s; /* various string values */
+ struct lentry *nvar; /* symbol table entry for a named variable */
+ struct code *cd; /* various pointers to other pieces of code */
+ struct c_fnc *fnc; /* pointer to function information */
+ struct centry *lit; /* symbol table entry for a literal */
+ struct sig_act *sa; /* actions to take for a returned signal */
+ struct sig_lst *sigref; /* pointer to func's reference to signal */
+ struct val_loc *vloc; /* value location */
+ char *oper_nm; /* name of run-time operation or NULL */
+ };
+
+/*
+ * code - struct used to hold the internal representation of generated code.
+ */
+struct code {
+ int cd_id; /* kind of code: C_* */
+ struct code *next; /* next code fragment in list */
+ struct code *prev; /* previous code fragment in list */
+ union cd_fld fld[1]; /* fields of code fragment, actual number varies */
+ };
+
+/*
+ * NewCode - allocate a code structure with "size" fields.
+ */
+#define NewCode(size) (struct code *)alloc((unsigned int)\
+ (sizeof(struct code) + (size-1) * sizeof(union cd_fld)))
+
+/*
+ * c_fnc contains information about a C function that implements a continuation.
+ */
+#define CF_SigOnly 1 /* this function only returns a signal */
+#define CF_ForeignSig 2 /* may return foreign signal from a suspend */
+#define CF_Mark 4 /* this function has been visited by fix_fncs() */
+#define CF_Coexpr 8 /* this function implements a co-expression */
+struct c_fnc {
+ char prefix[PrfxSz+1]; /* function prefix */
+ char frm_prfx[PrfxSz+1]; /* procedure frame prefix */
+ int flag; /* CF_* flags */
+ struct code cd; /* start of code sequence */
+ struct code *cursor; /* place to insert more code into sequence */
+ struct code *call_lst; /* functions called by this function */
+ struct code *creatlst; /* list of creates in this function */
+ struct sig_lst *sig_lst; /* signals returned by this function */
+ int ref_cnt; /* reference count for this function */
+ struct c_fnc *next;
+ };
+
+
+/*
+ * sig_lst - a list of signals returned by a continuation along with a count
+ * of the number of places each signal is returned.
+ */
+struct sig_lst {
+ struct code *sig; /* signal */
+ int ref_cnt; /* number of places returned */
+ struct sig_lst *next;
+ };
+
+/*
+ * op_symentry - entry in symbol table for an operation
+ */
+#define AdjNone 1 /* no adjustment to this argument */
+#define AdjDrf 2 /* deref in place */
+#define AdjNDrf 3 /* deref into a new temporary */
+#define AdjCpy 4 /* copy into a new temporary */
+struct op_symentry {
+ int n_refs; /* number of non-modifying references */
+ int n_mods; /* number of modifying referenced */
+ int n_rets; /* number of times directly returned from operation */
+ int var_safe; /* if arg is named var, it may be used directly */
+ int adjust; /* AdjNone, AdjInplc, or AdjToNew */
+ int itmp_indx; /* index of temporary C integer variable */
+ int dtmp_indx; /* index of temporary C double variable */
+ struct val_loc *loc;
+ };
+
+extern int num_tmp; /* number of temporary descriptor variables */
+extern int num_itmp; /* number of temporary C integer variables */
+extern int num_dtmp; /* number of temporary C double variables */
+extern int num_sbuf; /* number of string buffers */
+extern int num_cbuf; /* number of cset buffers */
+
+extern struct code *bound_sig; /* bounding signal for current procedure */
+
+/*
+ * statically declared "signals".
+ */
+extern struct code resume;
+extern struct code contin;
+extern struct code fallthru;
+extern struct code next_fail;
+
+extern struct val_loc ignore; /* no values, just something to point at */
+extern struct c_fnc *cur_fnc; /* C function currently being built */
+extern struct code *on_failure; /* place to go on failure */
+
+extern int lbl_seq_num; /* next label sequence number */
+
+extern char pre[PrfxSz]; /* next unused prefix */
+
+extern struct op_symentry *cur_symtab; /* current operation symbol table */
+
+#define SepFnc 1 /* success continuation goes in separate function */
+#define SContIL 2 /* in line success continuation */
+#define EndOper 3 /* success continuation goes at end of operation */
+
+#define HasVal 1 /* type contains values */
+#define HasLcl 2 /* type contains local variables */
+#define HasPrm 4 /* type contains parameters */
+#define HasGlb 8 /* type contains globals (including statics and elements) */
+#define HasVar(x) ((x) & (HasLcl | HasPrm | HasGlb))
diff --git a/src/iconc/ccomp.c b/src/iconc/ccomp.c
new file mode 100644
index 0000000..5b86189
--- /dev/null
+++ b/src/iconc/ccomp.c
@@ -0,0 +1,130 @@
+/*
+ * ccomp.c - routines for compiling and linking the C program produced
+ * by the translator.
+ */
+#include "../h/gsupport.h"
+#include "cglobals.h"
+#include "ctrans.h"
+#include "ctree.h"
+#include "ccode.h"
+#include "csym.h"
+#include "cproto.h"
+
+extern char *refpath;
+
+#define ExeFlag "-o"
+#define LinkLibs " -lm"
+
+/*
+ * Structure to hold the list of Icon run-time libraries that must be
+ * linked in.
+ */
+struct lib {
+ char *libname;
+ int nm_sz;
+ struct lib *next;
+ };
+static struct lib *liblst;
+static int lib_sz = 0;
+
+/*
+ * addlib - add a new library to the list the must be linked.
+ */
+void addlib(libname)
+char *libname;
+ {
+ static struct lib **nxtlib = &liblst;
+ struct lib *l;
+
+ l = NewStruct(lib);
+ l->libname = libname;
+ l->nm_sz = strlen(libname);
+ l->next = NULL;
+ *nxtlib = l;
+ nxtlib = &l->next;
+ lib_sz += l->nm_sz + 1;
+ }
+
+/*
+ * ccomp - perform C compilation and linking.
+ */
+int ccomp(srcname, exename)
+char *srcname;
+char *exename;
+ {
+ struct lib *l;
+ char sbuf[MaxPath]; /* file name construction buffer */
+ char *buf;
+ char *s;
+ char *dlrgint;
+ int cmd_sz, opt_sz, flg_sz, exe_sz, src_sz;
+
+ /*
+ * Compute the sizes of the various parts of the command line
+ * to do the compilation.
+ */
+ cmd_sz = strlen(c_comp);
+ opt_sz = strlen(c_opts);
+ flg_sz = strlen(ExeFlag);
+ exe_sz = strlen(exename);
+ src_sz = strlen(srcname);
+ lib_sz += strlen(LinkLibs);
+ if (!largeints) {
+ dlrgint = makename(sbuf, refpath, "dlrgint", ObjSuffix);
+ lib_sz += strlen(dlrgint) + 1;
+ }
+
+#ifdef Graphics
+ lib_sz += strlen(" -L") +
+ strlen(refpath) +
+ strlen(" -lIgpx ");
+ lib_sz += strlen(ICONC_XLIB);
+#endif /* Graphics */
+
+ buf = alloc((unsigned int)cmd_sz + opt_sz + flg_sz + exe_sz + src_sz +
+ lib_sz + 5);
+ strcpy(buf, c_comp);
+ s = buf + cmd_sz;
+ *s++ = ' ';
+ strcpy(s, c_opts);
+ s += opt_sz;
+ *s++ = ' ';
+ strcpy(s, ExeFlag);
+ s += flg_sz;
+ *s++ = ' ';
+ strcpy(s, exename);
+ s += exe_sz;
+ *s++ = ' ';
+ strcpy(s, srcname);
+ s += src_sz;
+ if (!largeints) {
+ *s++ = ' ';
+ strcpy(s, dlrgint);
+ s += strlen(dlrgint);
+ }
+ for (l = liblst; l != NULL; l = l->next) {
+ *s++ = ' ';
+ strcpy(s, l->libname);
+ s += l->nm_sz;
+ }
+
+#ifdef Graphics
+ strcpy(s," -L");
+ strcat(s, refpath);
+ strcat(s," -lIgpx ");
+ strcat(s, ICONC_XLIB);
+ s += strlen(s);
+#endif /* Graphics */
+
+ strcpy(s, LinkLibs);
+
+ if (system(buf) != 0)
+ return EXIT_FAILURE;
+ strcpy(buf, "strip ");
+ s = buf + 6;
+ strcpy(s, exename);
+ system(buf);
+
+
+ return EXIT_SUCCESS;
+ }
diff --git a/src/iconc/cglobals.h b/src/iconc/cglobals.h
new file mode 100644
index 0000000..301a602
--- /dev/null
+++ b/src/iconc/cglobals.h
@@ -0,0 +1,50 @@
+/*
+ * Global variables.
+ */
+
+extern char *runtime;
+
+#ifndef Global
+#define Global extern
+#define Init(v)
+#endif /* Global */
+
+/*
+ * Variables related to command processing.
+ */
+Global char *progname Init("iconc"); /* program name for diagnostics */
+
+Global int debug_info Init(0); /* -fd, -t: generate debugging info */
+Global int err_conv Init(0); /* -fe: support error conversion */
+
+#ifdef LargeInts
+ Global int largeints Init(1); /* -fl: support large integers */
+#else /* LargeInts */
+ Global int largeints Init(0); /* -fl: support large integers */
+#endif /* LargeInts */
+
+Global int line_info Init(0); /* -fn, -fd, -t: generate line info */
+Global int m4pre Init(0); /* -m: use m4 preprocessor? */
+Global int str_inv Init(0); /* -fs: enable full string invocation */
+Global int trace Init(0); /* -t: initial &trace value */
+Global int uwarn Init(0); /* -u: warn about undefined ids? */
+Global int just_type_trace Init(0); /* -T: suppress C code */
+Global int verbose Init(1); /* -s, -v: level of verbosity */
+Global int pponly Init(0); /* -E: preprocess only */
+
+Global char *c_comp Init(CComp); /* -C: C compiler */
+Global char *c_opts Init(COpts); /* -p: options for C compiler */
+
+/*
+ * Flags turned off by the -n option.
+ */
+Global int opt_cntrl Init(1); /* do control flow optimization */
+Global int opt_sgnl Init(1); /* do signal handling optimizations */
+Global int do_typinfer Init(1); /* do type inference */
+Global int allow_inline Init(1); /* allow expanding operations in line */
+
+/*
+ * Files.
+ */
+Global FILE *codefile Init(0); /* C code output - primary file */
+Global FILE *inclfile Init(0); /* C code output - include file */
diff --git a/src/iconc/cgrammar.c b/src/iconc/cgrammar.c
new file mode 100644
index 0000000..a48e621
--- /dev/null
+++ b/src/iconc/cgrammar.c
@@ -0,0 +1,221 @@
+/*
+ * cgrammar.c - includes and macros for building the parse tree.
+ */
+#include "../h/define.h"
+#include "../common/yacctok.h"
+
+%{
+/*
+ * These commented directives are passed through the first application
+ * of cpp, then turned into real directives in cgram.g by fixgram.icn.
+ */
+/*#include "../h/gsupport.h"*/
+/*#include "../h/lexdef.h"*/
+/*#include "ctrans.h"*/
+/*#include "csym.h"*/
+/*#include "ctree.h"*/
+/*#include "ccode.h" */
+/*#include "cproto.h"*/
+/*#undef YYSTYPE*/
+/*#define YYSTYPE nodeptr*/
+/*#define YYMAXDEPTH 500*/
+
+int idflag;
+
+#define EmptyNode tree1(N_Empty)
+
+#define Alt(x1,x2,x3) $$ = tree4(N_Alt,x2,x1,x3)
+#define Apply(x1,x2,x3) $$ = tree4(N_Apply,x2,x1,x3)
+#define Arglist1() /* empty */
+#define Arglist2(x) /* empty */
+#define Arglist3(x1,x2,x3) proc_lst->nargs = -proc_lst->nargs
+#define Bact(x1,x2,x3) $$ = tree5(N_Activat,x2,x2,x1,x3)
+#define Bamper(x1,x2,x3) $$ = binary_nd(x2,x1,x3)
+#define Bassgn(x1,x2,x3) $$ = binary_nd(x2,x1,x3)
+#define Baugact(x1,x2,x3) $$ = tree5(N_Activat,x2,x2,x1,x3)
+#define Baugamper(x1,x2,x3) $$ = aug_nd(x2,x1,x3)
+#define Baugcat(x1,x2,x3) $$ = aug_nd(x2,x1,x3)
+#define Baugeq(x1,x2,x3) $$ = aug_nd(x2,x1,x3)
+#define Baugeqv(x1,x2,x3) $$ = aug_nd(x2,x1,x3)
+#define Baugge(x1,x2,x3) $$ = aug_nd(x2,x1,x3)
+#define Bauggt(x1,x2,x3) $$ = aug_nd(x2,x1,x3)
+#define Bauglcat(x1,x2,x3) $$ = aug_nd(x2,x1,x3)
+#define Baugle(x1,x2,x3) $$ = aug_nd(x2,x1,x3)
+#define Bauglt(x1,x2,x3) $$ = aug_nd(x2,x1,x3)
+#define Baugne(x1,x2,x3) $$ = aug_nd(x2,x1,x3)
+#define Baugneqv(x1,x2,x3) $$ = aug_nd(x2,x1,x3)
+#define Baugques(x1,x2,x3) $$ = tree5(N_Scan,x2,x2,x1,x3)
+#define Baugseq(x1,x2,x3) $$ = aug_nd(x2,x1,x3)
+#define Baugsge(x1,x2,x3) $$ = aug_nd(x2,x1,x3)
+#define Baugsgt(x1,x2,x3) $$ = aug_nd(x2,x1,x3)
+#define Baugsle(x1,x2,x3) $$ = aug_nd(x2,x1,x3)
+#define Baugslt(x1,x2,x3) $$ = aug_nd(x2,x1,x3)
+#define Baugsne(x1,x2,x3) $$ = aug_nd(x2,x1,x3)
+#define Bcaret(x1,x2,x3) $$ = binary_nd(x2,x1,x3)
+#define Bcareta(x1,x2,x3) $$ = aug_nd(x2,x1,x3)
+#define Bcat(x1,x2,x3) $$ = binary_nd(x2,x1,x3)
+#define Bdiff(x1,x2,x3) $$ = binary_nd(x2,x1,x3)
+#define Bdiffa(x1,x2,x3) $$ = aug_nd(x2,x1,x3)
+#define Beq(x1,x2,x3) $$ = binary_nd(x2,x1,x3)
+#define Beqv(x1,x2,x3) $$ = binary_nd(x2,x1,x3)
+#define Bge(x1,x2,x3) $$ = binary_nd(x2,x1,x3)
+#define Bgt(x1,x2,x3) $$ = binary_nd(x2,x1,x3)
+#define Binter(x1,x2,x3) $$ = binary_nd(x2,x1,x3)
+#define Bintera(x1,x2,x3) $$ = aug_nd(x2,x1,x3)
+#define Blcat(x1,x2,x3) $$ = binary_nd(x2,x1,x3)
+#define Ble(x1,x2,x3) $$ = binary_nd(x2,x1,x3)
+#define Blim(x1,x2,x3) $$ = tree4(N_Limit,x2,x1,x3)
+#define Blt(x1,x2,x3) $$ = binary_nd(x2,x1,x3)
+#define Bminus(x1,x2,x3) $$ = binary_nd(x2,x1,x3)
+#define Bminusa(x1,x2,x3) $$ = aug_nd(x2,x1,x3)
+#define Bmod(x1,x2,x3) $$ = binary_nd(x2,x1,x3)
+#define Bmoda(x1,x2,x3) $$ = aug_nd(x2,x1,x3)
+#define Bne(x1,x2,x3) $$ = binary_nd(x2,x1,x3)
+#define Bneqv(x1,x2,x3) $$ = binary_nd(x2,x1,x3)
+#define Bplus(x1,x2,x3) $$ = binary_nd(x2,x1,x3)
+#define Bplusa(x1,x2,x3) $$ = aug_nd(x2,x1,x3)
+#define Bques(x1,x2,x3) $$ = tree5(N_Scan,x2,x2,x1,x3)
+#define Brace(x1,x2,x3) $$ = x2
+#define Brack(x1,x2,x3) $$ = list_nd(x1,x2)
+#define Brassgn(x1,x2,x3) $$ = binary_nd(x2,x1,x3)
+#define Break(x1,x2) $$ = tree3(N_Break,x1,x2)
+#define Brswap(x1,x2,x3) $$ = binary_nd(x2,x1,x3)
+#define Bseq(x1,x2,x3) $$ = binary_nd(x2,x1,x3)
+#define Bsge(x1,x2,x3) $$ = binary_nd(x2,x1,x3)
+#define Bsgt(x1,x2,x3) $$ = binary_nd(x2,x1,x3)
+#define Bslash(x1,x2,x3) $$ = binary_nd(x2,x1,x3)
+#define Bslasha(x1,x2,x3) $$ = aug_nd(x2,x1,x3)
+#define Bsle(x1,x2,x3) $$ = binary_nd(x2,x1,x3)
+#define Bslt(x1,x2,x3) $$ = binary_nd(x2,x1,x3)
+#define Bsne(x1,x2,x3) $$ = binary_nd(x2,x1,x3)
+#define Bstar(x1,x2,x3) $$ = binary_nd(x2,x1,x3)
+#define Bstara(x1,x2,x3) $$ = aug_nd(x2,x1,x3)
+#define Bswap(x1,x2,x3) $$ = binary_nd(x2,x1,x3)
+#define Bunion(x1,x2,x3) $$ = binary_nd(x2,x1,x3)
+#define Buniona(x1,x2,x3) $$ = aug_nd(x2,x1,x3)
+#define Case(x1,x2,x3,x4,x5,x6) $$ = case_nd(x1,x2,x5)
+#define Caselist(x1,x2,x3) $$ = tree4(N_Clist,x2,x1,x3)
+#define Cclause0(x1,x2,x3) $$ = tree4(N_Ccls,x2,x1,x3)
+#define Cclause1(x1,x2,x3) $$ = tree4(N_Ccls,x2,x1,x3)
+#define Cliter(x) CSym0(x) = putlit(Str0(x),F_CsetLit,(int)Val1(x))
+#define Colon(x) $$ = x
+#define Compound(x1,x2,x3) $$ = tree4(N_Slist,x2,x1,x3)
+#define Create(x1,x2) $$ = tree3(N_Create,x1,x2);\
+ proc_lst->has_coexpr = 1;
+#define Elst0(x) $$ = x;
+#define Elst1(x1,x2,x3) $$ = tree4(N_Elist,x2,x1,x3);
+#define Every0(x1,x2) $$ = tree5(N_Loop,x1,x1,x2,EmptyNode)
+#define Every1(x1,x2,x3,x4) $$ = tree5(N_Loop,x1,x1,x2,x4)
+#define Fail(x) $$ = tree4(N_Ret,x,x,EmptyNode)
+#define Field(x1,x2,x3) $$ = tree4(N_Field,x2,x1,x3)
+#define Global0(x) idflag = F_Global
+#define Global1(x1,x2,x3) /* empty */
+#define Globdcl(x) /* empty */
+#define Ident(x) install(Str0(x),idflag)
+#define Idlist(x1,x2,x3) install(Str0(x3),idflag)
+#define If0(x1,x2,x3,x4) $$ = tree5(N_If,x1,x2,x4,EmptyNode)
+#define If1(x1,x2,x3,x4,x5,x6) $$ = tree5(N_If,x1,x2,x4,x6)
+#define Iliter(x) CSym0(x) = putlit(Str0(x),F_IntLit,0)
+#define Initial1() $$ = EmptyNode
+#define Initial2(x1,x2,x3) $$ = x2
+#define Invocdcl(x) /* empty */
+#define Invocable(x1,x2) /* empty */
+#define Invoclist(x1,x2, x3) /* empty */
+#define Invocop1(x) invoc_grp(Str0(x));
+#define Invocop2(x) invocbl(x, -1);
+#define Invocop3(x1,x2,x3) invocbl(x1, atoi(Str0(x3)));
+#define Invoke(x1,x2,x3,x4) $$ = invk_nd(x2,x1,x3)
+#define Keyword(x1,x2) $$ = key_leaf(x1,Str0(x2))
+#define Kfail(x1,x2) $$ = key_leaf(x1,spec_str("fail"))
+#define Link(x1,x2) /* empty */
+#define Linkdcl(x) /* empty */
+#define Lnkfile1(x) lnkdcl(Str0(x));
+#define Lnkfile2(x) lnkdcl(Str0(x));
+#define Lnklist(x1,x2,x3) /* empty */
+#define Local(x) idflag = F_Dynamic
+#define Locals1() /* empty */
+#define Locals2(x1,x2,x3,x4) /* empty */
+#define Mcolon(x) $$ = x
+#define Nexpr() $$ = EmptyNode
+#define Next(x) $$ = tree2(N_Next,x)
+#define Paren(x1,x2,x3) if ((x2)->n_type == N_Elist)\
+ $$ = invk_nd(x1,EmptyNode,x2);\
+ else\
+ $$ = x2
+#define Pcolon(x) $$ = x
+#define Pdco0(x1,x2,x3) $$ = invk_nd(x2,x1,list_nd(x2,EmptyNode))
+#define Pdco1(x1,x2,x3,x4) $$ = invk_nd(x2,x1,list_nd(x2,x3))
+#define Pdcolist0(x) $$ = tree3(N_Create,x,x);\
+ proc_lst->has_coexpr = 1;
+#define Pdcolist1(x1,x2,x3) $$ =tree4(N_Elist,x2,x1,tree3(N_Create,x2,x3));\
+ proc_lst->has_coexpr = 1;
+#define Proc1(x1,x2,x3,x4,x5,x6) $$ = tree6(N_Proc,x1,x1,x4,x5,x6)
+#define Procbody1() $$ = EmptyNode
+#define Procbody2(x1,x2,x3) $$ = tree4(N_Slist,x2,x1,x3)
+#define Procdcl(x) proc_lst->tree = x
+#define Prochead1(x1,x2) init_proc(Str0(x2));\
+ idflag = F_Argument
+#define Prochead2(x1,x2,x3,x4,x5,x6) /* empty */
+#define Progend(x1,x2) /* empty */
+#define Recdcl(x) /* empty */
+#define Record1(x1, x2) init_rec(Str0(x2));\
+ idflag = F_Field
+#define Record2(x1,x2,x3,x4,x5,x6) /* empty */
+#define Repeat(x1,x2) $$ = tree5(N_Loop,x1,x1,x2,EmptyNode)
+#define Return(x1,x2) $$ = tree4(N_Ret,x1,x1,x2)
+#define Rliter(x) CSym0(x) = putlit(Str0(x),F_RealLit,0)
+#define Section(x1,x2,x3,x4,x5,x6) $$ = sect_nd(x4,x1,x3,x5)
+#define Sliter(x) CSym0(x) = putlit(Str0(x),F_StrLit,(int)Val1(x))
+#define Static(x) idflag = F_Static
+#define Subscript(x1,x2,x3,x4) $$ = buildarray(x1,x2,x3)
+#define Suspend0(x1,x2) $$ = tree5(N_Loop,x1,x1,x2,EmptyNode)
+#define Suspend1(x1,x2,x3,x4) $$ = tree5(N_Loop,x1,x1,x2,x4)
+#define To0(x1,x2,x3) $$ = to_nd(x2,x1,x3)
+#define To1(x1,x2,x3,x4,x5) $$ = toby_nd(x2,x1,x3,x5)
+#define Uat(x1,x2) $$ = tree5(N_Activat,x1,x1,EmptyNode,x2)
+#define Ubackslash(x1,x2) $$ = unary_nd(x1,x2)
+#define Ubang(x1,x2) $$ = unary_nd(x1,x2)
+#define Ubar(x1,x2) $$ = tree3(N_Bar,x2,x2)
+#define Ucaret(x1,x2) $$ = unary_nd(x1,x2)
+#define Uconcat(x1,x2) $$ = tree3(N_Bar,x2,x2)
+#define Udiff(x1,x2) $$ = MultiUnary(x1,x2)
+#define Udot(x1,x2) $$ = unary_nd(x1,x2)
+#define Uequiv(x1,x2) $$ = MultiUnary(x1,x2)
+#define Uinter(x1,x2) $$ = MultiUnary(x1,x2)
+#define Ulconcat(x1,x2) $$ = tree3(N_Bar,x2,x2)
+#define Ulexeq(x1,x2) $$ = MultiUnary(x1,x2)
+#define Ulexne(x1,x2) $$ = MultiUnary(x1,x2)
+#define Uminus(x1,x2) $$ = unary_nd(x1,x2)
+#define Unot(x1,x2) $$ = tree3(N_Not,x2,x2)
+#define Unotequiv(x1,x2) $$ = MultiUnary(x1,x2)
+#define Until0(x1,x2) $$ = tree5(N_Loop,x1,x1,x2,EmptyNode)
+#define Until1(x1,x2,x3,x4) $$ = tree5(N_Loop,x1,x1,x2,x4)
+#define Unumeq(x1,x2) $$ = unary_nd(x1,x2)
+#define Unumne(x1,x2) $$ = MultiUnary(x1,x2)
+#define Uplus(x1,x2) $$ = unary_nd(x1,x2)
+#define Uqmark(x1,x2) $$ = unary_nd(x1,x2)
+#define Uslash(x1,x2) $$ = unary_nd(x1,x2)
+#define Ustar(x1,x2) $$ = unary_nd(x1,x2)
+#define Utilde(x1,x2) $$ = unary_nd(x1,x2)
+#define Uunion(x1,x2) $$ = MultiUnary(x1,x2)
+#define Var(x) LSym0(x) = putloc(Str0(x),0)
+#define While0(x1,x2) $$ = tree5(N_Loop,x1,x1,x2,EmptyNode)
+#define While1(x1,x2,x3,x4) $$ = tree5(N_Loop,x1,x1,x2,x4)
+%}
+
+%%
+#include "../h/grammar.h"
+%%
+
+/*
+ * xfree(p) -- used with free(p) macro to avoid compiler errors from
+ * miscast free calls generated by Yacc.
+ */
+#undef free
+static void xfree(p)
+char *p;
+{
+ free(p);
+}
+
+/*#define free(p) xfree((char*)p)*/
diff --git a/src/iconc/chkinv.c b/src/iconc/chkinv.c
new file mode 100644
index 0000000..af4298f
--- /dev/null
+++ b/src/iconc/chkinv.c
@@ -0,0 +1,545 @@
+/*
+ * chkinv.c - routines to determine which global names are only
+ * used as immediate operand to invocation and to directly invoke
+ * the corresponding operations. In addition, simple assignments to
+ * names variables are recognized and it is determined whether
+ * procedures return, suspend, or fail.
+ */
+#include "../h/gsupport.h"
+#include "ctrans.h"
+#include "csym.h"
+#include "ctree.h"
+#include "ctoken.h"
+#include "cglobals.h"
+#include "ccode.h"
+#include "cproto.h"
+
+/*
+ * prototypes for static functions.
+ */
+static int chg_ret (int flag);
+static void chksmpl (struct node *n, int smpl_invk);
+static int seq_exec (int exec_flg1, int exec_flg2);
+static int spcl_inv (struct node *n, struct node *asgn);
+
+static ret_flag;
+
+/*
+ * chkinv - check for invocation and assignment optimizations.
+ */
+void chkinv()
+ {
+ struct gentry *gp;
+ struct pentry *proc;
+ int exec_flg;
+ int i;
+
+ if (debug_info)
+ return; /* The following analysis is not valid */
+
+ /*
+ * start off assuming that global variables for procedure, etc. are
+ * only used as immediate operands to invocations then mark any
+ * which are not. Any variables retaining the property are never
+ * changed. Go through the code and change invocations to such
+ * variables to invocations directly to the operation.
+ */
+ for (i = 0; i < GHSize; i++)
+ for (gp = ghash[i]; gp != NULL; gp = gp->blink) {
+ if (gp->flag & (F_Proc | F_Builtin | F_Record) &&
+ !(gp->flag & F_StrInv))
+ gp->flag |= F_SmplInv;
+ /*
+ * However, only optimize normal cases for main.
+ */
+ if (strcmp(gp->name, "main") == 0 && (gp->flag & F_Proc) &&
+ (gp->val.proc->nargs < 0 || gp->val.proc->nargs > 1))
+ gp->flag &= ~(uword)F_SmplInv;
+ /*
+ * Work-around to problem that a co-expression block needs
+ * block for enclosing procedure: just keep procedure in
+ * a variable to force outputting the block. Note, this
+ * inhibits tailored calling conventions for the procedure.
+ */
+ if ((gp->flag & F_Proc) && gp->val.proc->has_coexpr)
+ gp->flag &= ~(uword)F_SmplInv;
+ }
+
+ /*
+ * Analyze code in each procedure.
+ */
+ for (proc = proc_lst; proc != NULL; proc = proc->next) {
+ chksmpl(Tree1(proc->tree), 0); /* initial expression */
+ chksmpl(Tree2(proc->tree), 0); /* procedure body */
+ }
+
+ /*
+ * Go through each procedure performing "naive" optimizations on
+ * invocations and assignments. Also determine whether the procedure
+ * returns, suspends, or fails (possibly by falling through to
+ * the end).
+ */
+ for (proc = proc_lst; proc != NULL; proc = proc->next) {
+ ret_flag = 0;
+ spcl_inv(Tree1(proc->tree), NULL);
+ exec_flg = spcl_inv(Tree2(proc->tree), NULL);
+ if (exec_flg & DoesFThru)
+ ret_flag |= DoesFail;
+ proc->ret_flag = ret_flag;
+ }
+ }
+
+/*
+ * smpl_invk - find any global variable uses that are not a simple
+ * invocation and mark the variables.
+ */
+static void chksmpl(n, smpl_invk)
+struct node *n;
+int smpl_invk;
+ {
+ struct node *cases;
+ struct node *clause;
+ struct lentry *var;
+ int i;
+ int lst_arg;
+
+ switch (n->n_type) {
+ case N_Alt:
+ case N_Apply:
+ case N_Limit:
+ case N_Slist:
+ chksmpl(Tree0(n), 0);
+ chksmpl(Tree1(n), 0);
+ break;
+
+ case N_Activat:
+ chksmpl(Tree1(n), 0);
+ chksmpl(Tree2(n), 0);
+ break;
+
+ case N_Augop:
+ chksmpl(Tree2(n), 0);
+ chksmpl(Tree3(n), 0);
+ break;
+
+ case N_Bar:
+ case N_Break:
+ case N_Create:
+ case N_Field:
+ case N_Not:
+ chksmpl(Tree0(n), 0);
+ break;
+
+ case N_Case:
+ chksmpl(Tree0(n), 0); /* control clause */
+ cases = Tree1(n);
+ while (cases != NULL) {
+ if (cases->n_type == N_Ccls) {
+ clause = cases;
+ cases = NULL;
+ }
+ else {
+ clause = Tree1(cases);
+ cases = Tree0(cases);
+ }
+
+ chksmpl(Tree0(clause), 0); /* value of clause */
+ chksmpl(Tree1(clause), 0); /* body of clause */
+ }
+ if (Tree2(n) != NULL)
+ chksmpl(Tree2(n), 0); /* default */
+ break;
+
+ case N_Cset:
+ case N_Int:
+ case N_Real:
+ case N_Str:
+ case N_Empty:
+ case N_Next:
+ break;
+
+ case N_Id:
+ if (!smpl_invk) {
+ /*
+ * The variable is being used somewhere other than in a simple
+ * invocation.
+ */
+ var = LSym0(n);
+ if (var->flag & F_Global)
+ var->val.global->flag &= ~F_SmplInv;
+ }
+ break;
+
+ case N_If:
+ chksmpl(Tree0(n), 0);
+ chksmpl(Tree1(n), 0);
+ chksmpl(Tree2(n), 0);
+ break;
+
+ case N_Invok:
+ lst_arg = 1 + Val0(n);
+ /*
+ * Check the thing being invoked, noting that it is in fact being
+ * invoked.
+ */
+ chksmpl(Tree1(n), 1);
+ for (i = 2; i <= lst_arg; ++i)
+ chksmpl(n->n_field[i].n_ptr, 0); /* arg i - 1 */
+ break;
+
+ case N_InvOp:
+ lst_arg = 1 + Val0(n);
+ for (i = 2; i <= lst_arg; ++i)
+ chksmpl(n->n_field[i].n_ptr, 0); /* arg i */
+ break;
+
+ case N_Loop: {
+ switch ((int)Val0(Tree0(n))) {
+ case EVERY:
+ case SUSPEND:
+ case WHILE:
+ case UNTIL:
+ chksmpl(Tree1(n), 0); /* control clause */
+ chksmpl(Tree2(n), 0); /* do clause */
+ break;
+
+ case REPEAT:
+ chksmpl(Tree1(n), 0); /* clause */
+ break;
+ }
+ }
+
+ case N_Ret:
+ if (Val0(Tree0(n)) == RETURN)
+ chksmpl(Tree1(n), 0);
+ break;
+
+ case N_Scan:
+ chksmpl(Tree1(n), 0);
+ chksmpl(Tree2(n), 0);
+ break;
+
+ case N_Sect:
+ chksmpl(Tree2(n), 0);
+ chksmpl(Tree3(n), 0);
+ chksmpl(Tree4(n), 0);
+ break;
+
+ default:
+ fprintf(stderr, "compiler error: node type %d unknown\n", n->n_type);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+/*
+ * spcl_inv - look for general invocations that can be replaced by
+ * special invocations. Simple assignment to a named variable is
+ * is a particularly special case. Also, determine whether execution
+ * might "fall through" this code and whether the code might fail.
+ */
+static int spcl_inv(n, asgn)
+struct node *n;
+struct node *asgn; /* the result goes into this special-cased assignment */
+ {
+ struct node *cases;
+ struct node *clause;
+ struct node *invokee;
+ struct gentry *gvar;
+ struct loop {
+ int exec_flg;
+ struct node *asgn;
+ struct loop *prev;
+ } loop_info;
+ struct loop *loop_sav;
+ int exec_flg;
+ int i;
+ int lst_arg;
+ static struct loop *cur_loop = NULL;
+
+ switch (n->n_type) {
+ case N_Activat:
+ if (asgn != NULL)
+ Val0(asgn) = AsgnDeref; /* assume worst case */
+ return seq_exec(spcl_inv(Tree1(n), NULL), spcl_inv(Tree2(n), NULL));
+
+ case N_Alt:
+ exec_flg = spcl_inv(Tree0(n), asgn) & DoesFThru;
+ return exec_flg | spcl_inv(Tree1(n), asgn);
+
+ case N_Apply:
+ if (asgn != NULL)
+ Val0(asgn) = AsgnCopy; /* assume worst case */
+ return seq_exec(spcl_inv(Tree0(n), NULL), spcl_inv(Tree1(n), NULL));
+
+ case N_Augop:
+ exec_flg = chg_ret(Impl1(n)->ret_flag);
+ if (Tree2(n)->n_type == N_Id) {
+ /*
+ * This is an augmented assignment to a named variable.
+ * An optimized version of assignment can be used.
+ */
+ n->n_type = N_SmplAug;
+ if (Impl1(n)->use_rslt)
+ Val0(n) = AsgnCopy;
+ else
+ Val0(n) = AsgnDirect;
+ }
+ else {
+ if (asgn != NULL)
+ Val0(asgn) = AsgnDeref; /* this operation produces a variable */
+ exec_flg = seq_exec(exec_flg, spcl_inv(Tree2(n), NULL));
+ exec_flg = seq_exec(exec_flg, chg_ret(Impl0(n)->ret_flag));
+ }
+ return seq_exec(exec_flg, spcl_inv(Tree3(n), NULL));
+
+ case N_Bar:
+ return spcl_inv(Tree0(n), asgn);
+
+ case N_Break:
+ if (cur_loop == NULL) {
+ nfatal(n, "invalid context for break", NULL);
+ return 0;
+ }
+ loop_sav = cur_loop;
+ cur_loop = cur_loop->prev;
+ loop_sav->exec_flg |= spcl_inv(Tree0(n), loop_sav->asgn);
+ cur_loop = loop_sav;
+ return 0;
+
+ case N_Create:
+ spcl_inv(Tree0(n), NULL);
+ return DoesFThru;
+
+ case N_Case:
+ exec_flg = spcl_inv(Tree0(n), NULL) & DoesFail; /* control clause */
+ cases = Tree1(n);
+ while (cases != NULL) {
+ if (cases->n_type == N_Ccls) {
+ clause = cases;
+ cases = NULL;
+ }
+ else {
+ clause = Tree1(cases);
+ cases = Tree0(cases);
+ }
+
+ spcl_inv(Tree0(clause), NULL);
+ exec_flg |= spcl_inv(Tree1(clause), asgn);
+ }
+ if (Tree2(n) != NULL)
+ exec_flg |= spcl_inv(Tree2(n), asgn); /* default */
+ else
+ exec_flg |= DoesFail;
+ return exec_flg;
+
+ case N_Cset:
+ case N_Int:
+ case N_Real:
+ case N_Str:
+ case N_Empty:
+ return DoesFThru;
+
+ case N_Field:
+ if (asgn != NULL)
+ Val0(asgn) = AsgnDeref; /* operation produces variable */
+ return spcl_inv(Tree0(n), NULL);
+
+ case N_Id:
+ if (asgn != NULL)
+ Val0(asgn) = AsgnDeref; /* variable */
+ return DoesFThru;
+
+ case N_If:
+ spcl_inv(Tree0(n), NULL);
+ exec_flg = spcl_inv(Tree1(n), asgn);
+ if (Tree2(n)->n_type == N_Empty)
+ exec_flg |= DoesFail;
+ else
+ exec_flg |= spcl_inv(Tree2(n), asgn);
+ return exec_flg;
+
+ case N_Invok:
+ lst_arg = 1 + Val0(n);
+ invokee = Tree1(n);
+ exec_flg = DoesFThru;
+ for (i = 2; i <= lst_arg; ++i)
+ exec_flg = seq_exec(exec_flg, spcl_inv(n->n_field[i].n_ptr, NULL));
+ if (invokee->n_type == N_Id && LSym0(invokee)->flag & F_Global) {
+ /*
+ * This is an invocation of a global variable. If we can
+ * convert this to a direct invocation, determine whether
+ * it is an invocation of a procedure, built-in function,
+ * or record constructor; each has a difference kind of
+ * direct invocation node.
+ */
+ gvar = LSym0(invokee)->val.global;
+ if (gvar->flag & F_SmplInv) {
+ switch (gvar->flag & (F_Proc | F_Builtin | F_Record)) {
+ case F_Proc:
+ n->n_type = N_InvProc;
+ Proc1(n) = gvar->val.proc;
+ return DoesFThru | DoesFail; /* assume worst case */
+ case F_Builtin:
+ n->n_type = N_InvOp;
+ Impl1(n) = gvar->val.builtin;
+ if (asgn != NULL && Impl1(n)->use_rslt)
+ Val0(asgn) = AsgnCopy;
+ return seq_exec(exec_flg, chg_ret(
+ gvar->val.builtin->ret_flag));
+ case F_Record:
+ n->n_type = N_InvRec;
+ Rec1(n) = gvar->val.rec;
+ return seq_exec(exec_flg, DoesFThru |
+ (err_conv ? DoesFail : 0));
+ }
+ }
+ }
+ if (asgn != NULL)
+ Val0(asgn) = AsgnCopy; /* assume worst case */
+ spcl_inv(invokee, NULL);
+ return DoesFThru | DoesFail; /* assume worst case */
+
+ case N_InvOp:
+ if (Impl1(n)->op != NULL && strcmp(Impl1(n)->op, ":=") == 0 &&
+ Tree2(n)->n_type == N_Id) {
+ /*
+ * This is a simple assignment to a named variable.
+ * An optimized version of assignment can be used.
+ */
+ n->n_type = N_SmplAsgn;
+
+ /*
+ * For now, assume rhs of := can compute directly into a
+ * variable. This may be changed when the rhs is examined
+ * in the recursive call to spcl_inv().
+ */
+ Val0(n) = AsgnDirect;
+ return spcl_inv(Tree3(n), n);
+ }
+ else {
+ /*
+ * No special cases.
+ */
+ lst_arg = 1 + Val0(n);
+ exec_flg = chg_ret(Impl1(n)->ret_flag);
+ for (i = 2; i <= lst_arg; ++i)
+ exec_flg = seq_exec(exec_flg, spcl_inv(n->n_field[i].n_ptr,
+ NULL)); /* arg i */
+ if (asgn != NULL && Impl1(n)->use_rslt)
+ Val0(asgn) = AsgnCopy;
+ return exec_flg;
+ }
+
+ case N_Limit:
+ return seq_exec(spcl_inv(Tree0(n), asgn),
+ spcl_inv(Tree1(n), NULL)) | DoesFail;
+
+ case N_Loop: {
+ loop_info.prev = cur_loop;
+ loop_info.exec_flg = 0;
+ loop_info.asgn = asgn;
+ cur_loop = &loop_info;
+ switch ((int)Val0(Tree0(n))) {
+ case EVERY:
+ case WHILE:
+ case UNTIL:
+ spcl_inv(Tree1(n), NULL); /* control clause */
+ spcl_inv(Tree2(n), NULL); /* do clause */
+ exec_flg = DoesFail;
+ break;
+
+ case SUSPEND:
+ spcl_inv(Tree1(n), NULL); /* control clause */
+ spcl_inv(Tree2(n), NULL); /* do clause */
+ ret_flag |= DoesSusp;
+ exec_flg = DoesFail;
+ break;
+
+ case REPEAT:
+ spcl_inv(Tree1(n), NULL); /* clause */
+ exec_flg = 0;
+ break;
+ }
+ exec_flg |= cur_loop->exec_flg;
+ cur_loop = cur_loop->prev;
+ return exec_flg;
+ }
+
+ case N_Next:
+ return 0;
+
+ case N_Not:
+ exec_flg = spcl_inv(Tree0(n), NULL);
+ return ((exec_flg & DoesFail) ? DoesFThru : 0) |
+ ((exec_flg & DoesFThru) ? DoesFail: 0);
+
+ case N_Ret:
+ if (Val0(Tree0(n)) == RETURN) {
+ exec_flg = spcl_inv(Tree1(n), NULL);
+ ret_flag |= DoesRet;
+ if (exec_flg & DoesFail)
+ ret_flag |= DoesFail;
+ }
+ else
+ ret_flag |= DoesFail;
+ return 0;
+
+ case N_Scan:
+ if (asgn != NULL)
+ Val0(asgn) = AsgnCopy; /* assume worst case */
+ return seq_exec(spcl_inv(Tree1(n), NULL),
+ spcl_inv(Tree2(n), NULL));
+
+ case N_Sect:
+ if (asgn != NULL && Impl0(n)->use_rslt)
+ Val0(asgn) = AsgnCopy;
+ exec_flg = spcl_inv(Tree2(n), NULL);
+ exec_flg = seq_exec(exec_flg, spcl_inv(Tree3(n), NULL));
+ exec_flg = seq_exec(exec_flg, spcl_inv(Tree4(n), NULL));
+ return seq_exec(exec_flg, chg_ret(Impl0(n)->ret_flag));
+
+ case N_Slist:
+ exec_flg = spcl_inv(Tree0(n), NULL);
+ if (exec_flg & (DoesFThru | DoesFail))
+ exec_flg = DoesFThru;
+ return seq_exec(exec_flg, spcl_inv(Tree1(n), asgn));
+
+ default:
+ fprintf(stderr, "compiler error: node type %d unknown\n", n->n_type);
+ exit(EXIT_FAILURE);
+ /* NOTREACHED */
+ }
+ }
+
+/*
+ * seq_exec - take the execution flags for sequential pieces of code
+ * and compute the flags for the combined code.
+ */
+static int seq_exec(exec_flg1, exec_flg2)
+int exec_flg1;
+int exec_flg2;
+ {
+ return (exec_flg1 & exec_flg2 & DoesFThru) |
+ ((exec_flg1 | exec_flg2) & DoesFail);
+ }
+
+/*
+ * chg_ret - take a return flag and change suspend and return to
+ * "fall through". If error conversion is supported, change error
+ * failure to failure.
+ *
+ */
+static int chg_ret(flag)
+int flag;
+ {
+ int flg1;
+
+ flg1 = flag & DoesFail;
+ if (flag & (DoesRet | DoesSusp))
+ flg1 |= DoesFThru;
+ if (err_conv && (flag & DoesEFail))
+ flg1 |= DoesFail;
+ return flg1;
+ }
+
+
diff --git a/src/iconc/clex.c b/src/iconc/clex.c
new file mode 100644
index 0000000..8e7d657
--- /dev/null
+++ b/src/iconc/clex.c
@@ -0,0 +1,18 @@
+/*
+ * clex.c -- the lexical analyzer for iconc.
+ */
+#define Iconc
+
+#include "../h/gsupport.h"
+#include "../h/lexdef.h"
+#include "ctrans.h"
+#include "ctoken.h"
+#include "ctree.h"
+#include "csym.h"
+#include "ccode.h"
+#include "cproto.h"
+
+#include "../h/parserr.h"
+#include "../common/lextab.h"
+#include "../common/yylex.h"
+#include "../common/error.h"
diff --git a/src/iconc/cmain.c b/src/iconc/cmain.c
new file mode 100644
index 0000000..6daf5c4
--- /dev/null
+++ b/src/iconc/cmain.c
@@ -0,0 +1,424 @@
+/*
+ * cmain.c - main program icon compiler.
+ */
+#include "../h/gsupport.h"
+#include "ctrans.h"
+#include "ctree.h"
+#include "ccode.h"
+#include "csym.h"
+#include "cproto.h"
+
+/*
+ * Prototypes.
+ */
+static void execute (char *ofile, char **args);
+static FILE *open_out (char *fname);
+static void rmfile (char *fname);
+static void report (char *s);
+static void usage (void);
+
+char *refpath;
+
+char patchpath[MaxPath+18] = "%PatchStringHere->";
+
+/*
+ * Define global variables.
+ */
+
+#define Global
+#define Init(v) = v
+#include "cglobals.h"
+
+/*
+ * getopt() variables
+ */
+extern int optind; /* index into parent argv vector */
+extern int optopt; /* character checked for validity */
+extern char *optarg; /* argument associated with option */
+
+/*
+ * main program
+ */
+int main(argc,argv)
+int argc;
+char **argv;
+ {
+ int no_c_comp = 0; /* suppress C compile and link? */
+ int errors = 0; /* compilation errors */
+ char *cfile = NULL; /* name of C file - primary */
+ char *hfile = NULL; /* name of C file - include */
+ char *ofile = NULL; /* name of executable result */
+
+ char *db_name = "rt.db"; /* data base name */
+ char *incl_file = "rt.h"; /* header file name */
+
+ char *db_path; /* path to data base */
+ char *db_lst; /* list of private data bases */
+ char *incl_path; /* path to header file */
+ char *s, c1;
+ char buf[MaxPath]; /* file name construction buffer */
+ int c;
+ int ret_code;
+ struct fileparts *fp;
+
+ if ((int)strlen(patchpath) > 18)
+ refpath = patchpath+18;
+ else
+ refpath = relfile(argv[0], "/../");
+
+ /*
+ * Process options.
+ */
+ while ((c = getopt(argc,argv,"+C:ELS:Tcf:mn:o:p:r:stuv:x")) != EOF)
+ switch (c) {
+ case 'C': /* -C C-comp: C compiler*/
+ c_comp = optarg;
+ break;
+ case 'E': /* -E: preprocess only */
+ pponly = 1;
+ no_c_comp = 1;
+ break;
+ case 'L': /* Ignore: interpreter only */
+ break;
+ case 'S': /* Ignore: interpreter only */
+ break;
+ case 'T':
+ just_type_trace = 1;
+ break;
+ case 'c': /* -c: produce C file only */
+ no_c_comp = 1;
+ break;
+ case 'f': /* -f: enable features */
+ for (s = optarg; *s != '\0'; ++s) {
+ switch (*s) {
+ case 'a': /* -fa: enable all features */
+ line_info = 1;
+ debug_info = 1;
+ err_conv = 1;
+ largeints = 1;
+ str_inv = 1;
+ break;
+ case 'd': /* -fd: enable debugging features */
+ line_info = 1;
+ debug_info = 1;
+ break;
+ case 'e': /* -fe: enable error conversion */
+ err_conv = 1;
+ break;
+ case 'l': /* -fl: support large integers */
+ largeints = 1;
+ break;
+ case 'n': /* -fn: enable line numbers */
+ line_info = 1;
+ break;
+ case 's': /* -fs: enable full string invocation */
+ str_inv = 1;
+ break;
+ default:
+ quitf("-f option must be a, d, e, l, n, or s. found: %s",
+ optarg);
+ }
+ }
+ break;
+ case 'm': /* -m: preprocess using m4(1) */
+ m4pre = 1;
+ break;
+ case 'n': /* -n: disable optimizations */
+ for (s = optarg; *s != '\0'; ++s) {
+ switch (*s) {
+ case 'a': /* -na: disable all optimizations */
+ opt_cntrl = 0;
+ allow_inline = 0;
+ opt_sgnl = 0;
+ do_typinfer = 0;
+ break;
+ case 'c': /* -nc: disable control flow opts */
+ opt_cntrl = 0;
+ break;
+ case 'e': /* -ne: disable expanding in-line */
+ allow_inline = 0;
+ break;
+ case 's': /* -ns: disable switch optimizations */
+ opt_sgnl = 0;
+ break;
+ case 't': /* -nt: disable type inference */
+ do_typinfer = 0;
+ break;
+ default:
+ usage();
+ }
+ }
+ break;
+ case 'o': /* -o file: name output file */
+ ofile = optarg;
+ break;
+ case 'p': /* -p C-opts: options for C comp */
+ if (*optarg == '\0') /* if empty string, clear options */
+ c_opts = optarg;
+ else { /* else append to current set */
+ s = (char *)alloc(strlen(c_opts) + 1 + strlen(optarg) + 1);
+ sprintf(s, "%s %s", c_opts, optarg);
+ c_opts = s;
+ }
+ break;
+ case 'r': /* -r path: primary runtime system */
+ refpath = optarg;
+ break;
+ case 's': /* -s: suppress informative messages */
+ verbose = 0;
+ break;
+ case 't': /* -t: &trace = -1 */
+ line_info = 1;
+ debug_info = 1;
+ trace = 1;
+ break;
+ case 'u': /* -u: warn about undeclared ids */
+ uwarn = 1;
+ break;
+ case 'v': /* -v: set level of verbosity */
+ if (sscanf(optarg, "%d%c", &verbose, &c1) != 1)
+ quitf("bad operand to -v option: %s",optarg);
+ break;
+ default:
+ case 'x': /* -x illegal until after file list */
+ usage();
+ }
+
+ init(); /* initialize memory for translation */
+
+ /*
+ * Load the data bases of information about run-time routines and
+ * determine what libraries are needed for linking (these libraries
+ * go before any specified on the command line).
+ */
+ db_lst = getenv("DBLIST");
+ if (db_lst != NULL)
+ db_lst = salloc(db_lst);
+ s = db_lst;
+ while (s != NULL) {
+ db_lst = s;
+ while (isspace(*db_lst))
+ ++db_lst;
+ if (*db_lst == '\0')
+ break;
+ for (s = db_lst; !isspace(*s) && *s != '\0'; ++s)
+ ;
+ if (*s == '\0')
+ s = NULL;
+ else
+ *s++ = '\0';
+ readdb(db_lst);
+ addlib(salloc(makename(buf,SourceDir, db_lst, LibSuffix)));
+ }
+ db_path = (char *)alloc((unsigned int)strlen(refpath) + strlen(db_name) + 1);
+ strcpy(db_path, refpath);
+ strcat(db_path, db_name);
+ readdb(db_path);
+ addlib(salloc(makename(buf,SourceDir, db_path, LibSuffix)));
+
+ /*
+ * Scan the rest of the command line for file name arguments.
+ */
+ while (optind < argc) {
+ if (strcmp(argv[optind],"-x") == 0) /* stop at -x */
+ break;
+ else if (strcmp(argv[optind],"-") == 0)
+ src_file("-"); /* "-" means standard input */
+ else if (argv[optind][0] == '-')
+ addlib(argv[optind]); /* assume linker option */
+ else {
+ fp = fparse(argv[optind]); /* parse file name */
+ if (*fp->ext == '\0' || smatch(fp->ext, SourceSuffix)) {
+ makename(buf,SourceDir,argv[optind], SourceSuffix);
+ src_file(buf);
+ }
+ else
+ /*
+ * Assume all files that are not Icon source go to linker.
+ */
+ addlib(argv[optind]);
+ }
+ optind++;
+ }
+
+ if (srclst == NULL)
+ usage(); /* error -- no files named */
+
+ if (pponly) {
+ if (trans() == 0)
+ exit (EXIT_FAILURE);
+ else
+ exit (EXIT_SUCCESS);
+ }
+
+ if (ofile == NULL) { /* if no -o file, synthesize a name */
+ if (strcmp(srclst->name,"-") == 0)
+ ofile = salloc(makename(buf,TargetDir,"stdin",ExecSuffix));
+ else
+ ofile = salloc(makename(buf,TargetDir,srclst->name,ExecSuffix));
+ } else { /* add extension if necessary */
+ fp = fparse(ofile);
+ if (*fp->ext == '\0' && *ExecSuffix != '\0')
+ ofile = salloc(makename(buf,NULL,ofile,ExecSuffix));
+ }
+
+ /*
+ * Make name of intermediate C files.
+ */
+ cfile = salloc(makename(buf,TargetDir,ofile,CSuffix));
+ hfile = salloc(makename(buf,TargetDir,ofile,HSuffix));
+
+ codefile = open_out(cfile);
+ fprintf(codefile, "#include \"%s\"\n", hfile);
+
+ inclfile = open_out(hfile);
+ fprintf(inclfile, "#define COMPILER 1\n");
+
+ incl_path = (char *)alloc((unsigned int)(strlen(refpath) +
+ strlen(incl_file) + 1));
+ strcpy(incl_path, refpath);
+ strcat(incl_path, incl_file);
+ fprintf(inclfile,"#include \"%s\"\n", incl_path);
+
+ /*
+ * Translate .icn files to make C file.
+ */
+ if ((verbose > 0) && !just_type_trace)
+ report("Translating to C");
+
+ errors = trans();
+ if ((errors > 0) || just_type_trace) { /* exit if errors seen */
+ rmfile(cfile);
+ rmfile(hfile);
+ if (errors > 0)
+ exit(EXIT_FAILURE);
+ else exit(EXIT_SUCCESS);
+ }
+
+ fclose(codefile);
+ fclose(inclfile);
+
+ /*
+ * Compile and link C file.
+ */
+ if (no_c_comp) /* exit if no C compile wanted */
+ exit(EXIT_SUCCESS);
+
+ if (verbose > 0)
+ report("Compiling and linking C code");
+
+ ret_code = ccomp(cfile, ofile);
+ if (ret_code == EXIT_FAILURE) {
+ fprintf(stderr, "*** C compile and link failed ***\n");
+ rmfile(ofile);
+ }
+
+ /*
+ * Finish by removing C files.
+ */
+ rmfile(cfile);
+ rmfile(hfile);
+ rmfile(makename(buf,TargetDir,cfile,ObjSuffix));
+
+ if (ret_code == EXIT_SUCCESS && optind < argc) {
+ if (verbose > 0)
+ report("Executing");
+ execute (ofile, argv+optind+1);
+ }
+
+ return ret_code;
+ }
+
+/*
+ * execute - execute compiled Icon program
+ */
+static void execute(ofile,args)
+char *ofile, **args;
+ {
+
+ int n;
+ char **argv, **p;
+ char buf[MaxPath]; /* file name construction buffer */
+
+ ofile = salloc(makename(buf,"./",ofile,ExecSuffix));
+
+ for (n = 0; args[n] != NULL; n++) /* count arguments */
+ ;
+ p = argv = (char **)alloc((unsigned int)((n + 2) * sizeof(char *)));
+
+ *p++ = ofile; /* set executable file */
+
+ while (*p++ = *args++) /* copy args into argument vector */
+ ;
+ *p = NULL;
+
+ execvp(ofile,argv);
+ quitf("could not run %s",ofile);
+ }
+
+/*
+ * Report phase.
+ */
+static void report(s)
+char *s;
+ {
+ fprintf(stderr,"%s:\n",s);
+ }
+
+/*
+ * rmfile - remove a file
+ */
+
+static void rmfile(fname)
+char *fname;
+ {
+ remove(fname);
+ }
+
+/*
+ * open_out - open a C output file and write identifying information
+ * to the front.
+ */
+static FILE *open_out(fname)
+char *fname;
+ {
+ FILE *f;
+ static char *ident = "/*ICONC*/";
+ int c;
+ int i;
+
+ /*
+ * If the file already exists, make sure it is old output from iconc
+ * before overwriting it. Note, this test doesn't work if the file
+ * is writable but not readable.
+ */
+ f = fopen(fname, "r");
+ if (f != NULL) {
+ for (i = 0; i < (int)strlen(ident); ++i) {
+ c = getc(f);
+ if (c == EOF)
+ break;
+ if ((char)c != ident[i])
+ quitf("%s not in iconc format; rename or delete, and rerun", fname);
+ }
+ fclose(f);
+ }
+
+ f = fopen(fname, "w");
+ if (f == NULL)
+ quitf("cannot create %s", fname);
+ fprintf(f, "%s\n", ident); /* write "belongs to iconc" comment */
+ id_comment(f); /* write detailed comment for human readers */
+ fflush(f);
+ return f;
+ }
+
+/*
+ * Print an error message if called incorrectly. The message depends
+ * on the legal options for this system.
+ */
+static void usage()
+ {
+ fprintf(stderr,"usage: %s %s file ... [-x args]\n", progname, CUsage);
+ exit(EXIT_FAILURE);
+ }
diff --git a/src/iconc/cmem.c b/src/iconc/cmem.c
new file mode 100644
index 0000000..720a495
--- /dev/null
+++ b/src/iconc/cmem.c
@@ -0,0 +1,114 @@
+/*
+ * cmem.c -- memory initialization and allocation for the translator.
+ */
+#include "../h/gsupport.h"
+#include "cglobals.h"
+#include "ctrans.h"
+#include "csym.h"
+#include "ctree.h"
+#include "ccode.h"
+#include "cproto.h"
+
+struct centry *chash[CHSize]; /* hash area for constant table */
+struct fentry *fhash[FHSize]; /* hash area for field table */
+struct gentry *ghash[GHSize]; /* hash area for global table */
+
+struct implement *bhash[IHSize]; /* hash area for built-in functions */
+struct implement *khash[IHSize]; /* hash area for keywords */
+struct implement *ohash[IHSize]; /* hash area for operators */
+
+struct implement *spec_op[NumSpecOp]; /* table of ops with special syntax */
+
+char pre[PrfxSz] = {'0', '0', '0'}; /* initial function name prefix */
+
+extern struct str_buf lex_sbuf;
+
+
+/*
+ * init - initialize memory for the translator
+ */
+
+void init()
+{
+ int i;
+
+ init_str();
+ init_sbuf(&lex_sbuf);
+
+ /*
+ * Zero out the hash tables.
+ */
+ for (i = 0; i < CHSize; i++)
+ chash[i] = NULL;
+ for (i = 0; i < FHSize; i++)
+ fhash[i] = NULL;
+ for (i = 0; i < GHSize; i++)
+ ghash[i] = NULL;
+ for (i = 0; i < IHSize; i++) {
+ bhash[i] = NULL;
+ khash[i] = NULL;
+ ohash[i] = NULL;
+ }
+
+ /*
+ * Clear table of operators with non-standard operator syntax.
+ */
+ for (i = 0; i < NumSpecOp; ++i)
+ spec_op[i] = NULL;
+ }
+
+/*
+ * init_proc - add a new entry on front of procedure list.
+ */
+void init_proc(name)
+char *name;
+ {
+ register struct pentry *p;
+ int i;
+ struct gentry *sym_ent;
+
+ p = NewStruct(pentry);
+ p->name = name;
+ nxt_pre(p->prefix, pre, PrfxSz);
+ p->prefix[PrfxSz] = '\0';
+ p->nargs = 0;
+ p->args = NULL;
+ p->ndynam = 0;
+ p->dynams = NULL;
+ p->nstatic = 0;
+ p->has_coexpr = 0;
+ p->statics = NULL;
+ p->ret_flag = DoesRet | DoesFail | DoesSusp; /* start out pessimistic */
+ p->arg_lst = 0;
+ p->lhash =
+ (struct lentry **)alloc((unsigned int)((LHSize)*sizeof(struct lentry *)));
+ for (i = 0; i < LHSize; i++)
+ p->lhash[i] = NULL;
+ p->next = proc_lst;
+ proc_lst = p;
+ sym_ent = instl_p(name, F_Proc);
+ sym_ent->val.proc = proc_lst;
+ }
+
+/*
+ * init_rec - add a new entry on the front of the record list.
+ */
+void init_rec(name)
+char *name;
+ {
+ register struct rentry *r;
+ struct gentry *sym_ent;
+ static int rec_num = 0;
+
+ r = NewStruct(rentry);
+ r->name = name;
+ nxt_pre(r->prefix, pre, PrfxSz);
+ r->prefix[PrfxSz] = '\0';
+ r->rec_num = rec_num++;
+ r->nfields = 0;
+ r->fields = NULL;
+ r->next = rec_lst;
+ rec_lst = r;
+ sym_ent= instl_p(name, F_Record);
+ sym_ent->val.rec = r;
+ }
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);
+ }
+
diff --git a/src/iconc/cparse.c b/src/iconc/cparse.c
new file mode 100644
index 0000000..b29986d
--- /dev/null
+++ b/src/iconc/cparse.c
@@ -0,0 +1,1940 @@
+# define IDENT 257
+# define INTLIT 258
+# define REALLIT 259
+# define STRINGLIT 260
+# define CSETLIT 261
+# define EOFX 262
+# define BREAK 263
+# define BY 264
+# define CASE 265
+# define CREATE 266
+# define DEFAULT 267
+# define DO 268
+# define ELSE 269
+# define END 270
+# define EVERY 271
+# define FAIL 272
+# define GLOBAL 273
+# define IF 274
+# define INITIAL 275
+# define INVOCABLE 276
+# define LINK 277
+# define LOCAL 278
+# define NEXT 279
+# define NOT 280
+# define OF 281
+# define PROCEDURE 282
+# define RECORD 283
+# define REPEAT 284
+# define RETURN 285
+# define STATIC 286
+# define SUSPEND 287
+# define THEN 288
+# define TO 289
+# define UNTIL 290
+# define WHILE 291
+# define BANG 292
+# define MOD 293
+# define AUGMOD 294
+# define AND 295
+# define AUGAND 296
+# define STAR 297
+# define AUGSTAR 298
+# define INTER 299
+# define AUGINTER 300
+# define PLUS 301
+# define AUGPLUS 302
+# define UNION 303
+# define AUGUNION 304
+# define MINUS 305
+# define AUGMINUS 306
+# define DIFF 307
+# define AUGDIFF 308
+# define DOT 309
+# define SLASH 310
+# define AUGSLASH 311
+# define ASSIGN 312
+# define SWAP 313
+# define NMLT 314
+# define AUGNMLT 315
+# define REVASSIGN 316
+# define REVSWAP 317
+# define SLT 318
+# define AUGSLT 319
+# define SLE 320
+# define AUGSLE 321
+# define NMLE 322
+# define AUGNMLE 323
+# define NMEQ 324
+# define AUGNMEQ 325
+# define SEQ 326
+# define AUGSEQ 327
+# define EQUIV 328
+# define AUGEQUIV 329
+# define NMGT 330
+# define AUGNMGT 331
+# define NMGE 332
+# define AUGNMGE 333
+# define SGT 334
+# define AUGSGT 335
+# define SGE 336
+# define AUGSGE 337
+# define QMARK 338
+# define AUGQMARK 339
+# define AT 340
+# define AUGAT 341
+# define BACKSLASH 342
+# define CARET 343
+# define AUGCARET 344
+# define BAR 345
+# define CONCAT 346
+# define AUGCONCAT 347
+# define LCONCAT 348
+# define AUGLCONCAT 349
+# define TILDE 350
+# define NMNE 351
+# define AUGNMNE 352
+# define SNE 353
+# define AUGSNE 354
+# define NEQUIV 355
+# define AUGNEQUIV 356
+# define LPAREN 357
+# define RPAREN 358
+# define PCOLON 359
+# define COMMA 360
+# define MCOLON 361
+# define COLON 362
+# define SEMICOL 363
+# define LBRACK 364
+# define RBRACK 365
+# define LBRACE 366
+# define RBRACE 367
+
+# line 145 "cgram.g"
+/*
+ * These commented directives are passed through the first application
+ * of cpp, then turned into real directives in cgram.g by fixgram.icn.
+ */
+#include "../h/gsupport.h"
+#include "../h/lexdef.h"
+#include "ctrans.h"
+#include "csym.h"
+#include "ctree.h"
+#include "ccode.h"
+#include "cproto.h"
+#undef YYSTYPE
+#define YYSTYPE nodeptr
+#define YYMAXDEPTH 500
+
+int idflag;
+
+
+
+#define yyclearin yychar = -1
+#define yyerrok yyerrflag = 0
+extern int yychar;
+extern int yyerrflag;
+#ifndef YYMAXDEPTH
+#define YYMAXDEPTH 150
+#endif
+#ifndef YYSTYPE
+#define YYSTYPE int
+#endif
+YYSTYPE yylval, yyval;
+# define YYERRCODE 256
+
+# line 441 "cgram.g"
+
+
+/*
+ * xfree(p) -- used with free(p) macro to avoid compiler errors from
+ * miscast free calls generated by Yacc.
+ */
+
+static void xfree(p)
+char *p;
+{
+ free(p);
+}
+
+#define free(p) xfree((char*)p)
+int yyexca[] ={
+-1, 0,
+ 262, 2,
+ 273, 2,
+ 276, 2,
+ 277, 2,
+ 282, 2,
+ 283, 2,
+ -2, 0,
+-1, 1,
+ 0, -1,
+ -2, 0,
+-1, 20,
+ 270, 40,
+ 363, 42,
+ -2, 0,
+-1, 86,
+ 264, 42,
+ 268, 42,
+ 269, 42,
+ 281, 42,
+ 288, 42,
+ 289, 42,
+ 293, 42,
+ 294, 42,
+ 296, 42,
+ 298, 42,
+ 300, 42,
+ 302, 42,
+ 304, 42,
+ 306, 42,
+ 308, 42,
+ 311, 42,
+ 312, 42,
+ 313, 42,
+ 314, 42,
+ 315, 42,
+ 316, 42,
+ 317, 42,
+ 318, 42,
+ 319, 42,
+ 320, 42,
+ 321, 42,
+ 322, 42,
+ 323, 42,
+ 325, 42,
+ 327, 42,
+ 329, 42,
+ 330, 42,
+ 331, 42,
+ 332, 42,
+ 333, 42,
+ 334, 42,
+ 335, 42,
+ 336, 42,
+ 337, 42,
+ 339, 42,
+ 341, 42,
+ 344, 42,
+ 347, 42,
+ 349, 42,
+ 352, 42,
+ 354, 42,
+ 356, 42,
+ 358, 42,
+ 359, 42,
+ 360, 42,
+ 361, 42,
+ 362, 42,
+ 363, 42,
+ 365, 42,
+ 367, 42,
+ -2, 0,
+-1, 87,
+ 358, 42,
+ 360, 42,
+ -2, 0,
+-1, 88,
+ 363, 42,
+ 367, 42,
+ -2, 0,
+-1, 89,
+ 360, 42,
+ 365, 42,
+ -2, 0,
+-1, 96,
+ 264, 42,
+ 268, 42,
+ 269, 42,
+ 281, 42,
+ 288, 42,
+ 289, 42,
+ 293, 42,
+ 294, 42,
+ 296, 42,
+ 298, 42,
+ 300, 42,
+ 302, 42,
+ 304, 42,
+ 306, 42,
+ 308, 42,
+ 311, 42,
+ 312, 42,
+ 313, 42,
+ 314, 42,
+ 315, 42,
+ 316, 42,
+ 317, 42,
+ 318, 42,
+ 319, 42,
+ 320, 42,
+ 321, 42,
+ 322, 42,
+ 323, 42,
+ 325, 42,
+ 327, 42,
+ 329, 42,
+ 330, 42,
+ 331, 42,
+ 332, 42,
+ 333, 42,
+ 334, 42,
+ 335, 42,
+ 336, 42,
+ 337, 42,
+ 339, 42,
+ 341, 42,
+ 344, 42,
+ 347, 42,
+ 349, 42,
+ 352, 42,
+ 354, 42,
+ 356, 42,
+ 358, 42,
+ 359, 42,
+ 360, 42,
+ 361, 42,
+ 362, 42,
+ 363, 42,
+ 365, 42,
+ 367, 42,
+ -2, 0,
+-1, 97,
+ 264, 42,
+ 268, 42,
+ 269, 42,
+ 281, 42,
+ 288, 42,
+ 289, 42,
+ 293, 42,
+ 294, 42,
+ 296, 42,
+ 298, 42,
+ 300, 42,
+ 302, 42,
+ 304, 42,
+ 306, 42,
+ 308, 42,
+ 311, 42,
+ 312, 42,
+ 313, 42,
+ 314, 42,
+ 315, 42,
+ 316, 42,
+ 317, 42,
+ 318, 42,
+ 319, 42,
+ 320, 42,
+ 321, 42,
+ 322, 42,
+ 323, 42,
+ 325, 42,
+ 327, 42,
+ 329, 42,
+ 330, 42,
+ 331, 42,
+ 332, 42,
+ 333, 42,
+ 334, 42,
+ 335, 42,
+ 336, 42,
+ 337, 42,
+ 339, 42,
+ 341, 42,
+ 344, 42,
+ 347, 42,
+ 349, 42,
+ 352, 42,
+ 354, 42,
+ 356, 42,
+ 358, 42,
+ 359, 42,
+ 360, 42,
+ 361, 42,
+ 362, 42,
+ 363, 42,
+ 365, 42,
+ 367, 42,
+ -2, 0,
+-1, 111,
+ 270, 40,
+ 363, 42,
+ -2, 0,
+-1, 117,
+ 270, 40,
+ 363, 42,
+ -2, 0,
+-1, 182,
+ 360, 42,
+ 365, 42,
+ -2, 0,
+-1, 183,
+ 360, 42,
+ -2, 0,
+-1, 184,
+ 358, 42,
+ 360, 42,
+ -2, 0,
+-1, 311,
+ 358, 42,
+ 360, 42,
+ 365, 42,
+ -2, 0,
+-1, 313,
+ 363, 42,
+ 367, 42,
+ -2, 0,
+-1, 335,
+ 360, 42,
+ 367, 42,
+ -2, 0,
+ };
+# define YYNPROD 203
+# define YYLAST 728
+int yyact[]={
+
+ 38, 84, 91, 92, 93, 94, 312, 86, 185, 99,
+ 83, 118, 335, 359, 341, 102, 95, 358, 98, 334,
+ 311, 311, 355, 85, 51, 329, 314, 20, 103, 96,
+ 118, 97, 313, 228, 101, 100, 56, 346, 118, 90,
+ 118, 59, 117, 62, 360, 58, 108, 70, 336, 64,
+ 311, 57, 228, 55, 60, 326, 184, 228, 310, 119,
+ 311, 107, 106, 182, 345, 183, 324, 232, 65, 110,
+ 67, 168, 69, 169, 352, 214, 118, 350, 328, 177,
+ 41, 356, 71, 174, 50, 175, 73, 61, 325, 52,
+ 53, 320, 54, 316, 63, 66, 176, 68, 327, 72,
+ 118, 87, 332, 118, 333, 331, 319, 361, 89, 116,
+ 88, 305, 38, 84, 91, 92, 93, 94, 118, 86,
+ 181, 99, 83, 353, 317, 231, 3, 102, 95, 218,
+ 98, 318, 105, 118, 19, 85, 51, 315, 118, 28,
+ 103, 96, 29, 97, 217, 321, 101, 100, 56, 309,
+ 170, 90, 172, 59, 173, 62, 171, 58, 118, 70,
+ 30, 64, 18, 57, 118, 55, 60, 44, 180, 37,
+ 179, 178, 113, 24, 104, 114, 25, 330, 351, 306,
+ 65, 212, 67, 115, 69, 82, 2, 81, 80, 27,
+ 17, 36, 23, 79, 71, 78, 50, 77, 73, 61,
+ 76, 52, 53, 75, 54, 74, 63, 66, 49, 68,
+ 47, 72, 42, 87, 38, 84, 91, 92, 93, 94,
+ 89, 86, 88, 99, 83, 40, 112, 322, 109, 102,
+ 95, 34, 98, 273, 274, 111, 33, 85, 51, 12,
+ 233, 32, 103, 96, 21, 97, 22, 26, 101, 100,
+ 56, 10, 9, 90, 8, 59, 7, 62, 31, 58,
+ 6, 70, 5, 64, 1, 57, 0, 55, 60, 13,
+ 0, 216, 15, 14, 0, 210, 0, 0, 16, 11,
+ 0, 0, 65, 0, 67, 234, 69, 236, 239, 221,
+ 222, 223, 224, 225, 226, 227, 71, 230, 50, 229,
+ 73, 61, 0, 52, 53, 237, 54, 0, 63, 66,
+ 0, 68, 0, 72, 0, 87, 46, 84, 91, 92,
+ 93, 94, 89, 86, 88, 99, 83, 45, 0, 0,
+ 0, 102, 95, 0, 98, 0, 289, 290, 0, 85,
+ 51, 0, 0, 235, 103, 96, 0, 97, 0, 238,
+ 101, 100, 56, 0, 0, 90, 0, 59, 0, 62,
+ 0, 58, 4, 70, 303, 64, 308, 57, 0, 55,
+ 60, 0, 0, 13, 304, 0, 15, 14, 0, 0,
+ 0, 0, 16, 11, 65, 0, 67, 0, 69, 338,
+ 0, 213, 0, 0, 0, 0, 0, 0, 71, 43,
+ 50, 0, 73, 61, 0, 52, 53, 323, 54, 347,
+ 63, 66, 35, 68, 152, 72, 0, 87, 0, 133,
+ 0, 150, 0, 130, 89, 131, 88, 128, 0, 127,
+ 0, 129, 0, 126, 362, 0, 132, 121, 120, 0,
+ 140, 123, 122, 0, 147, 164, 146, 0, 139, 158,
+ 135, 157, 143, 163, 136, 160, 138, 154, 137, 166,
+ 145, 162, 144, 161, 149, 156, 151, 155, 0, 134,
+ 0, 0, 124, 0, 125, 0, 153, 141, 211, 148,
+ 215, 142, 165, 39, 159, 0, 167, 0, 219, 220,
+ 0, 295, 296, 297, 298, 299, 0, 0, 291, 292,
+ 293, 294, 0, 35, 0, 0, 0, 339, 340, 35,
+ 342, 343, 344, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 348, 0, 0, 0, 48, 0, 0, 0,
+ 0, 0, 0, 354, 0, 0, 0, 0, 0, 0,
+ 0, 0, 357, 0, 0, 0, 0, 0, 0, 0,
+ 0, 354, 363, 364, 275, 276, 277, 278, 279, 280,
+ 281, 282, 283, 284, 285, 286, 287, 288, 0, 0,
+ 0, 0, 0, 0, 0, 307, 0, 186, 187, 188,
+ 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
+ 199, 200, 201, 202, 203, 204, 205, 206, 207, 208,
+ 209, 0, 0, 240, 241, 242, 243, 244, 245, 246,
+ 247, 248, 249, 250, 251, 252, 253, 254, 255, 256,
+ 257, 258, 259, 260, 261, 262, 263, 264, 265, 266,
+ 267, 268, 269, 270, 271, 272, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 337, 0, 215, 300, 301, 302, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 349 };
+int yypact[]={
+
+ -130, -1000, 100, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
+ -1000, -95, -229, -1000, -84, -118, -97, -4, -1000, -1000,
+ -42, -125, -298, -1000, -1000, -1000, -299, -1000, -1000, -316,
+ -1000, -1000, -288, -103, -161, -321, -219, -279, -1000, -1000,
+ 125, -1000, 131, -275, -151, -214, -1000, -172, -1000, -301,
+ 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+ 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+ 60, 60, 60, 60, -1000, -1000, -1000, -1000, -1000, -1000,
+ -1000, -1000, -1000, -42, -1000, -1000, -42, -42, -42, -42,
+ -128, -1000, -1000, -1000, -1000, -1000, -42, -42, -42, -42,
+ -42, -42, -42, -42, -303, -1000, -84, -118, -133, -290,
+ -125, -42, -125, -42, -1000, -1000, -1000, -42, 60, 60,
+ 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+ 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+ 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+ 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+ 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+ 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+ 60, 60, -42, -256, -42, -108, -1000, -1000, -1000, -1000,
+ -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
+ -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
+ -219, -1000, -300, -1000, -361, -331, -339, -1000, -1000, -1000,
+ -1000, -131, -195, -157, -137, -162, -177, -219, -112, -1000,
+ -1000, -1000, -125, -292, -303, -182, -308, -265, -1000, -279,
+ -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
+ -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
+ -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
+ -1000, -1000, -1000, -186, -1000, -275, -275, -275, -275, -275,
+ -275, -275, -275, -275, -275, -275, -275, -275, -275, -151,
+ -151, -214, -214, -214, -214, -1000, -1000, -1000, -1000, -1000,
+ -1000, -1000, -1000, -340, -257, -1000, -348, -1000, -310, -1000,
+ -1000, -42, -1000, -42, -1000, -42, -42, -352, -42, -42,
+ -42, -1000, -294, -327, -1000, -1000, -1000, -1000, 60, -1000,
+ -42, -1000, -1000, -1000, -1000, -42, -1000, -1000, -1000, -219,
+ -192, -144, -219, -219, -219, -1000, -343, -1000, -284, -1000,
+ -42, -350, -1000, -318, -255, -1000, -1000, -219, -1000, -144,
+ -42, -42, -1000, -219, -219 };
+int yypgo[]={
+
+ 0, 264, 186, 262, 260, 256, 254, 252, 251, 247,
+ 189, 246, 192, 244, 174, 241, 240, 239, 236, 235,
+ 231, 228, 227, 226, 191, 391, 169, 483, 225, 80,
+ 212, 399, 167, 327, 316, 210, 526, 208, 205, 203,
+ 200, 197, 195, 193, 188, 187, 185, 181, 75, 179,
+ 178, 74, 177 };
+int yyr1[]={
+
+ 0, 1, 2, 2, 3, 3, 3, 3, 3, 8,
+ 9, 9, 10, 10, 10, 7, 11, 11, 12, 12,
+ 13, 6, 15, 4, 16, 16, 5, 21, 17, 22,
+ 22, 22, 14, 14, 18, 18, 23, 23, 19, 19,
+ 20, 20, 25, 25, 24, 24, 26, 26, 27, 27,
+ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+ 27, 28, 28, 28, 29, 29, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 31, 31, 31, 32, 32, 32, 32, 32, 33,
+ 33, 33, 33, 33, 34, 34, 35, 35, 35, 35,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37, 43, 43,
+ 44, 44, 45, 45, 46, 40, 40, 40, 40, 41,
+ 41, 42, 50, 50, 51, 51, 47, 47, 49, 49,
+ 38, 38, 38, 38, 39, 52, 52, 52, 48, 48,
+ 1, 5, 24 };
+int yyr2[]={
+
+ 0, 5, 0, 4, 3, 3, 3, 3, 3, 5,
+ 2, 7, 3, 3, 7, 5, 2, 7, 3, 3,
+ 1, 7, 1, 13, 1, 3, 13, 1, 13, 1,
+ 3, 7, 3, 7, 1, 9, 3, 3, 1, 7,
+ 1, 7, 1, 2, 2, 7, 2, 7, 2, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 2, 7, 11, 2, 7, 2, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 2, 7, 7, 2, 7, 7, 7, 7, 2,
+ 7, 7, 7, 7, 2, 7, 2, 7, 7, 7,
+ 2, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 5, 3, 3, 5, 7, 7,
+ 7, 9, 7, 9, 9, 7, 5, 5, 5, 9,
+ 5, 9, 5, 9, 5, 3, 5, 5, 9, 9,
+ 13, 13, 2, 7, 7, 7, 3, 7, 3, 7,
+ 3, 3, 3, 3, 13, 3, 3, 3, 2, 7,
+ 6, 8, 2 };
+int yychk[]={
+
+ -1000, -1, -2, 256, 262, -3, -4, -5, -6, -7,
+ -8, 283, -17, 273, 277, 276, 282, -2, 257, 363,
+ 256, -13, -11, -12, 257, 260, -9, -10, 257, 260,
+ 257, 262, -15, -18, -20, -25, -24, -26, 256, -27,
+ -28, -29, -30, -31, -32, -33, -34, -35, -36, -37,
+ 340, 280, 345, 346, 348, 309, 292, 307, 301, 297,
+ 310, 343, 299, 350, 305, 324, 351, 326, 353, 328,
+ 303, 338, 355, 342, -38, -39, -40, -41, -42, -43,
+ -44, -45, -46, 266, 257, 279, 263, 357, 366, 364,
+ 295, 258, 259, 260, 261, 272, 285, 287, 274, 265,
+ 291, 290, 271, 284, -14, 257, 360, 360, 362, -21,
+ 357, -19, -23, 275, 278, 286, 270, 363, 295, 338,
+ 313, 312, 317, 316, 347, 349, 308, 304, 302, 306,
+ 298, 300, 311, 294, 344, 325, 329, 333, 331, 323,
+ 315, 352, 356, 327, 337, 335, 321, 319, 354, 339,
+ 296, 341, 289, 345, 326, 336, 334, 320, 318, 353,
+ 324, 332, 330, 322, 314, 351, 328, 355, 346, 348,
+ 301, 307, 303, 305, 297, 299, 310, 293, 343, 342,
+ 340, 292, 364, 366, 357, 309, -36, -36, -36, -36,
+ -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
+ -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
+ -24, -25, -47, -25, -48, -25, -47, 272, 257, -25,
+ -25, -24, -24, -24, -24, -24, -24, -24, 360, -12,
+ -10, 258, 357, -16, -14, -20, -14, -24, -20, -26,
+ -27, -27, -27, -27, -27, -27, -27, -27, -27, -27,
+ -27, -27, -27, -27, -27, -27, -27, -27, -27, -27,
+ -27, -27, -27, -27, -27, -27, -27, -27, -27, -27,
+ -27, -27, -27, -29, -29, -31, -31, -31, -31, -31,
+ -31, -31, -31, -31, -31, -31, -31, -31, -31, -32,
+ -32, -33, -33, -33, -33, -34, -34, -34, -34, -34,
+ -36, -36, -36, -47, -24, 367, -49, -25, -47, 257,
+ 358, 360, 367, 363, 365, 268, 288, 281, 268, 268,
+ 268, 257, -22, -14, 358, 270, 363, 363, 264, 365,
+ -52, 362, 359, 361, 367, 360, 358, -25, -48, -24,
+ -24, 366, -24, -24, -24, 358, 364, -29, -24, -25,
+ 269, -50, -51, 267, -24, 365, 365, -24, 367, 363,
+ 362, 362, -51, -24, -24 };
+int yydef[]={
+
+ -2, -2, 0, 2, 1, 3, 4, 5, 6, 7,
+ 8, 0, 0, 20, 0, 0, 0, 0, 22, 34,
+ -2, 0, 15, 16, 18, 19, 9, 10, 12, 13,
+ 27, 200, 0, 38, 0, 0, 43, 44, 202, 46,
+ 48, 81, 84, 86, 101, 104, 109, 114, 116, 120,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 145, 146, 147, 148, 149, 150,
+ 151, 152, 153, 0, 155, 156, -2, -2, -2, -2,
+ 0, 190, 191, 192, 193, 175, -2, -2, 0, 0,
+ 0, 0, 0, 0, 21, 32, 0, 0, 0, 0,
+ 24, -2, 0, 0, 36, 37, 201, -2, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, -2, -2, -2, 0, 121, 122, 123, 124,
+ 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
+ 135, 136, 137, 138, 139, 140, 141, 142, 143, 144,
+ 154, 157, 0, 186, 0, 198, 0, 166, 167, 176,
+ 177, 43, 0, 0, 168, 170, 172, 174, 0, 17,
+ 11, 14, 29, 0, 25, 0, 0, 0, 41, 45,
+ 47, 49, 50, 51, 52, 53, 54, 55, 56, 57,
+ 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
+ 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
+ 78, 79, 80, 82, 85, 87, 88, 89, 90, 91,
+ 92, 93, 94, 95, 96, 97, 98, 99, 100, 102,
+ 103, 105, 106, 107, 108, 110, 111, 112, 113, 115,
+ 117, 118, 119, 0, 43, 162, 0, 188, 0, 165,
+ 158, -2, 159, -2, 160, 0, 0, 0, 0, 0,
+ 0, 33, 0, 30, 23, 26, 35, 39, 0, 161,
+ 0, 195, 196, 197, 163, -2, 164, 187, 199, 178,
+ 179, 0, 169, 171, 173, 28, 0, 83, 0, 189,
+ 0, 0, 182, 0, 0, 31, 194, 180, 181, 0,
+ 0, 0, 183, 184, 185 };
+typedef struct { char *t_name; int t_val; } yytoktype;
+#ifndef YYDEBUG
+# define YYDEBUG 0 /* don't allow debugging */
+#endif
+
+#if YYDEBUG
+
+yytoktype yytoks[] =
+{
+ "IDENT", 257,
+ "INTLIT", 258,
+ "REALLIT", 259,
+ "STRINGLIT", 260,
+ "CSETLIT", 261,
+ "EOFX", 262,
+ "BREAK", 263,
+ "BY", 264,
+ "CASE", 265,
+ "CREATE", 266,
+ "DEFAULT", 267,
+ "DO", 268,
+ "ELSE", 269,
+ "END", 270,
+ "EVERY", 271,
+ "FAIL", 272,
+ "GLOBAL", 273,
+ "IF", 274,
+ "INITIAL", 275,
+ "INVOCABLE", 276,
+ "LINK", 277,
+ "LOCAL", 278,
+ "NEXT", 279,
+ "NOT", 280,
+ "OF", 281,
+ "PROCEDURE", 282,
+ "RECORD", 283,
+ "REPEAT", 284,
+ "RETURN", 285,
+ "STATIC", 286,
+ "SUSPEND", 287,
+ "THEN", 288,
+ "TO", 289,
+ "UNTIL", 290,
+ "WHILE", 291,
+ "BANG", 292,
+ "MOD", 293,
+ "AUGMOD", 294,
+ "AND", 295,
+ "AUGAND", 296,
+ "STAR", 297,
+ "AUGSTAR", 298,
+ "INTER", 299,
+ "AUGINTER", 300,
+ "PLUS", 301,
+ "AUGPLUS", 302,
+ "UNION", 303,
+ "AUGUNION", 304,
+ "MINUS", 305,
+ "AUGMINUS", 306,
+ "DIFF", 307,
+ "AUGDIFF", 308,
+ "DOT", 309,
+ "SLASH", 310,
+ "AUGSLASH", 311,
+ "ASSIGN", 312,
+ "SWAP", 313,
+ "NMLT", 314,
+ "AUGNMLT", 315,
+ "REVASSIGN", 316,
+ "REVSWAP", 317,
+ "SLT", 318,
+ "AUGSLT", 319,
+ "SLE", 320,
+ "AUGSLE", 321,
+ "NMLE", 322,
+ "AUGNMLE", 323,
+ "NMEQ", 324,
+ "AUGNMEQ", 325,
+ "SEQ", 326,
+ "AUGSEQ", 327,
+ "EQUIV", 328,
+ "AUGEQUIV", 329,
+ "NMGT", 330,
+ "AUGNMGT", 331,
+ "NMGE", 332,
+ "AUGNMGE", 333,
+ "SGT", 334,
+ "AUGSGT", 335,
+ "SGE", 336,
+ "AUGSGE", 337,
+ "QMARK", 338,
+ "AUGQMARK", 339,
+ "AT", 340,
+ "AUGAT", 341,
+ "BACKSLASH", 342,
+ "CARET", 343,
+ "AUGCARET", 344,
+ "BAR", 345,
+ "CONCAT", 346,
+ "AUGCONCAT", 347,
+ "LCONCAT", 348,
+ "AUGLCONCAT", 349,
+ "TILDE", 350,
+ "NMNE", 351,
+ "AUGNMNE", 352,
+ "SNE", 353,
+ "AUGSNE", 354,
+ "NEQUIV", 355,
+ "AUGNEQUIV", 356,
+ "LPAREN", 357,
+ "RPAREN", 358,
+ "PCOLON", 359,
+ "COMMA", 360,
+ "MCOLON", 361,
+ "COLON", 362,
+ "SEMICOL", 363,
+ "LBRACK", 364,
+ "RBRACK", 365,
+ "LBRACE", 366,
+ "RBRACE", 367,
+ "-unknown-", -1 /* ends search */
+};
+
+char * yyreds[] =
+{
+ "-no such reduction-",
+ "program : decls EOFX",
+ "decls : /* empty */",
+ "decls : decls decl",
+ "decl : record",
+ "decl : proc",
+ "decl : global",
+ "decl : link",
+ "decl : invocable",
+ "invocable : INVOCABLE invoclist",
+ "invoclist : invocop",
+ "invoclist : invoclist COMMA invocop",
+ "invocop : IDENT",
+ "invocop : STRINGLIT",
+ "invocop : STRINGLIT COLON INTLIT",
+ "link : LINK lnklist",
+ "lnklist : lnkfile",
+ "lnklist : lnklist COMMA lnkfile",
+ "lnkfile : IDENT",
+ "lnkfile : STRINGLIT",
+ "global : GLOBAL",
+ "global : GLOBAL idlist",
+ "record : RECORD IDENT",
+ "record : RECORD IDENT LPAREN fldlist RPAREN",
+ "fldlist : /* empty */",
+ "fldlist : idlist",
+ "proc : prochead SEMICOL locals initial procbody END",
+ "prochead : PROCEDURE IDENT",
+ "prochead : PROCEDURE IDENT LPAREN arglist RPAREN",
+ "arglist : /* empty */",
+ "arglist : idlist",
+ "arglist : idlist LBRACK RBRACK",
+ "idlist : IDENT",
+ "idlist : idlist COMMA IDENT",
+ "locals : /* empty */",
+ "locals : locals retention idlist SEMICOL",
+ "retention : LOCAL",
+ "retention : STATIC",
+ "initial : /* empty */",
+ "initial : INITIAL expr SEMICOL",
+ "procbody : /* empty */",
+ "procbody : nexpr SEMICOL procbody",
+ "nexpr : /* empty */",
+ "nexpr : expr",
+ "expr : expr1a",
+ "expr : expr AND expr1a",
+ "expr1a : expr1",
+ "expr1a : expr1a QMARK expr1",
+ "expr1 : expr2",
+ "expr1 : expr2 SWAP expr1",
+ "expr1 : expr2 ASSIGN expr1",
+ "expr1 : expr2 REVSWAP expr1",
+ "expr1 : expr2 REVASSIGN expr1",
+ "expr1 : expr2 AUGCONCAT expr1",
+ "expr1 : expr2 AUGLCONCAT expr1",
+ "expr1 : expr2 AUGDIFF expr1",
+ "expr1 : expr2 AUGUNION expr1",
+ "expr1 : expr2 AUGPLUS expr1",
+ "expr1 : expr2 AUGMINUS expr1",
+ "expr1 : expr2 AUGSTAR expr1",
+ "expr1 : expr2 AUGINTER expr1",
+ "expr1 : expr2 AUGSLASH expr1",
+ "expr1 : expr2 AUGMOD expr1",
+ "expr1 : expr2 AUGCARET expr1",
+ "expr1 : expr2 AUGNMEQ expr1",
+ "expr1 : expr2 AUGEQUIV expr1",
+ "expr1 : expr2 AUGNMGE expr1",
+ "expr1 : expr2 AUGNMGT expr1",
+ "expr1 : expr2 AUGNMLE expr1",
+ "expr1 : expr2 AUGNMLT expr1",
+ "expr1 : expr2 AUGNMNE expr1",
+ "expr1 : expr2 AUGNEQUIV expr1",
+ "expr1 : expr2 AUGSEQ expr1",
+ "expr1 : expr2 AUGSGE expr1",
+ "expr1 : expr2 AUGSGT expr1",
+ "expr1 : expr2 AUGSLE expr1",
+ "expr1 : expr2 AUGSLT expr1",
+ "expr1 : expr2 AUGSNE expr1",
+ "expr1 : expr2 AUGQMARK expr1",
+ "expr1 : expr2 AUGAND expr1",
+ "expr1 : expr2 AUGAT expr1",
+ "expr2 : expr3",
+ "expr2 : expr2 TO expr3",
+ "expr2 : expr2 TO expr3 BY expr3",
+ "expr3 : expr4",
+ "expr3 : expr4 BAR expr3",
+ "expr4 : expr5",
+ "expr4 : expr4 SEQ expr5",
+ "expr4 : expr4 SGE expr5",
+ "expr4 : expr4 SGT expr5",
+ "expr4 : expr4 SLE expr5",
+ "expr4 : expr4 SLT expr5",
+ "expr4 : expr4 SNE expr5",
+ "expr4 : expr4 NMEQ expr5",
+ "expr4 : expr4 NMGE expr5",
+ "expr4 : expr4 NMGT expr5",
+ "expr4 : expr4 NMLE expr5",
+ "expr4 : expr4 NMLT expr5",
+ "expr4 : expr4 NMNE expr5",
+ "expr4 : expr4 EQUIV expr5",
+ "expr4 : expr4 NEQUIV expr5",
+ "expr5 : expr6",
+ "expr5 : expr5 CONCAT expr6",
+ "expr5 : expr5 LCONCAT expr6",
+ "expr6 : expr7",
+ "expr6 : expr6 PLUS expr7",
+ "expr6 : expr6 DIFF expr7",
+ "expr6 : expr6 UNION expr7",
+ "expr6 : expr6 MINUS expr7",
+ "expr7 : expr8",
+ "expr7 : expr7 STAR expr8",
+ "expr7 : expr7 INTER expr8",
+ "expr7 : expr7 SLASH expr8",
+ "expr7 : expr7 MOD expr8",
+ "expr8 : expr9",
+ "expr8 : expr9 CARET expr8",
+ "expr9 : expr10",
+ "expr9 : expr9 BACKSLASH expr10",
+ "expr9 : expr9 AT expr10",
+ "expr9 : expr9 BANG expr10",
+ "expr10 : expr11",
+ "expr10 : AT expr10",
+ "expr10 : NOT expr10",
+ "expr10 : BAR expr10",
+ "expr10 : CONCAT expr10",
+ "expr10 : LCONCAT expr10",
+ "expr10 : DOT expr10",
+ "expr10 : BANG expr10",
+ "expr10 : DIFF expr10",
+ "expr10 : PLUS expr10",
+ "expr10 : STAR expr10",
+ "expr10 : SLASH expr10",
+ "expr10 : CARET expr10",
+ "expr10 : INTER expr10",
+ "expr10 : TILDE expr10",
+ "expr10 : MINUS expr10",
+ "expr10 : NMEQ expr10",
+ "expr10 : NMNE expr10",
+ "expr10 : SEQ expr10",
+ "expr10 : SNE expr10",
+ "expr10 : EQUIV expr10",
+ "expr10 : UNION expr10",
+ "expr10 : QMARK expr10",
+ "expr10 : NEQUIV expr10",
+ "expr10 : BACKSLASH expr10",
+ "expr11 : literal",
+ "expr11 : section",
+ "expr11 : return",
+ "expr11 : if",
+ "expr11 : case",
+ "expr11 : while",
+ "expr11 : until",
+ "expr11 : every",
+ "expr11 : repeat",
+ "expr11 : CREATE expr",
+ "expr11 : IDENT",
+ "expr11 : NEXT",
+ "expr11 : BREAK nexpr",
+ "expr11 : LPAREN exprlist RPAREN",
+ "expr11 : LBRACE compound RBRACE",
+ "expr11 : LBRACK exprlist RBRACK",
+ "expr11 : expr11 LBRACK exprlist RBRACK",
+ "expr11 : expr11 LBRACE RBRACE",
+ "expr11 : expr11 LBRACE pdcolist RBRACE",
+ "expr11 : expr11 LPAREN exprlist RPAREN",
+ "expr11 : expr11 DOT IDENT",
+ "expr11 : AND FAIL",
+ "expr11 : AND IDENT",
+ "while : WHILE expr",
+ "while : WHILE expr DO expr",
+ "until : UNTIL expr",
+ "until : UNTIL expr DO expr",
+ "every : EVERY expr",
+ "every : EVERY expr DO expr",
+ "repeat : REPEAT expr",
+ "return : FAIL",
+ "return : RETURN nexpr",
+ "return : SUSPEND nexpr",
+ "return : SUSPEND expr DO expr",
+ "if : IF expr THEN expr",
+ "if : IF expr THEN expr ELSE expr",
+ "case : CASE expr OF LBRACE caselist RBRACE",
+ "caselist : cclause",
+ "caselist : caselist SEMICOL cclause",
+ "cclause : DEFAULT COLON expr",
+ "cclause : expr COLON expr",
+ "exprlist : nexpr",
+ "exprlist : exprlist COMMA nexpr",
+ "pdcolist : nexpr",
+ "pdcolist : pdcolist COMMA nexpr",
+ "literal : INTLIT",
+ "literal : REALLIT",
+ "literal : STRINGLIT",
+ "literal : CSETLIT",
+ "section : expr11 LBRACK expr sectop expr RBRACK",
+ "sectop : COLON",
+ "sectop : PCOLON",
+ "sectop : MCOLON",
+ "compound : nexpr",
+ "compound : nexpr SEMICOL compound",
+ "program : error decls EOFX",
+ "proc : prochead error procbody END",
+ "expr : error",
+};
+#endif
+#line 1 "/usr/lib/yaccpar"
+/* @(#)yaccpar 1.10 89/04/04 SMI; from S5R3 1.10 */
+
+/*
+** Skeleton parser driver for yacc output
+*/
+
+/*
+** yacc user known macros and defines
+*/
+#define YYERROR goto yyerrlab
+#define YYACCEPT { free(yys); free(yyv); return(0); }
+#define YYABORT { free(yys); free(yyv); return(1); }
+#define YYBACKUP( newtoken, newvalue )\
+{\
+ if ( yychar >= 0 || ( yyr2[ yytmp ] >> 1 ) != 1 )\
+ {\
+ tsyserr("parser: syntax error - cannot backup" );\
+ goto yyerrlab;\
+ }\
+ yychar = newtoken;\
+ yystate = *yyps;\
+ yylval = newvalue;\
+ goto yynewstate;\
+}
+#define YYRECOVERING() (!!yyerrflag)
+#ifndef YYDEBUG
+# define YYDEBUG 1 /* make debugging available */
+#endif
+
+/*
+** user known globals
+*/
+int yydebug; /* set to 1 to get debugging */
+
+/*
+** driver internal defines
+*/
+#define YYFLAG (-1000)
+
+/*
+** static variables used by the parser
+*/
+static YYSTYPE *yyv; /* value stack */
+static int *yys; /* state stack */
+
+static YYSTYPE *yypv; /* top of value stack */
+static int *yyps; /* top of state stack */
+
+static int yystate; /* current state */
+static int yytmp; /* extra var (lasts between blocks) */
+
+int yynerrs; /* number of errors */
+
+int yyerrflag; /* error recovery flag */
+int yychar; /* current input token number */
+
+
+/*
+** yyparse - return 0 if worked, 1 if syntax error not recovered from
+*/
+int
+yyparse()
+{
+ register YYSTYPE *yypvt; /* top of value stack for $vars */
+ unsigned yymaxdepth = YYMAXDEPTH;
+
+ /*
+ ** Initialize externals - yyparse may be called more than once
+ */
+ yyv = (YYSTYPE*)malloc(yymaxdepth*sizeof(YYSTYPE));
+ yys = (int*)malloc(yymaxdepth*sizeof(int));
+ if (!yyv || !yys)
+ {
+ tsyserr("parser: out of memory" );
+ return(1);
+ }
+ yypv = &yyv[-1];
+ yyps = &yys[-1];
+ yystate = 0;
+ yytmp = 0;
+ yynerrs = 0;
+ yyerrflag = 0;
+ yychar = -1;
+
+ goto yystack;
+ {
+ register YYSTYPE *yy_pv; /* top of value stack */
+ register int *yy_ps; /* top of state stack */
+ register int yy_state; /* current state */
+ register int yy_n; /* internal state number info */
+
+ /*
+ ** get globals into registers.
+ ** branch to here only if YYBACKUP was called.
+ */
+ yynewstate:
+ yy_pv = yypv;
+ yy_ps = yyps;
+ yy_state = yystate;
+ goto yy_newstate;
+
+ /*
+ ** get globals into registers.
+ ** either we just started, or we just finished a reduction
+ */
+ yystack:
+ yy_pv = yypv;
+ yy_ps = yyps;
+ yy_state = yystate;
+
+ /*
+ ** top of for (;;) loop while no reductions done
+ */
+ yy_stack:
+ /*
+ ** put a state and value onto the stacks
+ */
+#if YYDEBUG
+ /*
+ ** if debugging, look up token value in list of value vs.
+ ** name pairs. 0 and negative (-1) are special values.
+ ** Note: linear search is used since time is not a real
+ ** consideration while debugging.
+ */
+ if ( yydebug )
+ {
+ register int yy_i;
+
+ (void)printf( "State %d, token ", yy_state );
+ if ( yychar == 0 )
+ (void)printf( "end-of-file\n" );
+ else if ( yychar < 0 )
+ (void)printf( "-none-\n" );
+ else
+ {
+ for ( yy_i = 0; yytoks[yy_i].t_val >= 0;
+ yy_i++ )
+ {
+ if ( yytoks[yy_i].t_val == yychar )
+ break;
+ }
+ (void)printf( "%s\n", yytoks[yy_i].t_name );
+ }
+ }
+#endif
+ if ( ++yy_ps >= &yys[ yymaxdepth ] ) /* room on stack? */
+ {
+ /*
+ ** reallocate and recover. Note that pointers
+ ** have to be reset, or bad things will happen
+ */
+ int yyps_index = (yy_ps - yys);
+ int yypv_index = (yy_pv - yyv);
+ int yypvt_index = (yypvt - yyv);
+ yymaxdepth += YYMAXDEPTH;
+ yyv = (YYSTYPE*)realloc((char*)yyv,
+ yymaxdepth * sizeof(YYSTYPE));
+ yys = (int*)realloc((char*)yys,
+ yymaxdepth * sizeof(int));
+ if (!yyv || !yys)
+ {
+ tsyserr("parse stack overflow" );
+ return(1);
+ }
+ yy_ps = yys + yyps_index;
+ yy_pv = yyv + yypv_index;
+ yypvt = yyv + yypvt_index;
+ }
+ *yy_ps = yy_state;
+ *++yy_pv = yyval;
+
+ /*
+ ** we have a new state - find out what to do
+ */
+ yy_newstate:
+ if ( ( yy_n = yypact[ yy_state ] ) <= YYFLAG )
+ goto yydefault; /* simple state */
+#if YYDEBUG
+ /*
+ ** if debugging, need to mark whether new token grabbed
+ */
+ yytmp = yychar < 0;
+#endif
+ if ( ( yychar < 0 ) && ( ( yychar = yylex() ) < 0 ) )
+ yychar = 0; /* reached EOF */
+#if YYDEBUG
+ if ( yydebug && yytmp )
+ {
+ register int yy_i;
+
+ (void)printf( "Received token " );
+ if ( yychar == 0 )
+ (void)printf( "end-of-file\n" );
+ else if ( yychar < 0 )
+ (void)printf( "-none-\n" );
+ else
+ {
+ for ( yy_i = 0; yytoks[yy_i].t_val >= 0;
+ yy_i++ )
+ {
+ if ( yytoks[yy_i].t_val == yychar )
+ break;
+ }
+ (void)printf( "%s\n", yytoks[yy_i].t_name );
+ }
+ }
+#endif
+ if ( ( ( yy_n += yychar ) < 0 ) || ( yy_n >= YYLAST ) )
+ goto yydefault;
+ if ( yychk[ yy_n = yyact[ yy_n ] ] == yychar ) /*valid shift*/
+ {
+ yychar = -1;
+ yyval = yylval;
+ yy_state = yy_n;
+ if ( yyerrflag > 0 )
+ yyerrflag--;
+ goto yy_stack;
+ }
+
+ yydefault:
+ if ( ( yy_n = yydef[ yy_state ] ) == -2 )
+ {
+#if YYDEBUG
+ yytmp = yychar < 0;
+#endif
+ if ( ( yychar < 0 ) && ( ( yychar = yylex() ) < 0 ) )
+ yychar = 0; /* reached EOF */
+#if YYDEBUG
+ if ( yydebug && yytmp )
+ {
+ register int yy_i;
+
+ (void)printf( "Received token " );
+ if ( yychar == 0 )
+ (void)printf( "end-of-file\n" );
+ else if ( yychar < 0 )
+ (void)printf( "-none-\n" );
+ else
+ {
+ for ( yy_i = 0;
+ yytoks[yy_i].t_val >= 0;
+ yy_i++ )
+ {
+ if ( yytoks[yy_i].t_val
+ == yychar )
+ {
+ break;
+ }
+ }
+ (void)printf( "%s\n", yytoks[yy_i].t_name );
+ }
+ }
+#endif
+ /*
+ ** look through exception table
+ */
+ {
+ register int *yyxi = yyexca;
+
+ while ( ( *yyxi != -1 ) ||
+ ( yyxi[1] != yy_state ) )
+ {
+ yyxi += 2;
+ }
+ while ( ( *(yyxi += 2) >= 0 ) &&
+ ( *yyxi != yychar ) )
+ ;
+ if ( ( yy_n = yyxi[1] ) < 0 )
+ YYACCEPT;
+ }
+ }
+
+ /*
+ ** check for syntax error
+ */
+ if ( yy_n == 0 ) /* have an error */
+ {
+ /* no worry about speed here! */
+ switch ( yyerrflag )
+ {
+ case 0: /* new error */
+ yyerror(yychar, yylval, yy_state );
+ goto skip_init;
+ yyerrlab:
+ /*
+ ** get globals into registers.
+ ** we have a user generated syntax type error
+ */
+ yy_pv = yypv;
+ yy_ps = yyps;
+ yy_state = yystate;
+ yynerrs++;
+ skip_init:
+ case 1:
+ case 2: /* incompletely recovered error */
+ /* try again... */
+ yyerrflag = 3;
+ /*
+ ** find state where "error" is a legal
+ ** shift action
+ */
+ while ( yy_ps >= yys )
+ {
+ yy_n = yypact[ *yy_ps ] + YYERRCODE;
+ if ( yy_n >= 0 && yy_n < YYLAST &&
+ yychk[yyact[yy_n]] == YYERRCODE) {
+ /*
+ ** simulate shift of "error"
+ */
+ yy_state = yyact[ yy_n ];
+ goto yy_stack;
+ }
+ /*
+ ** current state has no shift on
+ ** "error", pop stack
+ */
+#if YYDEBUG
+# define _POP_ "Error recovery pops state %d, uncovers state %d\n"
+ if ( yydebug )
+ (void)printf( _POP_, *yy_ps,
+ yy_ps[-1] );
+# undef _POP_
+#endif
+ yy_ps--;
+ yy_pv--;
+ }
+ /*
+ ** there is no state on stack with "error" as
+ ** a valid shift. give up.
+ */
+ YYABORT;
+ case 3: /* no shift yet; eat a token */
+#if YYDEBUG
+ /*
+ ** if debugging, look up token in list of
+ ** pairs. 0 and negative shouldn't occur,
+ ** but since timing doesn't matter when
+ ** debugging, it doesn't hurt to leave the
+ ** tests here.
+ */
+ if ( yydebug )
+ {
+ register int yy_i;
+
+ (void)printf( "Error recovery discards " );
+ if ( yychar == 0 )
+ (void)printf( "token end-of-file\n" );
+ else if ( yychar < 0 )
+ (void)printf( "token -none-\n" );
+ else
+ {
+ for ( yy_i = 0;
+ yytoks[yy_i].t_val >= 0;
+ yy_i++ )
+ {
+ if ( yytoks[yy_i].t_val
+ == yychar )
+ {
+ break;
+ }
+ }
+ (void)printf( "token %s\n",
+ yytoks[yy_i].t_name );
+ }
+ }
+#endif
+ if ( yychar == 0 ) /* reached EOF. quit */
+ YYABORT;
+ yychar = -1;
+ goto yy_newstate;
+ }
+ }/* end if ( yy_n == 0 ) */
+ /*
+ ** reduction by production yy_n
+ ** put stack tops, etc. so things right after switch
+ */
+#if YYDEBUG
+ /*
+ ** if debugging, print the string that is the user's
+ ** specification of the reduction which is just about
+ ** to be done.
+ */
+ if ( yydebug )
+ (void)printf( "Reduce by (%d) \"%s\"\n",
+ yy_n, yyreds[ yy_n ] );
+#endif
+ yytmp = yy_n; /* value to switch over */
+ yypvt = yy_pv; /* $vars top of value stack */
+ /*
+ ** Look in goto table for next state
+ ** Sorry about using yy_state here as temporary
+ ** register variable, but why not, if it works...
+ ** If yyr2[ yy_n ] doesn't have the low order bit
+ ** set, then there is no action to be done for
+ ** this reduction. So, no saving & unsaving of
+ ** registers done. The only difference between the
+ ** code just after the if and the body of the if is
+ ** the goto yy_stack in the body. This way the test
+ ** can be made before the choice of what to do is needed.
+ */
+ {
+ /* length of production doubled with extra bit */
+ register int yy_len = yyr2[ yy_n ];
+
+ if ( !( yy_len & 01 ) )
+ {
+ yy_len >>= 1;
+ yyval = ( yy_pv -= yy_len )[1]; /* $$ = $1 */
+ yy_state = yypgo[ yy_n = yyr1[ yy_n ] ] +
+ *( yy_ps -= yy_len ) + 1;
+ if ( yy_state >= YYLAST ||
+ yychk[ yy_state =
+ yyact[ yy_state ] ] != -yy_n )
+ {
+ yy_state = yyact[ yypgo[ yy_n ] ];
+ }
+ goto yy_stack;
+ }
+ yy_len >>= 1;
+ yyval = ( yy_pv -= yy_len )[1]; /* $$ = $1 */
+ yy_state = yypgo[ yy_n = yyr1[ yy_n ] ] +
+ *( yy_ps -= yy_len ) + 1;
+ if ( yy_state >= YYLAST ||
+ yychk[ yy_state = yyact[ yy_state ] ] != -yy_n )
+ {
+ yy_state = yyact[ yypgo[ yy_n ] ];
+ }
+ }
+ /* save until reenter driver code */
+ yystate = yy_state;
+ yyps = yy_ps;
+ yypv = yy_pv;
+ }
+ /*
+ ** code supplied by user is placed in this switch
+ */
+ switch( yytmp )
+ {
+
+case 1:
+# line 177 "cgram.g"
+{;} break;
+case 4:
+# line 182 "cgram.g"
+{;} break;
+case 5:
+# line 183 "cgram.g"
+{proc_lst->tree = yypvt[-0] ;} break;
+case 6:
+# line 184 "cgram.g"
+{;} break;
+case 7:
+# line 185 "cgram.g"
+{;} break;
+case 8:
+# line 186 "cgram.g"
+{;} break;
+case 9:
+# line 188 "cgram.g"
+{;} break;
+case 11:
+# line 191 "cgram.g"
+{;} break;
+case 12:
+# line 193 "cgram.g"
+{invoc_grp(Str0(yypvt[-0])); ;} break;
+case 13:
+# line 194 "cgram.g"
+{invocbl(yypvt[-0], -1); ;} break;
+case 14:
+# line 195 "cgram.g"
+{invocbl(yypvt[-2], atoi(Str0(yypvt[-0]))); ;} break;
+case 15:
+# line 197 "cgram.g"
+{;} break;
+case 17:
+# line 200 "cgram.g"
+{;} break;
+case 18:
+# line 202 "cgram.g"
+{lnkdcl(Str0(yypvt[-0])); ;} break;
+case 19:
+# line 203 "cgram.g"
+{lnkdcl(Str0(yypvt[-0])); ;} break;
+case 20:
+# line 205 "cgram.g"
+{idflag = F_Global ;} break;
+case 21:
+# line 205 "cgram.g"
+{;} break;
+case 22:
+# line 207 "cgram.g"
+{init_rec(Str0(yypvt[-0])); idflag = F_Field ;} break;
+case 23:
+# line 207 "cgram.g"
+{
+ ;
+ } break;
+case 24:
+# line 211 "cgram.g"
+{;} break;
+case 25:
+# line 212 "cgram.g"
+{;} break;
+case 26:
+# line 214 "cgram.g"
+{
+ yyval = tree6(N_Proc,yypvt[-5],yypvt[-5],yypvt[-2],yypvt[-1],yypvt[-0]) ;
+ } break;
+case 27:
+# line 218 "cgram.g"
+{init_proc(Str0(yypvt[-0])); idflag = F_Argument ;} break;
+case 28:
+# line 218 "cgram.g"
+{
+ ;
+ } break;
+case 29:
+# line 222 "cgram.g"
+{;} break;
+case 30:
+# line 223 "cgram.g"
+{;} break;
+case 31:
+# line 224 "cgram.g"
+{proc_lst->nargs = -proc_lst->nargs ;} break;
+case 32:
+# line 227 "cgram.g"
+{
+ install(Str0(yypvt[-0]),idflag) ;
+ } break;
+case 33:
+# line 230 "cgram.g"
+{
+ install(Str0(yypvt[-0]),idflag) ;
+ } break;
+case 34:
+# line 234 "cgram.g"
+{;} break;
+case 35:
+# line 235 "cgram.g"
+{;} break;
+case 36:
+# line 237 "cgram.g"
+{idflag = F_Dynamic ;} break;
+case 37:
+# line 238 "cgram.g"
+{idflag = F_Static ;} break;
+case 38:
+# line 240 "cgram.g"
+{yyval = tree1(N_Empty) ;} break;
+case 39:
+# line 241 "cgram.g"
+{yyval = yypvt[-1] ;} break;
+case 40:
+# line 243 "cgram.g"
+{yyval = tree1(N_Empty) ;} break;
+case 41:
+# line 244 "cgram.g"
+{yyval = tree4(N_Slist,yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 42:
+# line 246 "cgram.g"
+{yyval = tree1(N_Empty) ;} break;
+case 45:
+# line 250 "cgram.g"
+{yyval = binary_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 47:
+# line 253 "cgram.g"
+{yyval = tree5(N_Scan,yypvt[-1],yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 49:
+# line 256 "cgram.g"
+{yyval = binary_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 50:
+# line 257 "cgram.g"
+{yyval = binary_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 51:
+# line 258 "cgram.g"
+{yyval = binary_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 52:
+# line 259 "cgram.g"
+{yyval = binary_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 53:
+# line 260 "cgram.g"
+{yyval = aug_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 54:
+# line 261 "cgram.g"
+{yyval = aug_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 55:
+# line 262 "cgram.g"
+{yyval = aug_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 56:
+# line 263 "cgram.g"
+{yyval = aug_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 57:
+# line 264 "cgram.g"
+{yyval = aug_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 58:
+# line 265 "cgram.g"
+{yyval = aug_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 59:
+# line 266 "cgram.g"
+{yyval = aug_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 60:
+# line 267 "cgram.g"
+{yyval = aug_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 61:
+# line 268 "cgram.g"
+{yyval = aug_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 62:
+# line 269 "cgram.g"
+{yyval = aug_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 63:
+# line 270 "cgram.g"
+{yyval = aug_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 64:
+# line 271 "cgram.g"
+{yyval = aug_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 65:
+# line 272 "cgram.g"
+{yyval = aug_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 66:
+# line 273 "cgram.g"
+{yyval = aug_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 67:
+# line 274 "cgram.g"
+{yyval = aug_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 68:
+# line 275 "cgram.g"
+{yyval = aug_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 69:
+# line 276 "cgram.g"
+{yyval = aug_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 70:
+# line 277 "cgram.g"
+{yyval = aug_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 71:
+# line 278 "cgram.g"
+{yyval = aug_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 72:
+# line 279 "cgram.g"
+{yyval = aug_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 73:
+# line 280 "cgram.g"
+{yyval = aug_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 74:
+# line 281 "cgram.g"
+{yyval = aug_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 75:
+# line 282 "cgram.g"
+{yyval = aug_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 76:
+# line 283 "cgram.g"
+{yyval = aug_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 77:
+# line 284 "cgram.g"
+{yyval = aug_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 78:
+# line 285 "cgram.g"
+{yyval = tree5(N_Scan,yypvt[-1],yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 79:
+# line 286 "cgram.g"
+{yyval = aug_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 80:
+# line 287 "cgram.g"
+{yyval = tree5(N_Activat,yypvt[-1],yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 82:
+# line 290 "cgram.g"
+{yyval = to_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 83:
+# line 291 "cgram.g"
+{yyval = toby_nd(yypvt[-3],yypvt[-4],yypvt[-2],yypvt[-0]) ;} break;
+case 85:
+# line 294 "cgram.g"
+{yyval = tree4(N_Alt,yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 87:
+# line 297 "cgram.g"
+{yyval = binary_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 88:
+# line 298 "cgram.g"
+{yyval = binary_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 89:
+# line 299 "cgram.g"
+{yyval = binary_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 90:
+# line 300 "cgram.g"
+{yyval = binary_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 91:
+# line 301 "cgram.g"
+{yyval = binary_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 92:
+# line 302 "cgram.g"
+{yyval = binary_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 93:
+# line 303 "cgram.g"
+{yyval = binary_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 94:
+# line 304 "cgram.g"
+{yyval = binary_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 95:
+# line 305 "cgram.g"
+{yyval = binary_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 96:
+# line 306 "cgram.g"
+{yyval = binary_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 97:
+# line 307 "cgram.g"
+{yyval = binary_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 98:
+# line 308 "cgram.g"
+{yyval = binary_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 99:
+# line 309 "cgram.g"
+{yyval = binary_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 100:
+# line 310 "cgram.g"
+{yyval = binary_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 102:
+# line 313 "cgram.g"
+{yyval = binary_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 103:
+# line 314 "cgram.g"
+{yyval = binary_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 105:
+# line 317 "cgram.g"
+{yyval = binary_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 106:
+# line 318 "cgram.g"
+{yyval = binary_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 107:
+# line 319 "cgram.g"
+{yyval = binary_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 108:
+# line 320 "cgram.g"
+{yyval = binary_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 110:
+# line 323 "cgram.g"
+{yyval = binary_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 111:
+# line 324 "cgram.g"
+{yyval = binary_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 112:
+# line 325 "cgram.g"
+{yyval = binary_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 113:
+# line 326 "cgram.g"
+{yyval = binary_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 115:
+# line 329 "cgram.g"
+{yyval = binary_nd(yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 117:
+# line 332 "cgram.g"
+{yyval = tree4(N_Limit,yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 118:
+# line 333 "cgram.g"
+{yyval = tree5(N_Activat,yypvt[-1],yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 119:
+# line 334 "cgram.g"
+{yyval = tree4(N_Apply,yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 121:
+# line 337 "cgram.g"
+{yyval = tree5(N_Activat,yypvt[-1],yypvt[-1],tree1(N_Empty) ,yypvt[-0]) ;} break;
+case 122:
+# line 338 "cgram.g"
+{yyval = tree3(N_Not,yypvt[-0],yypvt[-0]) ;} break;
+case 123:
+# line 339 "cgram.g"
+{yyval = tree3(N_Bar,yypvt[-0],yypvt[-0]) ;} break;
+case 124:
+# line 340 "cgram.g"
+{yyval = tree3(N_Bar,yypvt[-0],yypvt[-0]) ;} break;
+case 125:
+# line 341 "cgram.g"
+{yyval = tree3(N_Bar,yypvt[-0],yypvt[-0]) ;} break;
+case 126:
+# line 342 "cgram.g"
+{yyval = unary_nd(yypvt[-1],yypvt[-0]) ;} break;
+case 127:
+# line 343 "cgram.g"
+{yyval = unary_nd(yypvt[-1],yypvt[-0]) ;} break;
+case 128:
+# line 344 "cgram.g"
+{yyval = MultiUnary(yypvt[-1],yypvt[-0]) ;} break;
+case 129:
+# line 345 "cgram.g"
+{yyval = unary_nd(yypvt[-1],yypvt[-0]) ;} break;
+case 130:
+# line 346 "cgram.g"
+{yyval = unary_nd(yypvt[-1],yypvt[-0]) ;} break;
+case 131:
+# line 347 "cgram.g"
+{yyval = unary_nd(yypvt[-1],yypvt[-0]) ;} break;
+case 132:
+# line 348 "cgram.g"
+{yyval = unary_nd(yypvt[-1],yypvt[-0]) ;} break;
+case 133:
+# line 349 "cgram.g"
+{yyval = MultiUnary(yypvt[-1],yypvt[-0]) ;} break;
+case 134:
+# line 350 "cgram.g"
+{yyval = unary_nd(yypvt[-1],yypvt[-0]) ;} break;
+case 135:
+# line 351 "cgram.g"
+{yyval = unary_nd(yypvt[-1],yypvt[-0]) ;} break;
+case 136:
+# line 352 "cgram.g"
+{yyval = unary_nd(yypvt[-1],yypvt[-0]) ;} break;
+case 137:
+# line 353 "cgram.g"
+{yyval = MultiUnary(yypvt[-1],yypvt[-0]) ;} break;
+case 138:
+# line 354 "cgram.g"
+{yyval = MultiUnary(yypvt[-1],yypvt[-0]) ;} break;
+case 139:
+# line 355 "cgram.g"
+{yyval = MultiUnary(yypvt[-1],yypvt[-0]) ;} break;
+case 140:
+# line 356 "cgram.g"
+{yyval = MultiUnary(yypvt[-1],yypvt[-0]) ;} break;
+case 141:
+# line 357 "cgram.g"
+{yyval = MultiUnary(yypvt[-1],yypvt[-0]) ;} break;
+case 142:
+# line 358 "cgram.g"
+{yyval = unary_nd(yypvt[-1],yypvt[-0]) ;} break;
+case 143:
+# line 359 "cgram.g"
+{yyval = MultiUnary(yypvt[-1],yypvt[-0]) ;} break;
+case 144:
+# line 360 "cgram.g"
+{yyval = unary_nd(yypvt[-1],yypvt[-0]) ;} break;
+case 154:
+# line 371 "cgram.g"
+{yyval = tree3(N_Create,yypvt[-1],yypvt[-0]); proc_lst->has_coexpr = 1; ;} break;
+case 155:
+# line 372 "cgram.g"
+{LSym0(yypvt[-0]) = putloc(Str0(yypvt[-0]),0) ;} break;
+case 156:
+# line 373 "cgram.g"
+{yyval = tree2(N_Next,yypvt[-0]) ;} break;
+case 157:
+# line 374 "cgram.g"
+{yyval = tree3(N_Break,yypvt[-1],yypvt[-0]) ;} break;
+case 158:
+# line 375 "cgram.g"
+{if ((yypvt[-1])->n_type == N_Elist) yyval = invk_nd(yypvt[-2],tree1(N_Empty) ,yypvt[-1]); else yyval = yypvt[-1] ;} break;
+case 159:
+# line 376 "cgram.g"
+{yyval = yypvt[-1] ;} break;
+case 160:
+# line 377 "cgram.g"
+{yyval = list_nd(yypvt[-2],yypvt[-1]) ;} break;
+case 161:
+# line 378 "cgram.g"
+{yyval = buildarray(yypvt[-3],yypvt[-2],yypvt[-1]) ;} break;
+case 162:
+# line 379 "cgram.g"
+{yyval = invk_nd(yypvt[-1],yypvt[-2],list_nd(yypvt[-1],tree1(N_Empty) )) ;} break;
+case 163:
+# line 380 "cgram.g"
+{yyval = invk_nd(yypvt[-2],yypvt[-3],list_nd(yypvt[-2],yypvt[-1])) ;} break;
+case 164:
+# line 381 "cgram.g"
+{yyval = invk_nd(yypvt[-2],yypvt[-3],yypvt[-1]) ;} break;
+case 165:
+# line 382 "cgram.g"
+{yyval = tree4(N_Field,yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 166:
+# line 383 "cgram.g"
+{yyval = key_leaf(yypvt[-1],spec_str("fail")) ;} break;
+case 167:
+# line 384 "cgram.g"
+{yyval = key_leaf(yypvt[-1],Str0(yypvt[-0])) ;} break;
+case 168:
+# line 386 "cgram.g"
+{yyval = tree5(N_Loop,yypvt[-1],yypvt[-1],yypvt[-0],tree1(N_Empty) ) ;} break;
+case 169:
+# line 387 "cgram.g"
+{yyval = tree5(N_Loop,yypvt[-3],yypvt[-3],yypvt[-2],yypvt[-0]) ;} break;
+case 170:
+# line 389 "cgram.g"
+{yyval = tree5(N_Loop,yypvt[-1],yypvt[-1],yypvt[-0],tree1(N_Empty) ) ;} break;
+case 171:
+# line 390 "cgram.g"
+{yyval = tree5(N_Loop,yypvt[-3],yypvt[-3],yypvt[-2],yypvt[-0]) ;} break;
+case 172:
+# line 392 "cgram.g"
+{yyval = tree5(N_Loop,yypvt[-1],yypvt[-1],yypvt[-0],tree1(N_Empty) ) ;} break;
+case 173:
+# line 393 "cgram.g"
+{yyval = tree5(N_Loop,yypvt[-3],yypvt[-3],yypvt[-2],yypvt[-0]) ;} break;
+case 174:
+# line 395 "cgram.g"
+{yyval = tree5(N_Loop,yypvt[-1],yypvt[-1],yypvt[-0],tree1(N_Empty) ) ;} break;
+case 175:
+# line 397 "cgram.g"
+{yyval = tree4(N_Ret,yypvt[-0],yypvt[-0],tree1(N_Empty) ) ;} break;
+case 176:
+# line 398 "cgram.g"
+{yyval = tree4(N_Ret,yypvt[-1],yypvt[-1],yypvt[-0]) ;} break;
+case 177:
+# line 399 "cgram.g"
+{yyval = tree5(N_Loop,yypvt[-1],yypvt[-1],yypvt[-0],tree1(N_Empty) ) ;} break;
+case 178:
+# line 400 "cgram.g"
+{yyval = tree5(N_Loop,yypvt[-3],yypvt[-3],yypvt[-2],yypvt[-0]) ;} break;
+case 179:
+# line 402 "cgram.g"
+{yyval = tree5(N_If,yypvt[-3],yypvt[-2],yypvt[-0],tree1(N_Empty) ) ;} break;
+case 180:
+# line 403 "cgram.g"
+{yyval = tree5(N_If,yypvt[-5],yypvt[-4],yypvt[-2],yypvt[-0]) ;} break;
+case 181:
+# line 405 "cgram.g"
+{yyval = case_nd(yypvt[-5],yypvt[-4],yypvt[-1]) ;} break;
+case 183:
+# line 408 "cgram.g"
+{yyval = tree4(N_Clist,yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 184:
+# line 410 "cgram.g"
+{yyval = tree4(N_Ccls,yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 185:
+# line 411 "cgram.g"
+{yyval = tree4(N_Ccls,yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+case 186:
+# line 413 "cgram.g"
+{yyval = yypvt[-0]; ;} break;
+case 187:
+# line 414 "cgram.g"
+{yyval = tree4(N_Elist,yypvt[-1],yypvt[-2],yypvt[-0]); ;} break;
+case 188:
+# line 416 "cgram.g"
+{
+ yyval = tree3(N_Create,yypvt[-0],yypvt[-0]); proc_lst->has_coexpr = 1; ;
+ } break;
+case 189:
+# line 419 "cgram.g"
+{
+ yyval =tree4(N_Elist,yypvt[-1],yypvt[-2],tree3(N_Create,yypvt[-1],yypvt[-0])); proc_lst->has_coexpr = 1; ;
+ } break;
+case 190:
+# line 423 "cgram.g"
+{CSym0(yypvt[-0]) = putlit(Str0(yypvt[-0]),F_IntLit,0) ;} break;
+case 191:
+# line 424 "cgram.g"
+{CSym0(yypvt[-0]) = putlit(Str0(yypvt[-0]),F_RealLit,0) ;} break;
+case 192:
+# line 425 "cgram.g"
+{CSym0(yypvt[-0]) = putlit(Str0(yypvt[-0]),F_StrLit,(int)Val1(yypvt[-0])) ;} break;
+case 193:
+# line 426 "cgram.g"
+{CSym0(yypvt[-0]) = putlit(Str0(yypvt[-0]),F_CsetLit,(int)Val1(yypvt[-0])) ;} break;
+case 194:
+# line 428 "cgram.g"
+{yyval = sect_nd(yypvt[-2],yypvt[-5],yypvt[-3],yypvt[-1]) ;} break;
+case 195:
+# line 430 "cgram.g"
+{yyval = yypvt[-0] ;} break;
+case 196:
+# line 431 "cgram.g"
+{yyval = yypvt[-0] ;} break;
+case 197:
+# line 432 "cgram.g"
+{yyval = yypvt[-0] ;} break;
+case 199:
+# line 435 "cgram.g"
+{yyval = tree4(N_Slist,yypvt[-1],yypvt[-2],yypvt[-0]) ;} break;
+ }
+ goto yystack; /* reset registers in driver code */
+}
diff --git a/src/iconc/cproto.h b/src/iconc/cproto.h
new file mode 100644
index 0000000..a32b982
--- /dev/null
+++ b/src/iconc/cproto.h
@@ -0,0 +1,165 @@
+/*
+ * Prototypes for functions in iconc.
+ */
+struct sig_lst *add_sig (struct code *sig, struct c_fnc *fnc);
+void addlib (char *libname);
+struct code *alc_ary (int n);
+int alc_cbufs (int num, nodeptr lifetime);
+int alc_dtmp (nodeptr lifetime);
+int alc_itmp (nodeptr lifetime);
+struct code *alc_lbl (char *desc, int flag);
+int alc_sbufs (int num, nodeptr lifetime);
+#ifdef OptimizeType
+unsigned int *alloc_mem_typ (unsigned int n_types);
+#endif /* OptimizeType */
+void arth_anlz (struct il_code *var1, struct il_code *var2,
+ int *maybe_int, int *maybe_dbl, int *chk1,
+ struct code **conv1p, int *chk2,
+ struct code **conv2p);
+struct node *aug_nd (nodeptr op, nodeptr arg1, nodeptr arg2);
+struct node *binary_nd (nodeptr op, nodeptr arg1, nodeptr arg2);
+void bitrange (int typcd, int *frst_bit, int *last_bit);
+nodeptr buildarray (nodeptr a, nodeptr lb, nodeptr e);
+void callc_add (struct c_fnc *cont);
+void callo_add (char *oper_nm, int ret_flag,
+ struct c_fnc *cont, int need_cont,
+ struct code *arglist, struct code *on_ret);
+struct node *case_nd (nodeptr loc_model, nodeptr expr, nodeptr cases);
+int ccomp (char *srcname, char *exename);
+void cd_add (struct code *cd);
+struct val_loc *chk_alc (struct val_loc *rslt, nodeptr lifetime);
+void chkinv (void);
+void chkstrinv (void);
+struct node *c_str_leaf (int type,struct node *loc_model, char *c);
+void codegen (struct node *t);
+int cond_anlz (struct il_code *il, struct code **cdp);
+void const_blks (void);
+struct val_loc *cvar_loc (char *name);
+int do_inlin (struct implement *impl, nodeptr n, int *sep_cont,
+ struct op_symentry *symtab, int n_va);
+void doiconx (char *s);
+struct val_loc *dtmp_loc (int n);
+void eval_arith (int indx1, int indx2, int *maybe_int, int *maybe_dbl);
+int eval_cnv (int typcd, int indx, int def, int *cnv_flags);
+int eval_is (int typcd,int indx);
+void findcases (struct il_code *il, int has_dflt,
+ struct case_anlz *case_anlz);
+void fix_fncs (struct c_fnc *fnc);
+struct fentry *flookup (char *id);
+void gen_inlin (struct il_code *il, struct val_loc *rslt,
+ struct code **scont_strt,
+ struct code **scont_fail, struct c_fnc *cont,
+ struct implement *impl, int nsyms,
+ struct op_symentry *symtab, nodeptr n,
+ int dcl_var, int n_va);
+int getopr (int ac, int *cc);
+#ifdef OptimizeType
+unsigned int get_bit_vector (struct typinfo *src, int pos);
+#endif /* OptimizeType */
+struct gentry *glookup (char *id);
+void hsyserr (char **av, char *file);
+struct node *i_str_leaf (int type,struct node *loc_model,char *c, int d);
+long iconint (char *image);
+struct code *il_copy (struct il_c *dest, struct val_loc *src);
+struct code *il_cnv (int typcd, struct il_code *src,
+ struct il_c *dflt, struct il_c *dest);
+struct code *il_dflt (int typcd, struct il_code *src,
+ struct il_c *dflt, struct il_c *dest);
+void implproto (struct implement *ip);
+void init (void);
+void init_proc (char *name);
+void init_rec (char *name);
+void init_src (void);
+void install (char *name,int flag);
+struct gentry *instl_p (char *name, int flag);
+struct node *int_leaf (int type,struct node *loc_model,int c);
+struct val_loc *itmp_loc (int n);
+struct node *invk_main (struct pentry *main_proc);
+struct node *invk_nd (struct node *loc_model, struct node *proc,
+ struct node *args);
+void invoc_grp (char *grp);
+void invocbl (nodeptr op, int arity);
+struct node *key_leaf (nodeptr loc_model, char *keyname);
+void liveness (nodeptr n, nodeptr resumer, nodeptr *failer, int *gen);
+struct node *list_nd (nodeptr loc_model, nodeptr args);
+void lnkdcl (char *name);
+void readdb (char *db_name);
+struct val_loc *loc_cpy (struct val_loc *loc, int mod_access);
+#ifdef OptimizeType
+void mark_recs (struct fentry *fp, struct typinfo *typ,
+ int *num_offsets, int *offset, int *bad_recs);
+#else /* OptimizeType */
+void mark_recs (struct fentry *fp, unsigned int *typ,
+ int *num_offsets, int *offset, int *bad_recs);
+#endif /* OptimizeType */
+struct code *mk_goto (struct code *label);
+struct node *multiunary (char *op, nodeptr loc_model, nodeptr oprnd);
+struct sig_act *new_sgact (struct code *sig, struct code *cd,
+ struct sig_act *next);
+int nextchar (void);
+void nfatal (struct node *n, char *s1, char *s2);
+int n_arg_sym (struct implement *ip);
+void outerfnc (struct c_fnc *fnc);
+int past_prms (struct node *n);
+void proccode (struct pentry *proc);
+void prt_fnc (struct c_fnc *fnc);
+void prt_frame (char *prefix, int ntend, int n_itmp,
+ int i, int j, int k);
+struct centry *putlit (char *image,int littype,int len);
+struct lentry *putloc (char *id,int id_type);
+void quit (char *msg);
+void quitf (char *msg,char *arg);
+void recconstr (struct rentry *r);
+void resolve (struct pentry *proc);
+unsigned int round2 (unsigned int n);
+struct code *sig_cd (struct code *fail, struct c_fnc *fnc);
+void src_file (char *name);
+struct node *sect_nd (nodeptr op, nodeptr arg1, nodeptr arg2,
+ nodeptr arg3);
+void tfatal (char *s1,char *s2);
+struct node *to_nd (nodeptr loc_model, nodeptr arg1,
+ nodeptr arg2);
+struct node *toby_nd (nodeptr loc_model, nodeptr arg1,
+ nodeptr arg2, nodeptr arg3);
+int trans (void);
+struct node *tree1 (int type);
+struct node *tree2 (int type,struct node *loc_model);
+struct node *tree3 (int type,struct node *loc_model,
+ struct node *c);
+struct node *tree4 (int type, struct node *loc_model,
+ struct node *c, struct node *d);
+struct node *tree5 (int type, struct node *loc_model,
+ struct node *c, struct node *d,
+ struct node *e);
+struct node *tree6 (int type,struct node *loc_model,
+ struct node *c, struct node *d,
+ struct node *e, struct node *f);
+void tsyserr (char *s);
+void twarn (char *s1,char *s2);
+struct code *typ_chk (struct il_code *var, int typcd);
+int type_case (struct il_code *il, int (*fnc)(),
+ struct case_anlz *case_anlz);
+void typeinfer (void);
+struct node *unary_nd (nodeptr op, nodeptr arg);
+void var_dcls (void);
+#ifdef OptimizeType
+int varsubtyp (struct typinfo *typ, struct lentry **single);
+#else /* OptimizeType */
+int varsubtyp (unsigned int *typ, struct lentry **single);
+#endif /* OptimizeType */
+void writecheck (int rc);
+void yyerror (int tok,struct node *lval,int state);
+int yylex (void);
+int yyparse (void);
+#ifdef OptimizeType
+void xfer_packed_types (struct typinfo *type);
+#endif /* OptimizeType */
+
+#ifdef DeBug
+void symdump (void);
+void ldump (struct lentry **lhash);
+void gdump (void);
+void cdump (void);
+void fdump (void);
+void rdump (void);
+#endif /* DeBug */
diff --git a/src/iconc/csym.c b/src/iconc/csym.c
new file mode 100644
index 0000000..8e764e3
--- /dev/null
+++ b/src/iconc/csym.c
@@ -0,0 +1,853 @@
+/*
+ * csym.c -- functions for symbol table management.
+ */
+#include "../h/gsupport.h"
+#include "cglobals.h"
+#include "ctrans.h"
+#include "ctree.h"
+#include "ctoken.h"
+#include "csym.h"
+#include "ccode.h"
+#include "cproto.h"
+
+/*
+ * Prototypes.
+ */
+
+static struct gentry *alcglob (struct gentry *blink,
+ char *name,int flag);
+static struct fentry *alcfld (struct fentry *blink, char *name,
+ struct par_rec *rp);
+static struct centry *alclit (struct centry *blink,
+ char *image, int len,int flag);
+static struct lentry *alcloc (struct lentry *blink,
+ char *name,int flag);
+static struct par_rec *alcprec (struct rentry *rec, int offset,
+ struct par_rec *next);
+static struct centry *clookup (char *image,int flag);
+static struct lentry *dcl_loc (char *id, int id_type,
+ struct lentry *next);
+static struct lentry *llookup (char *id);
+static void opstrinv (struct implement *ip);
+static struct gentry *putglob (char *id,int id_type);
+static struct gentry *try_gbl (char *id);
+
+int max_sym = 0; /* max number of parameter symbols in run-time routines */
+int max_prm = 0; /* max number of parameters for any invocable routine */
+
+/*
+ * The operands of the invocable declaration are stored in a list for
+ * later processing.
+ */
+struct strinv {
+ nodeptr op;
+ int arity;
+ struct strinv *next;
+ };
+struct strinv *strinvlst = NULL;
+int op_tbl_sz;
+
+struct pentry *proc_lst = NULL; /* procedure list */
+struct rentry *rec_lst = NULL; /* record list */
+
+
+/*
+ *instl_p - install procedure or record in global symbol table, returning
+ * the symbol table entry.
+ */
+struct gentry *instl_p(name, flag)
+char *name;
+int flag;
+ {
+ struct gentry *gp;
+
+ flag |= F_Global;
+ if ((gp = glookup(name)) == NULL)
+ gp = putglob(name, flag);
+ else if ((gp->flag & (~F_Global)) == 0) {
+ /*
+ * superfluous global declaration for record or proc
+ */
+ gp->flag |= flag;
+ }
+ else /* the user can't make up his mind */
+ tfatal("inconsistent redeclaration", name);
+ return gp;
+ }
+
+/*
+ * install - put an identifier into the global or local symbol table.
+ * The basic idea here is to look in the right table and install
+ * the identifier if it isn't already there. Some semantic checks
+ * are performed.
+ */
+void install(name, flag)
+char *name;
+int flag;
+ {
+ struct fentry *fp;
+ struct gentry *gp;
+ struct lentry *lp;
+ struct par_rec **rpp;
+ struct fldname *fnp;
+ int foffset;
+
+ switch (flag) {
+ case F_Global: /* a variable in a global declaration */
+ if ((gp = glookup(name)) == NULL)
+ putglob(name, flag);
+ else
+ gp->flag |= flag;
+ break;
+
+ case F_Static: /* static declaration */
+ ++proc_lst->nstatic;
+ lp = dcl_loc(name, flag, proc_lst->statics);
+ proc_lst->statics = lp;
+ break;
+
+ case F_Dynamic: /* local declaration */
+ ++proc_lst->ndynam;
+ lp = dcl_loc(name, flag, proc_lst->dynams);
+ proc_lst->dynams = lp;
+ break;
+
+ case F_Argument: /* formal parameter */
+ ++proc_lst->nargs;
+ if (proc_lst->nargs > max_prm)
+ max_prm = proc_lst->nargs;
+ lp = dcl_loc(name, flag, proc_lst->args);
+ proc_lst->args = lp;
+ break;
+
+ case F_Field: /* field declaration */
+ fnp = NewStruct(fldname);
+ fnp->name = name;
+ fnp->next = rec_lst->fields;
+ rec_lst->fields = fnp;
+ foffset = rec_lst->nfields++;
+ if (foffset > max_prm)
+ max_prm = foffset;
+ if ((fp = flookup(name)) == NULL) {
+ /*
+ * first occurrence of this field name.
+ */
+ fhash[FHasher(name)] = alcfld(fhash[FHasher(name)], name,
+ alcprec(rec_lst, foffset, NULL));
+ }
+ else {
+ rpp = &(fp->rlist);
+ while (*rpp != NULL && (*rpp)->offset <= foffset &&
+ (*rpp)->rec != rec_lst)
+ rpp = &((*rpp)->next);
+ if (*rpp == NULL || (*rpp)->offset > foffset)
+ *rpp = alcprec(rec_lst, foffset, *rpp);
+ else
+ tfatal("duplicate field name", name);
+ }
+ break;
+
+ default:
+ tsyserr("install: unrecognized symbol table flag.");
+ }
+ }
+
+/*
+ * dcl_loc - handle declaration of a local identifier.
+ */
+static struct lentry *dcl_loc(name, flag, next)
+char *name;
+int flag;
+struct lentry *next;
+ {
+ register struct lentry *lp;
+
+ if ((lp = llookup(name)) == NULL) {
+ lp = putloc(name,flag);
+ lp->next = next;
+ }
+ else if (lp->flag == flag) /* previously declared as same type */
+ twarn("redeclared identifier", name);
+ else /* previously declared as different type */
+ tfatal("inconsistent redeclaration", name);
+ return lp;
+ }
+
+/*
+ * putloc - make a local symbol table entry and return pointer to it.
+ */
+struct lentry *putloc(id,id_type)
+char *id;
+int id_type;
+ {
+ register struct lentry *ptr;
+ register struct lentry **lhash;
+ unsigned hashval;
+
+ if ((ptr = llookup(id)) == NULL) { /* add to head of hash chain */
+ lhash = proc_lst->lhash;
+ hashval = LHasher(id);
+ ptr = alcloc(lhash[hashval], id, id_type);
+ lhash[hashval] = ptr;
+ ptr->next = NULL;
+ }
+ return ptr;
+ }
+
+/*
+ * putglob makes a global symbol table entry and returns a pointer to it.
+ */
+static struct gentry *putglob(id, id_type)
+char *id;
+int id_type;
+ {
+ register struct gentry *ptr;
+ register unsigned hashval;
+
+ if ((ptr = glookup(id)) == NULL) { /* add to head of hash chain */
+ hashval = GHasher(id);
+ ptr = alcglob(ghash[hashval], id, id_type);
+ ghash[hashval] = ptr;
+ }
+ return ptr;
+ }
+
+/*
+ * putlit makes a constant symbol table entry and returns a pointer to it.
+ */
+struct centry *putlit(image, littype, len)
+char *image;
+int len, littype;
+ {
+ register struct centry *ptr;
+ register unsigned hashval;
+
+ if ((ptr = clookup(image,littype)) == NULL) { /* add to head of hash chain */
+ hashval = CHasher(image);
+ ptr = alclit(chash[hashval], image, len, littype);
+ chash[hashval] = ptr;
+ }
+ return ptr;
+ }
+
+/*
+ * llookup looks up id in local symbol table and returns pointer to
+ * to it if found or NULL if not present.
+ */
+
+static struct lentry *llookup(id)
+char *id;
+ {
+ register struct lentry *ptr;
+
+ ptr = proc_lst->lhash[LHasher(id)];
+ while (ptr != NULL && ptr->name != id)
+ ptr = ptr->blink;
+ return ptr;
+ }
+
+/*
+ * flookup looks up id in flobal symbol table and returns pointer to
+ * to it if found or NULL if not present.
+ */
+struct fentry *flookup(id)
+char *id;
+ {
+ register struct fentry *ptr;
+
+ ptr = fhash[FHasher(id)];
+ while (ptr != NULL && ptr->name != id) {
+ ptr = ptr->blink;
+ }
+ return ptr;
+ }
+
+/*
+ * glookup looks up id in global symbol table and returns pointer to
+ * to it if found or NULL if not present.
+ */
+struct gentry *glookup(id)
+char *id;
+ {
+ register struct gentry *ptr;
+
+ ptr = ghash[GHasher(id)];
+ while (ptr != NULL && ptr->name != id) {
+ ptr = ptr->blink;
+ }
+ return ptr;
+ }
+
+/*
+ * clookup looks up id in constant symbol table and returns pointer to
+ * to it if found or NULL if not present.
+ */
+static struct centry *clookup(image,flag)
+char *image;
+int flag;
+ {
+ register struct centry *ptr;
+
+ ptr = chash[CHasher(image)];
+ while (ptr != NULL && (ptr->image != image || ptr->flag != flag))
+ ptr = ptr->blink;
+
+ return ptr;
+ }
+
+#ifdef DeBug
+/*
+ * symdump - dump symbol tables.
+ */
+void symdump()
+ {
+ struct pentry *proc;
+
+ gdump();
+ cdump();
+ rdump();
+ fdump();
+ for (proc = proc_lst; proc != NULL; proc = proc->next) {
+ fprintf(stderr,"\n");
+ fprintf(stderr,"Procedure %s\n", proc->sym_entry->name);
+ ldump(proc->lhash);
+ }
+ }
+
+/*
+ * prt_flgs - print flags from a symbol table entry.
+ */
+static void prt_flgs(flags)
+int flags;
+ {
+ if (flags & F_Global)
+ fprintf(stderr, " F_Global");
+ if (flags & F_Proc)
+ fprintf(stderr, " F_Proc");
+ if (flags & F_Record)
+ fprintf(stderr, " F_Record");
+ if (flags & F_Dynamic)
+ fprintf(stderr, " F_Dynamic");
+ if (flags & F_Static)
+ fprintf(stderr, " F_Static");
+ if (flags & F_Builtin)
+ fprintf(stderr, " F_Builtin");
+ if (flags & F_StrInv)
+ fprintf(stderr, " F_StrInv");
+ if (flags & F_ImpError)
+ fprintf(stderr, " F_ImpError");
+ if (flags & F_Argument)
+ fprintf(stderr, " F_Argument");
+ if (flags & F_IntLit)
+ fprintf(stderr, " F_IntLit");
+ if (flags & F_RealLit)
+ fprintf(stderr, " F_RealLit");
+ if (flags & F_StrLit)
+ fprintf(stderr, " F_StrLit");
+ if (flags & F_CsetLit)
+ fprintf(stderr, " F_CsetLit");
+ if (flags & F_Field)
+ fprintf(stderr, " F_Field");
+ fprintf(stderr, "\n");
+ }
+/*
+ * ldump displays local symbol table to stderr.
+ */
+
+void ldump(lhash)
+struct lentry **lhash;
+ {
+ register int i;
+ register struct lentry *lptr;
+
+ fprintf(stderr," Dump of local symbol table\n");
+ fprintf(stderr," address name globol-ref flags\n");
+ for (i = 0; i < LHSize; i++)
+ for (lptr = lhash[i]; lptr != NULL; lptr = lptr->blink) {
+ fprintf(stderr," %8x %20s ", lptr, lptr->name);
+ if (lptr->flag & F_Global)
+ fprintf(stderr, "%8x ", lptr->val.global);
+ else
+ fprintf(stderr, " - ");
+ prt_flgs(lptr->flag);
+ }
+ fflush(stderr);
+ }
+
+/*
+ * gdump displays global symbol table to stderr.
+ */
+
+void gdump()
+ {
+ register int i;
+ register struct gentry *gptr;
+
+ fprintf(stderr,"\n");
+ fprintf(stderr,"Dump of global symbol table\n");
+ fprintf(stderr," address name nargs flags\n");
+ for (i = 0; i < GHSize; i++)
+ for (gptr = ghash[i]; gptr != NULL; gptr = gptr->blink) {
+ fprintf(stderr," %8x %20s %4d ", gptr,
+ gptr->name, gptr->nargs);
+ prt_flgs(gptr->flag);
+ }
+ fflush(stderr);
+ }
+
+/*
+ * cdump displays constant symbol table to stderr.
+ */
+
+void cdump()
+ {
+ register int i;
+ register struct centry *cptr;
+
+ fprintf(stderr,"\n");
+ fprintf(stderr,"Dump of constant symbol table\n");
+ fprintf(stderr,
+ " address value flags\n");
+ for (i = 0; i < CHSize; i++)
+ for (cptr = chash[i]; cptr != NULL; cptr = cptr->blink) {
+ fprintf(stderr," %8x %-40.40s ", cptr, cptr->image);
+ prt_flgs(cptr->flag);
+ }
+ fflush(stderr);
+ }
+
+/*
+ * fdump displays field symbol table to stderr.
+ */
+void fdump()
+ {
+ int i;
+ struct par_rec *prptr;
+ struct fentry *fp;
+
+ fprintf(stderr,"\n");
+ fprintf(stderr,"Dump of field symbol table\n");
+ fprintf(stderr,
+ " address field global-ref offset\n");
+ for (i = 0; i < FHSize; i++)
+ for (fp = fhash[i]; fp != NULL; fp = fp->blink) {
+ fprintf(stderr," %8x %20s\n", fp, fp->name);
+ for (prptr = fp->rlist; prptr != NULL; prptr = prptr->next)
+ fprintf(stderr," %8x %4d\n",
+ prptr->sym_entry, prptr->offset);
+ }
+ fflush(stderr);
+ }
+
+/*
+ * prt_flds - print a list of fields stored in reverse order.
+ */
+static void prt_flds(f)
+struct fldname *f;
+ {
+ if (f == NULL)
+ return;
+ prt_flds(f->next);
+ fprintf(stderr, " %s", f->name);
+ }
+
+/*
+ * rdump displays list of records and their fields.
+ */
+void rdump()
+ {
+ struct rentry *rp;
+
+ fprintf(stderr,"\n");
+ fprintf(stderr,"Dump of record list\n");
+ fprintf(stderr, " global-ref fields\n");
+ for (rp = rec_lst; rp != NULL; rp = rp->next) {
+ fprintf(stderr, " %8x ", rp->sym_entry);
+ prt_flds(rp->fields);
+ fprintf(stderr, "\n");
+ }
+ }
+#endif /* DeBug */
+
+/*
+ * alcloc allocates a local symbol table entry, fills in fields with
+ * specified values and returns pointer to new entry.
+ */
+static struct lentry *alcloc(blink, name, flag)
+struct lentry *blink;
+char *name;
+int flag;
+ {
+ register struct lentry *lp;
+
+ lp = NewStruct(lentry);
+ lp->blink = blink;
+ lp->name = name;
+ lp->flag = flag;
+ return lp;
+ }
+
+/*
+ * alcfld allocates a field symbol table entry, fills in the entry with
+ * specified values and returns pointer to new entry.
+ */
+static struct fentry *alcfld(blink, name, rp)
+struct fentry *blink;
+char *name;
+struct par_rec *rp;
+ {
+ register struct fentry *fp;
+
+ fp = NewStruct(fentry);
+ fp->blink = blink;
+ fp->name = name;
+ fp->rlist = rp;
+ return fp;
+ }
+
+/*
+ * alcglob allocates a global symbol table entry, fills in fields with
+ * specified values and returns pointer to new entry.
+ */
+static struct gentry *alcglob(blink, name, flag)
+struct gentry *blink;
+char *name;
+int flag;
+ {
+ register struct gentry *gp;
+
+ gp = NewStruct(gentry);
+ gp->blink = blink;
+ gp->name = name;
+ gp->flag = flag;
+ return gp;
+ }
+
+/*
+ * alclit allocates a constant symbol table entry, fills in fields with
+ * specified values and returns pointer to new entry.
+ */
+static struct centry *alclit(blink, image, len, flag)
+struct centry *blink;
+char *image;
+int len, flag;
+ {
+ register struct centry *cp;
+
+ cp = NewStruct(centry);
+ cp->blink = blink;
+ cp->image = image;
+ cp->length = len;
+ cp->flag = flag;
+ switch (flag) {
+ case F_IntLit:
+ cp->u.intgr = iconint(image);
+ break;
+ case F_CsetLit:
+ cp->u.cset = bitvect(image, len);
+ break;
+ }
+ return cp;
+ }
+
+/*
+ * alcprec allocates an entry for the parent record list for a field.
+ */
+static struct par_rec *alcprec(rec, offset, next)
+struct rentry *rec;
+int offset;
+struct par_rec *next;
+ {
+ register struct par_rec *rp;
+
+ rp = NewStruct(par_rec);
+ rp->rec= rec;
+ rp->offset = offset;
+ rp->next = next;
+ return rp;
+ }
+
+/*
+ * resolve - resolve the scope of undeclared identifiers.
+ */
+void resolve(proc)
+struct pentry *proc;
+ {
+ struct lentry **lhash;
+ register struct lentry *lp;
+ struct gentry *gp;
+ int i;
+ char *id;
+
+ lhash = proc->lhash;
+
+ for (i = 0; i < LHSize; ++i) {
+ lp = lhash[i];
+ while (lp != NULL) {
+ id = lp->name;
+ if (lp->flag == 0) { /* undeclared */
+ if ((gp = try_gbl(id)) != NULL) { /* check global */
+ lp->flag = F_Global;
+ lp->val.global = gp;
+ }
+ else { /* implicit local */
+ if (uwarn) {
+ fprintf(stderr, "%s undeclared identifier, procedure %s\n",
+ id, proc->name);
+ ++twarns;
+ }
+ lp->flag = F_Dynamic;
+ lp->next = proc->dynams;
+ proc->dynams = lp;
+ ++proc->ndynam;
+ }
+ }
+ lp = lp->blink;
+ }
+ }
+ }
+
+/*
+ * try_glb - see if the identifier is or should be a global variable.
+ */
+static struct gentry *try_gbl(id)
+char *id;
+ {
+ struct gentry *gp;
+ register struct implement *iptr;
+ int nargs;
+ int n;
+
+ gp = glookup(id);
+ if (gp == NULL) {
+ /*
+ * See if it is a built-in function.
+ */
+ iptr = db_ilkup(id, bhash);
+ if (iptr == NULL)
+ return NULL;
+ else {
+ if (iptr->in_line == NULL)
+ nfatal(NULL, "built-in function not installed", id);
+ nargs = iptr->nargs;
+ if (nargs > 0 && iptr->arg_flgs[nargs - 1] & VarPrm)
+ nargs = -nargs;
+ gp = putglob(id, F_Global | F_Builtin);
+ gp->val.builtin = iptr;
+
+ n = n_arg_sym(iptr);
+ if (n > max_sym)
+ max_sym = n;
+ }
+ }
+ return gp;
+ }
+
+/*
+ * invoc_grp - called when "invocable all" is encountered.
+ */
+void invoc_grp(grp)
+char *grp;
+ {
+ if (grp == spec_str("all"))
+ str_inv = 1; /* enable full string invocation */
+ else
+ tfatal("invalid operand to invocable", grp);
+ }
+
+/*
+ * invocbl - indicate that the operator is needed for for string invocation.
+ */
+void invocbl(op, arity)
+nodeptr op;
+int arity;
+ {
+ struct strinv *si;
+
+ si = NewStruct(strinv);
+ si->op = op;
+ si->arity = arity;
+ si->next = strinvlst;
+ strinvlst = si;
+ }
+
+/*
+ * chkstrinv - check to see what is needed for string invocation.
+ */
+void chkstrinv()
+ {
+ struct strinv *si;
+ struct gentry *gp;
+ struct implement *ip;
+ char *op_name;
+ int arity;
+ int i;
+
+ /*
+ * A table of procedure blocks for operators is set up for use by
+ * string invocation.
+ */
+ op_tbl_sz = 0;
+ fprintf(codefile, "\nstatic B_IProc(2) init_op_tbl[OpTblSz]");
+
+ if (str_inv) {
+ /*
+ * All operations must be available for string invocation. Make sure all
+ * built-in functions have either been hidden by global declarations
+ * or are in global variables, make sure no global variables are
+ * optimized away, and make sure all operations are in the table of
+ * operations.
+ */
+ for (i = 0; i < IHSize; ++i) /* built-in function table */
+ for (ip = bhash[i]; ip != NULL; ip = ip->blink)
+ try_gbl(ip->name);
+ for (i = 0; i < GHSize; i++) /* global symbol table */
+ for (gp = ghash[i]; gp != NULL; gp = gp->blink)
+ gp->flag |= F_StrInv;
+ for (i = 0; i < IHSize; ++i) /* operator table */
+ for (ip = ohash[i]; ip != NULL; ip = ip->blink)
+ opstrinv(ip);
+ }
+ else {
+ /*
+ * selected operations must be available for string invocation.
+ */
+ for (si = strinvlst; si != NULL; si = si->next) {
+ op_name = Str0(si->op);
+ if (isalpha(*op_name) || (*op_name == '_')) {
+ /*
+ * This needs to be something in a global variable: function,
+ * procedure, or constructor.
+ */
+ gp = try_gbl(op_name);
+ if (gp == NULL)
+ nfatal(si->op, "not available for string invocation", op_name);
+ else
+ gp->flag |= F_StrInv;
+ }
+ else {
+ /*
+ * must be an operator.
+ */
+ arity = si->arity;
+ i = IHasher(op_name);
+ for (ip = ohash[i]; ip != NULL && ip->op != op_name;
+ ip = ip->blink)
+ ;
+ if (arity < 0) {
+ /*
+ * Operators of all arities with this symbol.
+ */
+ while (ip != NULL && ip->op == op_name) {
+ opstrinv(ip);
+ ip = ip->blink;
+ }
+ }
+ else {
+ /*
+ * Operator of a specific arity.
+ */
+ while (ip != NULL && ip->nargs != arity)
+ ip = ip->blink;
+ if (ip == NULL || ip->op != op_name)
+ nfatal(si->op, "not available for string invocation",
+ op_name);
+ else
+ opstrinv(ip);
+ }
+ }
+ }
+ }
+
+ /*
+ * Add definitions to the header file indicating the size of the operator
+ * table and finish the declaration in the code file.
+ */
+ if (op_tbl_sz == 0) {
+ fprintf(inclfile, "#define OpTblSz 1\n");
+ fprintf(inclfile, "int op_tbl_sz = 0;\n");
+ fprintf(codefile, ";\n");
+ }
+ else {
+ fprintf(inclfile, "#define OpTblSz %d\n", op_tbl_sz);
+ fprintf(inclfile, "int op_tbl_sz = OpTblSz;\n");
+ fprintf(codefile, "\n };\n");
+ }
+ }
+
+/*
+ * opstrinv - set up string invocation for an operator.
+ */
+static void opstrinv(ip)
+struct implement *ip;
+ {
+ char c1, c2;
+ char *name;
+ char *op;
+ register char *s;
+ int nargs;
+ int n;
+
+ if (ip == NULL || ip->iconc_flgs & InStrTbl)
+ return;
+
+ /*
+ * Keep track of the maximum number of argument symbols in any operation
+ * so type inference can allocate enough storage for the worst case of
+ * general invocation.
+ */
+ n = n_arg_sym(ip);
+ if (n > max_sym)
+ max_sym = n;
+
+ name = ip->name;
+ c1 = ip->prefix[0];
+ c2 = ip->prefix[1];
+ op = ip->op;
+ nargs = ip->nargs;
+ if (ip->arg_flgs[nargs - 1] & VarPrm)
+ nargs = -nargs; /* indicate varargs with negative number of params */
+
+ if (op_tbl_sz++ == 0) {
+ fprintf(inclfile, "\n");
+ fprintf(codefile, " = {\n");
+ }
+ else
+ fprintf(codefile, ",\n");
+ implproto(ip); /* output prototype */
+
+ /*
+ * Output procedure block for this operator into table used by string
+ * invocation.
+ */
+ fprintf(codefile, " {T_Proc, 11, O%c%c_%s, %d, -1, 0, 0, {{%d, \"", c1, c2,
+ name, nargs, strlen(op));
+ for (s = op; *s != '\0'; ++s) {
+ if (*s == '\\')
+ fprintf(codefile, "\\");
+ fprintf(codefile, "%c", *s);
+ }
+ fprintf(codefile, "\"}}}");
+ ip->iconc_flgs |= InStrTbl;
+ }
+
+/*
+ * n_arg_sym - determine the number of argument symbols (dereferenced
+ * and undereferenced arguments are separate symbols) for an operation
+ * in the data base.
+ */
+int n_arg_sym(ip)
+struct implement *ip;
+ {
+ int i;
+ int num;
+
+ num = 0;
+ for (i = 0; i < ip->nargs; ++i) {
+ if (ip->arg_flgs[i] & RtParm)
+ ++num;
+ if (ip->arg_flgs[i] & DrfPrm)
+ ++num;
+ }
+ return num;
+ }
diff --git a/src/iconc/csym.h b/src/iconc/csym.h
new file mode 100644
index 0000000..cf104af
--- /dev/null
+++ b/src/iconc/csym.h
@@ -0,0 +1,380 @@
+/*
+ * Structures for symbol table entries.
+ */
+
+#define MaybeTrue 1 /* condition might be true at run time */
+#define MaybeFalse 2 /* condition might be false at run time */
+
+#define MayConvert 1 /* type conversion may convert the value */
+#define MayDefault 2 /* defaulting type conversion may use default */
+#define MayKeep 4 /* conversion may succeed without any actual conversion */
+
+#ifdef OptimizeType
+#define NULL_T 0x1000000
+#define REAL_T 0x2000000
+#define INT_T 0x4000000
+#define CSET_T 0x8000000
+#define STR_T 0x10000000
+
+#define TYPINFO_BLOCK 400000
+
+/*
+ * Optimized type structure for bit vectors
+ * All previous occurencess of unsigned int * (at least
+ * when refering to bit vectors) have been replaced by
+ * struct typinfo.
+ */
+struct typinfo {
+ unsigned int packed; /* packed representation of types */
+ unsigned int *bits; /* full length bit vector */
+};
+#endif /* OptimizeType */
+
+/*
+ * Data base type codes are mapped to type inferencing information using
+ * an array.
+ */
+struct typ_info {
+ int frst_bit; /* first bit in bit vector allocated to this type */
+ int num_bits; /* number of bits in bit vector allocated to this type */
+ int new_indx; /* index into arrays of allocated types for operation */
+#ifdef OptimizeType
+ struct typinfo *typ; /* for variables: initial type */
+#else /* OptimizeType */
+ unsigned int *typ; /* for variabled: initial type */
+#endif /* OptimizeType */
+ };
+
+/*
+ * A type is a bit vector representing a union of basic types. There
+ * are 3 sizes of types: first class types (Icon language types),
+ * intermediate value types (first class types plus variable references),
+ * run-time routine types (intermediate value types plus internal
+ * references to descriptors such as set elements). When the size of
+ * the type is known from context, a simple bit vector can be used.
+ * In other contexts, the size must be included.
+ */
+struct type {
+ int size;
+#ifdef OptimizeType
+ struct typinfo *bits;
+#else /* OptimizeType */
+ unsigned int *bits;
+#endif /* OptimizeType */
+ struct type *next;
+ };
+
+
+#define DecodeSize(x) (x & 0xFFFFFF)
+#define DecodePacked(x) (x >> 24)
+/*
+ * NumInts - convert from the number of bits in a bit vector to the
+ * number of integers implementing it.
+ */
+#define NumInts(n_bits) (n_bits - 1) / IntBits + 1
+
+/*
+ * ClrTyp - zero out the bit vector for a type.
+ */
+#ifdef OptimizeType
+#define ClrTyp(size,typ) {\
+ int typ_indx;\
+ if ((typ)->bits == NULL)\
+ clr_packed((typ),(size));\
+ else\
+ for (typ_indx = 0; typ_indx < NumInts((size)); ++typ_indx)\
+ (typ)->bits[typ_indx] = 0;}
+#else /* OptimizeType */
+#define ClrTyp(size,typ) {\
+ int typ_indx;\
+ for (typ_indx = 0; typ_indx < NumInts((size)); ++typ_indx)\
+ (typ)[typ_indx] = 0;}
+#endif /* OptimizeType */
+
+/*
+ * CpyTyp - copy a type of the given size from one bit vector to another.
+ */
+#ifdef OptimizeType
+#define CpyTyp(nsize,src,dest) {\
+ int typ_indx, num;\
+ if (((src)->bits == NULL) && ((dest)->bits == NULL)) {\
+ ClrTyp((nsize),(dest));\
+ cpy_packed_to_packed((src),(dest),(nsize));\
+ }\
+ else if (((src)->bits == NULL) && ((dest)->bits != NULL)) {\
+ ClrTyp((nsize),(dest));\
+ xfer_packed_to_bits((src),(dest),(nsize));\
+ }\
+ else if (((src)->bits != NULL) && ((dest)->bits == NULL)) {\
+ (dest)->bits = alloc_mem_typ(DecodeSize((dest)->packed));\
+ xfer_packed_types((dest));\
+ for (typ_indx = 0; typ_indx < NumInts((nsize)); ++typ_indx)\
+ (dest)->bits[typ_indx] = (src)->bits[typ_indx];\
+ }\
+ else\
+ for (typ_indx = 0; typ_indx < NumInts((nsize)); ++typ_indx)\
+ (dest)->bits[typ_indx] = (src)->bits[typ_indx];}
+#else /* OptimizeType */
+#define CpyTyp(size,src,dest) {\
+ int typ_indx;\
+ for (typ_indx = 0; typ_indx < NumInts((size)); ++typ_indx)\
+ (dest)[typ_indx] = (src)[typ_indx];}
+#endif /* OptimizeType */
+
+/*
+ * MrgTyp - merge a type of the given size from one bit vector into another.
+ */
+#ifdef OptimizeType
+#define MrgTyp(nsize,src,dest) {\
+ int typ_indx;\
+ if (((src)->bits == NULL) && ((dest)->bits == NULL))\
+ mrg_packed_to_packed((src),(dest),(nsize));\
+ else if (((src)->bits == NULL) && ((dest)->bits != NULL))\
+ xfer_packed_to_bits((src),(dest),(nsize));\
+ else if (((src)->bits != NULL) && ((dest)->bits == NULL)) {\
+ (dest)->bits = alloc_mem_typ(DecodeSize((dest)->packed));\
+ xfer_packed_types((dest));\
+ for (typ_indx = 0; typ_indx < NumInts((nsize)); ++typ_indx)\
+ (dest)->bits[typ_indx] |= (src)->bits[typ_indx];\
+ }\
+ else\
+ for (typ_indx = 0; typ_indx < NumInts((nsize)); ++typ_indx)\
+ (dest)->bits[typ_indx] |= (src)->bits[typ_indx];}
+#else /* OptimizeType */
+#define MrgTyp(size,src,dest) {\
+ int typ_indx;\
+ for (typ_indx = 0; typ_indx < NumInts((size)); ++typ_indx)\
+ (dest)[typ_indx] |= (src)[typ_indx];}
+#endif /* OptimizeType */
+
+/*
+ * ChkMrgTyp - merge a type of the given size from one bit vector into another,
+ * updating the changed flag if the destination is changed by the merger.
+ */
+#ifdef OptimizeType
+#define ChkMrgTyp(nsize,src,dest) {\
+ int typ_indx, ret; unsigned int old;\
+ if (((src)->bits == NULL) && ((dest)->bits == NULL)) {\
+ ret = mrg_packed_to_packed((src),(dest),(nsize));\
+ changed += ret;\
+ }\
+ else if (((src)->bits == NULL) && ((dest)->bits != NULL)) {\
+ ret = xfer_packed_to_bits((src),(dest),(nsize));\
+ changed += ret;\
+ }\
+ else if (((src)->bits != NULL) && ((dest)->bits == NULL)) {\
+ (dest)->bits = alloc_mem_typ(DecodeSize((dest)->packed));\
+ xfer_packed_types((dest));\
+ for (typ_indx = 0; typ_indx < NumInts((nsize)); ++typ_indx) {\
+ old = (dest)->bits[typ_indx];\
+ (dest)->bits[typ_indx] |= (src)->bits[typ_indx];\
+ if (old != (dest)->bits[typ_indx]) ++changed;}\
+ }\
+ else\
+ for (typ_indx = 0; typ_indx < NumInts((nsize)); ++typ_indx) {\
+ old = (dest)->bits[typ_indx];\
+ (dest)->bits[typ_indx] |= (src)->bits[typ_indx];\
+ if (old != (dest)->bits[typ_indx]) ++changed;}}
+#else /* OptimizeType */
+#define ChkMrgTyp(size,src,dest) {\
+ int typ_indx; unsigned int old;\
+ for (typ_indx = 0; typ_indx < NumInts((size)); ++typ_indx) {\
+ old = (dest)[typ_indx];\
+ (dest)[typ_indx] |= (src)[typ_indx];\
+ if (old != (dest)[typ_indx]) ++changed;}}
+#endif /* OptimizeType */
+
+
+struct centry { /* constant table entry */
+ struct centry *blink; /* link for bucket chain */
+ char *image; /* pointer to string image of literal */
+ int length; /* length of string */
+ union {
+ unsigned short *cset; /* pointer to bit string for cset literal */
+ long intgr; /* value of integer literal */
+ } u;
+ uword flag; /* type of literal flag */
+ char prefix[PrfxSz+1]; /* unique prefix used in data block name */
+ };
+
+struct fentry { /* field table entry */
+ struct fentry *blink; /* link for bucket chain */
+ char *name; /* name of field */
+ struct par_rec *rlist; /* head of list of records */
+ };
+
+struct lentry { /* local table entry */
+ struct lentry *blink; /* link for bucket chain */
+ char *name; /* name of variable */
+ uword flag; /* variable flags */
+ union {
+ struct gentry *global; /* for globals: global symbol table entry */
+ int index; /* type index; run-time descriptor index */
+ } val;
+ struct lentry *next; /* used for linking a class of variables */
+ };
+
+struct gentry { /* global table entry */
+ struct gentry *blink; /* link for bucket chain */
+ char *name; /* name of variable */
+ uword flag; /* variable flags */
+ union {
+ struct implement *builtin; /* pointer to built-in function */
+ struct pentry *proc; /* pointer to procedure entry */
+ struct rentry *rec; /* pointer to record entry */
+ } val;
+ int index; /* index into global array */
+ int init_type; /* initial type if procedure */
+ };
+
+/*
+ * Structure for list of parent records for a field name.
+ */
+struct par_rec {
+ struct rentry *rec; /* parent record */
+ int offset; /* field's offset within this record */
+ int mark; /* used during code generation */
+ struct par_rec *next;
+ };
+
+/*
+ * Structure for a procedure.
+ */
+struct pentry {
+ char *name; /* name of procedure */
+ char prefix[PrfxSz+1]; /* prefix to make name unique */
+ struct lentry **lhash; /* hash area for procedure's local table */
+ int nargs; /* number of args */
+ struct lentry *args; /* list of arguments in reverse order */
+ int ndynam; /* number of dynamic locals */
+ struct lentry *dynams; /* list of dynamics in reverse order */
+ int nstatic; /* number of statics */
+ struct lentry *statics; /* list of statics in reverse order */
+ struct node *tree; /* syntax tree for procedure */
+ int has_coexpr; /* this procedure contains co-expressions */
+ int tnd_loc; /* number of tended dynamic locals */
+ int ret_flag; /* proc returns, suspends, and/or fails */
+ int reachable; /* this procedure may be executed */
+ int iteration; /* last iteration of type inference performed */
+ int arg_lst; /* for varargs - the type number of the list */
+#ifdef OptimizeType
+ struct typinfo *ret_typ; /* type returned from procedure */
+#else /* OptimizeType */
+ unsigned int *ret_typ; /* type returned from procedure */
+#endif /* OptimizeType */
+ struct store *in_store; /* store at start of procedure */
+ struct store *susp_store; /* store for resumption points of procedure */
+ struct store *out_store; /* store on exiting procedure */
+ struct lentry **vartypmap; /* mapping from var types to symtab entries */
+#ifdef OptimizeType
+ struct typinfo *coexprs; /* co-expressions in which proc may be called */
+#else /* OptimizeType */
+ unsigned int *coexprs; /* co-expressions in which proc may be called */
+#endif /* OptimizeType */
+ struct pentry *next;
+ };
+
+/*
+ * Structure for a record.
+ */
+struct rentry {
+ char *name; /* name of record */
+ char prefix[PrfxSz+1]; /* prefix to make name unique */
+ int frst_fld; /* offset of variable type of 1st field */
+ int nfields; /* number of fields */
+ struct fldname *fields; /* list of field names in reverse order */
+ int rec_num; /* id number for record */
+ struct rentry *next;
+ };
+
+struct fldname { /* record field */
+ char *name; /* field name */
+ struct fldname *next;
+ };
+
+/*
+ * Structure used to analyze whether a type_case statement can be in-lined.
+ * Only one type check is supported: the type_case will be implemented
+ * as an "if" statement.
+ */
+struct case_anlz {
+ int n_cases; /* number of cases actually needed for this use */
+ int typcd; /* for "if" optimization, the type code to check */
+ struct il_code *il_then; /* for "if" optimization, the then clause */
+ struct il_code *il_else; /* for "if" optimization, the else clause */
+ };
+
+/*
+ * spec_op contains the implementations for operations with do not have
+ * standard unary/binary syntax.
+ */
+#define ToOp 0 /* index into spec_op of i to j */
+#define ToByOp 1 /* index into spec_op of i to j by k */
+#define SectOp 2 /* index into spec_op of x[i:j] */
+#define SubscOp 3 /* index into spec_op of x[i] */
+#define ListOp 4 /* index into spec_op of [e1, e2, ... ] */
+#define NumSpecOp 5
+extern struct implement *spec_op[NumSpecOp];
+
+/*
+ * Flag values.
+ */
+
+#define F_Global 01 /* variable declared global externally */
+#define F_Proc 04 /* procedure */
+#define F_Record 010 /* record */
+#define F_Dynamic 020 /* variable declared local dynamic */
+#define F_Static 040 /* variable declared local static */
+#define F_Builtin 0100 /* identifier refers to built-in procedure */
+#define F_StrInv 0200 /* variable needed for string invocation */
+#define F_ImpError 0400 /* procedure has default error */
+#define F_Argument 01000 /* variable is a formal parameter */
+#define F_IntLit 02000 /* literal is an integer */
+#define F_RealLit 04000 /* literal is a real */
+#define F_StrLit 010000 /* literal is a string */
+#define F_CsetLit 020000 /* literal is a cset */
+#define F_Field 040000 /* identifier refers to a record field */
+#define F_SmplInv 0100000 /* identifier only used in simple invocation */
+
+/*
+ * Symbol table region pointers.
+ */
+
+extern struct implement *bhash[]; /* hash area for built-in func table */
+extern struct centry *chash[]; /* hash area for constant table */
+extern struct fentry *fhash[]; /* hash area for field table */
+extern struct gentry *ghash[]; /* hash area for global table */
+extern struct implement *khash[]; /* hash area for keyword table */
+extern struct implement *ohash[]; /* hash area for operator table */
+
+extern struct pentry *proc_lst; /* procedure list */
+extern struct rentry *rec_lst; /* record list */
+
+extern int max_sym; /* max number of parameter symbols in run-time routines */
+extern int max_prm; /* max number of parameters for any invocable routine */
+
+extern struct symtyps *cur_symtyps; /* maps run-time routine symbols to types */
+extern struct pentry *cur_proc; /* procedure currently being translated */
+
+/*
+ * Hash functions for symbol tables. Note, hash table sizes (xHSize)
+ * are all a power of 2.
+ */
+
+#define CHasher(x) (((word)x)&(CHSize-1)) /* constant symbol table */
+#define FHasher(x) (((word)x)&(FHSize-1)) /* field symbol table */
+#define GHasher(x) (((word)x)&(GHSize-1)) /* global symbol table */
+#define LHasher(x) (((word)x)&(LHSize-1)) /* local symbol table */
+
+/*
+ * flags for implementation entries.
+ */
+#define ProtoPrint 1 /* a prototype has already been printed */
+#define InStrTbl 2 /* operator is in string table */
+
+/*
+ * Whether an operation can fail may depend on whether error conversion
+ * is allowed. The following macro checks this.
+ */
+#define MightFail(ret_flag) ((ret_flag & DoesFail) ||\
+ (err_conv && (ret_flag & DoesEFail)))
diff --git a/src/iconc/ctoken.h b/src/iconc/ctoken.h
new file mode 100644
index 0000000..1e95e98
--- /dev/null
+++ b/src/iconc/ctoken.h
@@ -0,0 +1,111 @@
+# define IDENT 257
+# define INTLIT 258
+# define REALLIT 259
+# define STRINGLIT 260
+# define CSETLIT 261
+# define EOFX 262
+# define BREAK 263
+# define BY 264
+# define CASE 265
+# define CREATE 266
+# define DEFAULT 267
+# define DO 268
+# define ELSE 269
+# define END 270
+# define EVERY 271
+# define FAIL 272
+# define GLOBAL 273
+# define IF 274
+# define INITIAL 275
+# define INVOCABLE 276
+# define LINK 277
+# define LOCAL 278
+# define NEXT 279
+# define NOT 280
+# define OF 281
+# define PROCEDURE 282
+# define RECORD 283
+# define REPEAT 284
+# define RETURN 285
+# define STATIC 286
+# define SUSPEND 287
+# define THEN 288
+# define TO 289
+# define UNTIL 290
+# define WHILE 291
+# define BANG 292
+# define MOD 293
+# define AUGMOD 294
+# define AND 295
+# define AUGAND 296
+# define STAR 297
+# define AUGSTAR 298
+# define INTER 299
+# define AUGINTER 300
+# define PLUS 301
+# define AUGPLUS 302
+# define UNION 303
+# define AUGUNION 304
+# define MINUS 305
+# define AUGMINUS 306
+# define DIFF 307
+# define AUGDIFF 308
+# define DOT 309
+# define SLASH 310
+# define AUGSLASH 311
+# define ASSIGN 312
+# define SWAP 313
+# define NMLT 314
+# define AUGNMLT 315
+# define REVASSIGN 316
+# define REVSWAP 317
+# define SLT 318
+# define AUGSLT 319
+# define SLE 320
+# define AUGSLE 321
+# define NMLE 322
+# define AUGNMLE 323
+# define NMEQ 324
+# define AUGNMEQ 325
+# define SEQ 326
+# define AUGSEQ 327
+# define EQUIV 328
+# define AUGEQUIV 329
+# define NMGT 330
+# define AUGNMGT 331
+# define NMGE 332
+# define AUGNMGE 333
+# define SGT 334
+# define AUGSGT 335
+# define SGE 336
+# define AUGSGE 337
+# define QMARK 338
+# define AUGQMARK 339
+# define AT 340
+# define AUGAT 341
+# define BACKSLASH 342
+# define CARET 343
+# define AUGCARET 344
+# define BAR 345
+# define CONCAT 346
+# define AUGCONCAT 347
+# define LCONCAT 348
+# define AUGLCONCAT 349
+# define TILDE 350
+# define NMNE 351
+# define AUGNMNE 352
+# define SNE 353
+# define AUGSNE 354
+# define NEQUIV 355
+# define AUGNEQUIV 356
+# define LPAREN 357
+# define RPAREN 358
+# define PCOLON 359
+# define COMMA 360
+# define MCOLON 361
+# define COLON 362
+# define SEMICOL 363
+# define LBRACK 364
+# define RBRACK 365
+# define LBRACE 366
+# define RBRACE 367
diff --git a/src/iconc/ctrans.c b/src/iconc/ctrans.c
new file mode 100644
index 0000000..7d33ac5
--- /dev/null
+++ b/src/iconc/ctrans.c
@@ -0,0 +1,184 @@
+/*
+ * ctrans.c - main control of the translation process.
+ */
+#include "../h/gsupport.h"
+#include "cglobals.h"
+#include "ctrans.h"
+#include "csym.h"
+#include "ctree.h"
+#include "ctoken.h"
+#include "ccode.h"
+#include "cproto.h"
+
+/*
+ * Prototypes.
+ */
+static void trans1 (char *filename);
+
+/*
+ * Variables.
+ */
+int tfatals = 0; /* total number of fatal errors */
+int twarns = 0; /* total number of warnings */
+int nocode; /* set by lexer; unused in compiler */
+int in_line; /* current input line number */
+int incol; /* current input column number */
+int peekc; /* one-character look ahead */
+struct srcfile *srclst = NULL; /* list of source files to translate */
+
+static char *lpath; /* LPATH value */
+
+/*
+ * translate a number of files, returning an error count
+ */
+int trans()
+ {
+ register struct pentry *proc;
+ struct srcfile *sf;
+
+ lpath = getenv("LPATH"); /* remains null if unspecified */
+
+ for (sf = srclst; sf != NULL; sf = sf->next)
+ trans1(sf->name); /* translate each file in turn */
+
+ if (!pponly) {
+ /*
+ * Resolve undeclared references.
+ */
+ for (proc = proc_lst; proc != NULL; proc = proc->next)
+ resolve(proc);
+
+#ifdef DeBug
+ symdump();
+#endif /* DeBug */
+
+ if (tfatals == 0) {
+ chkstrinv(); /* see what needs be available for string invocation */
+ chkinv(); /* perform "naive" optimizations */
+ }
+
+ if (tfatals == 0)
+ typeinfer(); /* perform type inference */
+
+ if (just_type_trace)
+ return tfatals; /* stop without generating code */
+
+ if (tfatals == 0) {
+ var_dcls(); /* output declarations for globals and statics */
+ const_blks(); /* output blocks for cset and real literals */
+ for (proc = proc_lst; proc != NULL; proc = proc->next)
+ proccode(proc); /* output code for a procedure */
+ recconstr(rec_lst); /* output code for record constructors */
+/* ANTHONY */
+/*
+ print_ghash();
+*/
+ }
+ }
+
+ /*
+ * Report information about errors and warnings and be correct about it.
+ */
+ if (tfatals == 1)
+ fprintf(stderr, "1 error; ");
+ else if (tfatals > 1)
+ fprintf(stderr, "%d errors; ", tfatals);
+ else if (verbose > 0)
+ fprintf(stderr, "No errors; ");
+
+ if (twarns == 1)
+ fprintf(stderr, "1 warning\n");
+ else if (twarns > 1)
+ fprintf(stderr, "%d warnings\n", twarns);
+ else if (verbose > 0)
+ fprintf(stderr, "no warnings\n");
+ else if (tfatals > 0)
+ fprintf(stderr, "\n");
+
+#ifdef TranStats
+ tokdump();
+#endif /* TranStats */
+
+ return tfatals;
+ }
+
+/*
+ * translate one file.
+ */
+static void trans1(filename)
+char *filename;
+ {
+ in_line = 1; /* start with line 1, column 0 */
+ incol = 0;
+ peekc = 0; /* clear character lookahead */
+
+ if (!ppinit(filename,lpath?lpath:".",m4pre)) {
+ tfatal(filename, "cannot open source file");
+ return;
+ }
+ if (!largeints) /* undefine predef symbol if no -l option */
+ ppdef("_LARGE_INTEGERS", (char *)NULL);
+ ppdef("_MULTITASKING", (char *)NULL); /* never defined in compiler */
+ ppdef("_EVENT_MONITOR", (char *)NULL);
+ ppdef("_MEMORY_MONITOR", (char *)NULL);
+ ppdef("_VISUALIZATION", (char *)NULL);
+
+ if (strcmp(filename,"-") == 0)
+ filename = "stdin";
+ if (verbose > 0)
+ fprintf(stderr, "%s:\n",filename);
+
+ tok_loc.n_file = filename;
+ in_line = 1;
+
+ if (pponly)
+ ppecho(); /* preprocess only */
+ else
+ yyparse(); /* Parse the input */
+ }
+
+/*
+ * writecheck - check the return code from a stdio output operation
+ */
+void writecheck(rc)
+ int rc;
+
+ {
+ if (rc < 0)
+ quit("unable to write to icode file");
+ }
+
+/*
+ * lnkdcl - find file locally or on LPATH and add to source list.
+ */
+void lnkdcl(name)
+char *name;
+{
+ struct srcfile **pp;
+ struct srcfile *p;
+ char buf[MaxPath];
+
+ if (pathfind(buf, lpath, name, SourceSuffix))
+ src_file(buf);
+ else
+ tfatal("cannot resolve reference to file name", name);
+ }
+
+/*
+ * src_file - add the file name to the list of source files to be translated,
+ * if it is not already on the list.
+ */
+void src_file(name)
+char *name;
+ {
+ struct srcfile **pp;
+ struct srcfile *p;
+
+ for (pp = &srclst; *pp != NULL; pp = &(*pp)->next)
+ if (strcmp((*pp)->name, name) == 0)
+ return;
+ p = NewStruct(srcfile);
+ p->name = salloc(name);
+ p->next = NULL;
+ *pp = p;
+}
diff --git a/src/iconc/ctrans.h b/src/iconc/ctrans.h
new file mode 100644
index 0000000..3e03d06
--- /dev/null
+++ b/src/iconc/ctrans.h
@@ -0,0 +1,47 @@
+/*
+ * Miscellaneous compiler-specific definitions.
+ */
+
+#define Iconc
+
+#ifndef CUsage
+ #define CUsage "[-C C-comp] [-E] [-T] [-c] [-f{adelns}] [-n{acest}]\n\
+ [-o ofile] [-p C-opts] [-r runtime] [-s] [-t] [-u] [-v i]"
+#endif /* CUsage */
+
+#define Abs(n) ((n) >= 0 ? (n) : -(n))
+#define Max(x,y) ((x)>(y)?(x):(y))
+
+#define tonum(c) (isdigit(c) ? (c - '0') : ((c & 037) + 9))
+
+/*
+ * Hash tables must be a power of 2.
+ */
+#define CHSize 128 /* size of constant hash table */
+#define FHSize 32 /* size of field hash table */
+#define GHSize 128 /* size of global hash table */
+#define LHSize 128 /* size of local hash table */
+
+#define PrfxSz 3 /* size of prefix */
+
+/*
+ * srcfile is used construct the queue of source files to be translated.
+ */
+struct srcfile {
+ char *name;
+ struct srcfile *next;
+ };
+
+extern struct srcfile *srclst;
+
+/*
+ * External definitions needed throughout translator.
+ */
+extern int twarns;
+
+#ifdef TranStats
+#include "tstats.h"
+#else /* TranStats */
+#define TokInc(x)
+#define TokDec(x)
+#endif /* TranStats */
diff --git a/src/iconc/ctree.c b/src/iconc/ctree.c
new file mode 100644
index 0000000..170a631
--- /dev/null
+++ b/src/iconc/ctree.c
@@ -0,0 +1,777 @@
+/*
+ * ctree.c -- functions for constructing parse trees.
+ */
+#include "../h/gsupport.h"
+#include "../h/lexdef.h"
+#include "ctrans.h"
+#include "ctree.h"
+#include "csym.h"
+#include "ctoken.h"
+#include "ccode.h"
+#include "cproto.h"
+
+/*
+ * prototypes for static functions.
+ */
+static nodeptr chk_empty (nodeptr n);
+static void put_elms (nodeptr t, nodeptr args, int slot);
+static nodeptr subsc_nd (nodeptr op, nodeptr arg1, nodeptr arg2);
+
+/*
+ * tree[1-6] construct parse tree nodes with specified values.
+ * loc_model is a node containing the same line and column information
+ * as is needed in this node, while parameters a through d are values to
+ * be assigned to n_field[0-3]. Note that this could be done with a
+ * single routine; a separate routine for each node size is used for
+ * speed and simplicity.
+ */
+
+nodeptr tree1(type)
+int type;
+ {
+ register nodeptr t;
+
+ t = NewNode(0);
+ t->n_type = type;
+ t->n_file = NULL;
+ t->n_line = 0;
+ t->n_col = 0;
+ t->freetmp = NULL;
+ return t;
+ }
+
+nodeptr tree2(type, loc_model)
+int type;
+nodeptr loc_model;
+ {
+ register nodeptr t;
+
+ t = NewNode(0);
+ t->n_type = type;
+ t->n_file = loc_model->n_file;
+ t->n_line = loc_model->n_line;
+ t->n_col = loc_model->n_col;
+ t->freetmp = NULL;
+ return t;
+ }
+
+nodeptr tree3(type, loc_model, a)
+int type;
+nodeptr loc_model;
+nodeptr a;
+ {
+ register nodeptr t;
+
+ t = NewNode(1);
+ t->n_type = type;
+ t->n_file = loc_model->n_file;
+ t->n_line = loc_model->n_line;
+ t->n_col = loc_model->n_col;
+ t->freetmp = NULL;
+ t->n_field[0].n_ptr = a;
+ return t;
+ }
+
+nodeptr tree4(type, loc_model, a, b)
+int type;
+nodeptr loc_model;
+nodeptr a, b;
+ {
+ register nodeptr t;
+
+ t = NewNode(2);
+ t->n_type = type;
+ t->n_file = loc_model->n_file;
+ t->n_line = loc_model->n_line;
+ t->n_col = loc_model->n_col;
+ t->freetmp = NULL;
+ t->n_field[0].n_ptr = a;
+ t->n_field[1].n_ptr = b;
+ return t;
+ }
+
+nodeptr tree5(type, loc_model, a, b, c)
+int type;
+nodeptr loc_model;
+nodeptr a, b, c;
+ {
+ register nodeptr t;
+
+ t = NewNode(3);
+ t->n_type = type;
+ t->n_file = loc_model->n_file;
+ t->n_line = loc_model->n_line;
+ t->n_col = loc_model->n_col;
+ t->freetmp = NULL;
+ t->n_field[0].n_ptr = a;
+ t->n_field[1].n_ptr = b;
+ t->n_field[2].n_ptr = c;
+ return t;
+ }
+
+nodeptr tree6(type, loc_model, a, b, c, d)
+int type;
+nodeptr loc_model;
+nodeptr a, b, c, d;
+ {
+ register nodeptr t;
+
+ t = NewNode(4);
+ t->n_type = type;
+ t->n_file = loc_model->n_file;
+ t->n_line = loc_model->n_line;
+ t->n_col = loc_model->n_col;
+ t->freetmp = NULL;
+ t->n_field[0].n_ptr = a;
+ t->n_field[1].n_ptr = b;
+ t->n_field[2].n_ptr = c;
+ t->n_field[3].n_ptr = d;
+ return t;
+ }
+
+nodeptr int_leaf(type, loc_model, a)
+int type;
+nodeptr loc_model;
+int a;
+ {
+ register nodeptr t;
+
+ t = NewNode(1);
+ t->n_type = type;
+ t->n_file = loc_model->n_file;
+ t->n_line = loc_model->n_line;
+ t->n_col = loc_model->n_col;
+ t->freetmp = NULL;
+ t->n_field[0].n_val = a;
+ return t;
+ }
+
+nodeptr c_str_leaf(type, loc_model, a)
+int type;
+nodeptr loc_model;
+char *a;
+ {
+ register nodeptr t;
+
+ t = NewNode(1);
+ t->n_type = type;
+ t->n_file = loc_model->n_file;
+ t->n_line = loc_model->n_line;
+ t->n_col = loc_model->n_col;
+ t->freetmp = NULL;
+ t->n_field[0].n_str = a;
+ return t;
+ }
+
+/*
+ * i_str_leaf - create a leaf node containing a string and length.
+ */
+nodeptr i_str_leaf(type, loc_model, a, b)
+int type;
+nodeptr loc_model;
+char *a;
+int b;
+ {
+ register nodeptr t;
+
+ t = NewNode(2);
+ t->n_type = type;
+ t->n_file = loc_model->n_file;
+ t->n_line = loc_model->n_line;
+ t->n_col = loc_model->n_col;
+ t->freetmp = NULL;
+ t->n_field[0].n_str = a;
+ t->n_field[1].n_val = b;
+ return t;
+ }
+
+/*
+ * key_leaf - create a leaf node for a keyword.
+ */
+nodeptr key_leaf(loc_model, keyname)
+nodeptr loc_model;
+char *keyname;
+ {
+ register nodeptr t;
+ struct implement *ip;
+ struct il_code *il;
+ char *s;
+ int typcd;
+
+ /*
+ * Find the data base entry for the keyword, if it exists.
+ */
+ ip = db_ilkup(keyname, khash);
+
+ if (ip == NULL)
+ tfatal("invalid keyword", keyname);
+ else if (ip->in_line == NULL)
+ tfatal("keyword not installed", keyname);
+ else {
+ il = ip->in_line;
+ s = il->u[1].s;
+ if (il->il_type == IL_Const) {
+ /*
+ * This is a constant keyword, treat it as a literal.
+ */
+ t = NewNode(1);
+ t->n_file = loc_model->n_file;
+ t->n_line = loc_model->n_line;
+ t->n_col = loc_model->n_col;
+ t->freetmp = NULL;
+ typcd = il->u[0].n;
+ if (typcd == cset_typ) {
+ t->n_type = N_Cset;
+ CSym0(t) = putlit(&s[1], F_CsetLit, strlen(s) - 2);
+ }
+ else if (typcd == int_typ) {
+ t->n_type = N_Int;
+ CSym0(t) = putlit(s, F_IntLit, 0);
+ }
+ else if (typcd == real_typ) {
+ t->n_type = N_Real;
+ CSym0(t) = putlit(s, F_RealLit, 0);
+ }
+ else if (typcd == str_typ) {
+ t->n_type = N_Str;
+ CSym0(t) = putlit(&s[1], F_StrLit, strlen(s) - 2);
+ }
+ return t;
+ }
+ }
+
+ t = NewNode(2);
+ t->n_type = N_InvOp;
+ t->n_file = loc_model->n_file;
+ t->n_line = loc_model->n_line;
+ t->n_col = loc_model->n_col;
+ t->freetmp = NULL;
+ t->n_field[0].n_val = 0; /* number of arguments */
+ t->n_field[1].ip = ip;
+ return t;
+ }
+
+/*
+ * list_nd - create a list creation node.
+ */
+nodeptr list_nd(loc_model, args)
+nodeptr loc_model;
+nodeptr args;
+ {
+ register nodeptr t;
+ struct implement *impl;
+ int nargs;
+
+ /*
+ * Determine the number of arguments.
+ */
+ if (args->n_type == N_Empty)
+ nargs = 0;
+ else {
+ nargs = 1;
+ for (t = args; t->n_type == N_Elist; t = t->n_field[0].n_ptr)
+ ++nargs;
+ if (nargs > max_prm)
+ max_prm = nargs;
+ }
+
+ impl = spec_op[ListOp];
+ if (impl == NULL)
+ nfatal(loc_model, "list creation not implemented", NULL);
+ else if (impl->in_line == NULL)
+ nfatal(loc_model, "list creation not installed", NULL);
+
+ t = NewNode(nargs + 2);
+ t->n_type = N_InvOp;
+ t->n_file = loc_model->n_file;
+ t->n_line = loc_model->n_line;
+ t->n_col = loc_model->n_col;
+ t->freetmp = NULL;
+ t->n_field[0].n_val = nargs;
+ t->n_field[1].ip = impl;
+ if (nargs > 0)
+ put_elms(t, args, nargs + 1);
+ return t;
+ }
+
+/*
+ * invk_nd - create a node for invocation.
+ */
+nodeptr invk_nd(loc_model, proc, args)
+nodeptr loc_model;
+nodeptr proc;
+nodeptr args;
+ {
+ register nodeptr t;
+ int nargs;
+
+ /*
+ * Determine the number of arguments.
+ */
+ if (args->n_type == N_Empty)
+ nargs = 0;
+ else {
+ nargs = 1;
+ for (t = args; t->n_type == N_Elist; t = t->n_field[0].n_ptr)
+ ++nargs;
+ if (nargs > max_prm)
+ max_prm = nargs;
+ }
+
+ t = NewNode(nargs + 2);
+ t->n_type = N_Invok;
+ t->n_file = loc_model->n_file;
+ t->n_line = loc_model->n_line;
+ t->n_col = loc_model->n_col;
+ t->freetmp = NULL;
+ t->n_field[0].n_val = nargs;
+ t->n_field[1].n_ptr = proc;
+ if (nargs > 0)
+ put_elms(t, args, nargs + 1);
+ return t;
+ }
+
+/*
+ * put_elms - convert a linked list of arguments into an array of arguments
+ * in a node.
+ */
+static void put_elms(t, args, slot)
+nodeptr t;
+nodeptr args;
+int slot;
+ {
+ if (args->n_type == N_Elist) {
+ /*
+ * The linked list is in reverse argument order.
+ */
+ t->n_field[slot].n_ptr = chk_empty(args->n_field[1].n_ptr);
+ put_elms(t, args->n_field[0].n_ptr, slot - 1);
+ free(args);
+ }
+ else
+ t->n_field[slot].n_ptr = chk_empty(args);
+ }
+
+/*
+ * chk_empty - if an argument is empty, replace it with &null.
+ */
+static nodeptr chk_empty(n)
+nodeptr n;
+ {
+ if (n->n_type == N_Empty)
+ n = key_leaf(n, spec_str("null"));
+ return n;
+ }
+
+/*
+ * case_nd - create a node for a case statement.
+ */
+nodeptr case_nd(loc_model, expr, cases)
+nodeptr loc_model;
+nodeptr expr;
+nodeptr cases;
+ {
+ register nodeptr t;
+ nodeptr reverse;
+ nodeptr nxt_cases;
+ nodeptr ccls;
+
+ t = NewNode(3);
+ t->n_type = N_Case;
+ t->n_file = loc_model->n_file;
+ t->n_line = loc_model->n_line;
+ t->n_col = loc_model->n_col;
+ t->freetmp = NULL;
+ t->n_field[0].n_ptr = expr;
+ t->n_field[2].n_ptr = NULL;
+
+ /*
+ * The list of cases is in reverse order. Walk the list reversing it,
+ * and extract the default clause if one exists.
+ */
+ reverse = NULL;
+ while (cases->n_type != N_Ccls) {
+ nxt_cases = cases->n_field[0].n_ptr;
+ ccls = cases->n_field[1].n_ptr;
+ if (ccls->n_field[0].n_ptr->n_type == N_Res) {
+ /*
+ * default clause.
+ */
+ if (t->n_field[2].n_ptr == NULL)
+ t->n_field[2].n_ptr = ccls->n_field[1].n_ptr;
+ else
+ nfatal(ccls, "duplicate default clause", NULL);
+ }
+ else {
+ if (reverse == NULL) {
+ reverse = cases;
+ reverse->n_field[0].n_ptr = ccls;
+ }
+ else {
+ reverse->n_field[1].n_ptr = ccls;
+ cases->n_field[0].n_ptr = reverse;
+ reverse = cases;
+ }
+ }
+ cases = nxt_cases;
+ }
+
+ /*
+ * Last element in list.
+ */
+ if (cases->n_field[0].n_ptr->n_type == N_Res) {
+ /*
+ * default clause.
+ */
+ if (t->n_field[2].n_ptr == NULL)
+ t->n_field[2].n_ptr = cases->n_field[1].n_ptr;
+ else
+ nfatal(ccls, "duplicate default clause", NULL);
+ if (reverse != NULL)
+ reverse = reverse->n_field[0].n_ptr;
+ }
+ else {
+ if (reverse == NULL)
+ reverse = cases;
+ else
+ reverse->n_field[1].n_ptr = cases;
+ }
+ t->n_field[1].n_ptr = reverse;
+ return t;
+ }
+
+/*
+ * multiunary - construct nodes to implement a sequence of unary operators
+ * that have been lexically analyzed as one operator.
+ */
+nodeptr multiunary(op, loc_model, oprnd)
+nodeptr loc_model;
+char *op;
+nodeptr oprnd;
+ {
+ int n;
+ nodeptr nd;
+
+ if (*op == '\0')
+ return oprnd;
+ for (n = 0; optab[n].tok.t_word != NULL; ++n)
+ if ((optab[n].expected & Unary) & (*(optab[n].tok.t_word) == *op)) {
+ nd = OpNode(n);
+ nd->n_file = loc_model->n_file;
+ nd->n_line = loc_model->n_line;
+ nd->n_col = loc_model->n_col;
+ return unary_nd(nd,multiunary(++op,loc_model,oprnd));
+ }
+ fprintf(stderr, "compiler error: inconsistent parsing of unary operators");
+ exit(EXIT_FAILURE);
+ }
+
+/*
+ * binary_nd - construct a node for a binary operator.
+ */
+nodeptr binary_nd(op, arg1, arg2)
+nodeptr op;
+nodeptr arg1;
+nodeptr arg2;
+ {
+ register nodeptr t;
+ struct implement *impl;
+
+ /*
+ * Find the data base entry for the operator.
+ */
+ impl = optab[Val0(op)].binary;
+ if (impl == NULL)
+ nfatal(op, "binary operator not implemented", optab[Val0(op)].tok.t_word);
+ else if (impl->in_line == NULL)
+ nfatal(op, "binary operator not installed", optab[Val0(op)].tok.t_word);
+
+ t = NewNode(4);
+ t->n_type = N_InvOp;
+ t->n_file = op->n_file;
+ t->n_line = op->n_line;
+ t->n_col = op->n_col;
+ t->freetmp = NULL;
+ t->n_field[0].n_val = 2; /* number of arguments */
+ t->n_field[1].ip = impl;
+ t->n_field[2].n_ptr = arg1;
+ t->n_field[3].n_ptr = arg2;
+ return t;
+ }
+
+/*
+ * unary_nd - construct a node for a unary operator.
+ */
+nodeptr unary_nd(op, arg)
+nodeptr op;
+nodeptr arg;
+ {
+ register nodeptr t;
+ struct implement *impl;
+
+ /*
+ * Find the data base entry for the operator.
+ */
+ impl = optab[Val0(op)].unary;
+ if (impl == NULL)
+ nfatal(op, "unary operator not implemented", optab[Val0(op)].tok.t_word);
+ else if (impl->in_line == NULL)
+ nfatal(op, "unary operator not installed", optab[Val0(op)].tok.t_word);
+
+ t = NewNode(3);
+ t->n_type = N_InvOp;
+ t->n_file = op->n_file;
+ t->n_line = op->n_line;
+ t->n_col = op->n_col;
+ t->freetmp = NULL;
+ t->n_field[0].n_val = 1; /* number of arguments */
+ t->n_field[1].ip = impl;
+ t->n_field[2].n_ptr = arg;
+ return t;
+ }
+
+/*
+ * buildarray - convert "multi-dimensional" subscripting into a sequence
+ * of subsripting operations.
+ */
+nodeptr buildarray(a,lb,e)
+nodeptr a, lb, e;
+ {
+ register nodeptr t, t2;
+ if (e->n_type == N_Elist) {
+ t2 = int_leaf(lb->n_type, lb, lb->n_field[0].n_val);
+ t = subsc_nd(t2, buildarray(a,lb,e->n_field[0].n_ptr),
+ e->n_field[1].n_ptr);
+ free(e);
+ }
+ else
+ t = subsc_nd(lb, a, e);
+ return t;
+ }
+
+/*
+ * subsc_nd - construct a node for subscripting.
+ */
+static nodeptr subsc_nd(op, arg1, arg2)
+nodeptr op;
+nodeptr arg1;
+nodeptr arg2;
+ {
+ register nodeptr t;
+ struct implement *impl;
+
+ /*
+ * Find the data base entry for subscripting.
+ */
+ impl = spec_op[SubscOp];
+ if (impl == NULL)
+ nfatal(op, "subscripting not implemented", NULL);
+ else if (impl->in_line == NULL)
+ nfatal(op, "subscripting not installed", NULL);
+
+ t = NewNode(4);
+ t->n_type = N_InvOp;
+ t->n_file = op->n_file;
+ t->n_line = op->n_line;
+ t->n_col = op->n_col;
+ t->freetmp = NULL;
+ t->n_field[0].n_val = 2; /* number of arguments */
+ t->n_field[1].ip = impl;
+ t->n_field[2].n_ptr = arg1;
+ t->n_field[3].n_ptr = arg2;
+ return t;
+ }
+
+/*
+ * to_nd - construct a node for binary to.
+ */
+nodeptr to_nd(op, arg1, arg2)
+nodeptr op;
+nodeptr arg1;
+nodeptr arg2;
+ {
+ register nodeptr t;
+ struct implement *impl;
+
+ /*
+ * Find the data base entry for to.
+ */
+ impl = spec_op[ToOp];
+ if (impl == NULL)
+ nfatal(op, "'i to j' not implemented", NULL);
+ else if (impl->in_line == NULL)
+ nfatal(op, "'i to j' not installed", NULL);
+
+ t = NewNode(4);
+ t->n_type = N_InvOp;
+ t->n_file = op->n_file;
+ t->n_line = op->n_line;
+ t->n_col = op->n_col;
+ t->freetmp = NULL;
+ t->n_field[0].n_val = 2; /* number of arguments */
+ t->n_field[1].ip = impl;
+ t->n_field[2].n_ptr = arg1;
+ t->n_field[3].n_ptr = arg2;
+ return t;
+ }
+
+/*
+ * toby_nd - construct a node for binary to-by.
+ */
+nodeptr toby_nd(op, arg1, arg2, arg3)
+nodeptr op;
+nodeptr arg1;
+nodeptr arg2;
+nodeptr arg3;
+ {
+ register nodeptr t;
+ struct implement *impl;
+
+ /*
+ * Find the data base entry for to-by.
+ */
+ impl = spec_op[ToByOp];
+ if (impl == NULL)
+ nfatal(op, "'i to j by k' not implemented", NULL);
+ else if (impl->in_line == NULL)
+ nfatal(op, "'i to j by k' not installed", NULL);
+
+ t = NewNode(5);
+ t->n_type = N_InvOp;
+ t->n_file = op->n_file;
+ t->n_line = op->n_line;
+ t->n_col = op->n_col;
+ t->freetmp = NULL;
+ t->n_field[0].n_val = 3; /* number of arguments */
+ t->n_field[1].ip = impl;
+ t->n_field[2].n_ptr = arg1;
+ t->n_field[3].n_ptr = arg2;
+ t->n_field[4].n_ptr = arg3;
+ return t;
+ }
+
+/*
+ * aug_nd - create a node for an augmented assignment.
+ */
+nodeptr aug_nd(op, arg1, arg2)
+nodeptr op;
+nodeptr arg1;
+nodeptr arg2;
+ {
+ register nodeptr t;
+ struct implement *impl;
+
+ t = NewNode(5);
+ t->n_type = N_Augop;
+ t->n_file = op->n_file;
+ t->n_line = op->n_line;
+ t->n_col = op->n_col;
+ t->freetmp = NULL;
+
+ /*
+ * Find the data base entry for assignment.
+ */
+ impl = optab[asgn_loc].binary;
+ if (impl == NULL)
+ nfatal(op, "assignment not implemented", NULL);
+ t->n_field[0].ip = impl;
+
+ /*
+ * The operator table entry for the augmented assignment is
+ * immediately after the entry for the operation.
+ */
+ impl = optab[Val0(op) - 1].binary;
+ if (impl == NULL)
+ nfatal(op, "binary operator not implemented",
+ optab[Val0(op) - 1].tok.t_word);
+ t->n_field[1].ip = impl;
+
+ t->n_field[2].n_ptr = arg1;
+ t->n_field[3].n_ptr = arg2;
+ /* t->n_field[4].typ - type of intermediate result */
+ return t;
+ }
+
+/*
+ * sect_nd - create a node for sectioning.
+ */
+nodeptr sect_nd(op, arg1, arg2, arg3)
+nodeptr op;
+nodeptr arg1;
+nodeptr arg2;
+nodeptr arg3;
+ {
+ register nodeptr t;
+ int tok;
+ struct implement *impl;
+ struct implement *impl1;
+
+ t = NewNode(5);
+ t->n_file = op->n_file;
+ t->n_line = op->n_line;
+ t->n_col = op->n_col;
+ t->freetmp = NULL;
+
+ /*
+ * Find the data base entry for sectioning.
+ */
+ impl = spec_op[SectOp];
+ if (impl == NULL)
+ nfatal(op, "sectioning not implemented", NULL);
+
+ tok = optab[Val0(op)].tok.t_type;
+ if (tok == COLON) {
+ /*
+ * Simple sectioning, treat as a ternary operator.
+ */
+ t->n_type = N_InvOp;
+ t->n_field[0].n_val = 3; /* number of arguments */
+ t->n_field[1].ip = impl;
+ }
+ else {
+ /*
+ * Find the data base entry for addition or subtraction.
+ */
+ if (tok == PCOLON) {
+ impl1 = optab[plus_loc].binary;
+ if (impl1 == NULL)
+ nfatal(op, "addition not implemented", NULL);
+ }
+ else { /* MCOLON */
+ impl1 = optab[minus_loc].binary;
+ if (impl1 == NULL)
+ nfatal(op, "subtraction not implemented", NULL);
+ }
+ t->n_type = N_Sect;
+ t->n_field[0].ip = impl;
+ t->n_field[1].ip = impl1;
+ }
+ t->n_field[2].n_ptr = arg1;
+ t->n_field[3].n_ptr = arg2;
+ t->n_field[4].n_ptr = arg3;
+ return t;
+ }
+
+/*
+ * invk_main - produce an procedure invocation node with one argument for
+ * use in the initial invocation to main() during type inference.
+ */
+nodeptr invk_main(main_proc)
+struct pentry *main_proc;
+ {
+ register nodeptr t;
+
+ t = NewNode(3);
+ t->n_type = N_InvProc;
+ t->n_file = NULL;
+ t->n_line = 0;
+ t->n_col = 0;
+ t->freetmp = NULL;
+ t->n_field[0].n_val = 1; /* 1 argument */
+ t->n_field[1].proc = main_proc;
+ t->n_field[2].n_ptr = tree1(N_Empty);
+
+ if (max_prm < 1)
+ max_prm = 1;
+ return t;
+ }
diff --git a/src/iconc/ctree.h b/src/iconc/ctree.h
new file mode 100644
index 0000000..d38d3c4
--- /dev/null
+++ b/src/iconc/ctree.h
@@ -0,0 +1,200 @@
+/*
+ * Structure of a tree node.
+ */
+
+typedef struct node *nodeptr;
+
+/*
+ * Kinds of fields in syntax tree node.
+ */
+union field {
+ long n_val; /* integer-valued fields */
+ char *n_str; /* string-valued fields */
+ struct lentry *lsym; /* fields referencing local symbol table entries */
+ struct centry *csym; /* fields referencing constant symbol table entries */
+ struct implement *ip; /* fields referencing an operation */
+ struct pentry *proc; /* pointer to procedure entry */
+ struct rentry *rec; /* pointer to record entry */
+#ifdef OptimizeType
+ struct typinfo *typ; /* extra type field */
+#else /* OptimizeType */
+ unsigned int *typ; /* extra type field */
+#endif /* OptimizeType */
+ nodeptr n_ptr; /* subtree pointers */
+ };
+
+/*
+ * A store is an array that maps variables types (which are given indexes)
+ * to the types stored within the variables.
+ */
+struct store {
+ struct store *next;
+ int perm; /* flag: whether store stays across iterations */
+#ifdef OptimizeType
+ struct typinfo *types[1]; /* actual size is number of variables */
+#else /* OptimizeType */
+ unsigned int *types[1]; /* actual size is number of variables */
+#endif /* OptimizeType */
+ };
+
+/*
+ * Array of parameter types for an operation call.
+ */
+struct symtyps {
+ int nsyms; /* number of parameter symbols */
+ struct symtyps *next;
+#ifdef OptimizeType
+ struct typinfo *types[1]; /* really one for every symbol */
+#else /* OptimizeType */
+ unsigned int *types[1]; /* really one for every symbol */
+#endif /* OptimizeType */
+ };
+
+/*
+ * definitions for maintaining allocation status.
+ */
+#define NotAlloc 0 /* temp var neither in use nor reserved */
+#define InUnse 1 /* temp var currently contains live variable */
+/* n < 0 reserved: must be free by node with postn field = n */
+
+#define DescTmp 1 /* allocation of descriptor temporary */
+#define CIntTmp 2 /* allocation of C integer temporary */
+#define CDblTmp 3 /* allocation of C double temporary */
+#define SBuf 4 /* allocation of string buffer */
+#define CBuf 5 /* allocation of cset buffer */
+
+struct freetmp { /* list of things to free at a node */
+ int kind; /* DescTmp, CIntTmp, CDblTmp, SBuf, or CBuf */
+ int indx; /* index into status array */
+ int old; /* old status */
+ struct freetmp *next;
+ };
+
+struct node {
+ int n_type; /* node type */
+ char *n_file; /* name of file containing source program */
+ int n_line; /* line number in source program */
+ int n_col; /* column number in source program */
+ int flag;
+ int *new_types; /* pntr to array of struct types created here */
+#ifdef OptimizeType
+ struct typinfo *type; /* type of this expression */
+#else /* OptimizeType */
+ unsigned int *type; /* type of this expression */
+#endif /* OptimizeType */
+ struct store *store; /* if needed, store saved between iterations */
+ struct symtyps *symtyps; /* for operation in data base: types of arg syms */
+ nodeptr lifetime; /* lifetime of intermediate result */
+ int reuse; /* result may be reused without being recomputed */
+ nodeptr intrnl_lftm; /* lifetime of variables internal to operation */
+ int postn; /* relative position of node in execution order */
+ struct freetmp *freetmp; /* temporary variables to free at this point */
+ union field n_field[1]; /* node fields */
+ };
+
+/*
+ * NewNode - allocate a parse tree node with "size" fields.
+ */
+#define NewNode(size) (struct node *)alloc((unsigned int)\
+ (sizeof(struct node) + (size-1) * sizeof(union field)))
+
+/*
+ * Macros to access fields of parse tree nodes.
+ */
+
+#define Type(t) t->n_type
+#define File(t) t->n_file
+#define Line(t) t->n_line
+#define Col(t) t->n_col
+#define Tree0(t) t->n_field[0].n_ptr
+#define Tree1(t) t->n_field[1].n_ptr
+#define Tree2(t) t->n_field[2].n_ptr
+#define Tree3(t) t->n_field[3].n_ptr
+#define Tree4(t) t->n_field[4].n_ptr
+#define Val0(t) t->n_field[0].n_val
+#define Val1(t) t->n_field[1].n_val
+#define Val2(t) t->n_field[2].n_val
+#define Val3(t) t->n_field[3].n_val
+#define Val4(t) t->n_field[4].n_val
+#define Str0(t) t->n_field[0].n_str
+#define Str1(t) t->n_field[1].n_str
+#define Str2(t) t->n_field[2].n_str
+#define Str3(t) t->n_field[3].n_str
+#define LSym0(t) t->n_field[0].lsym
+#define CSym0(t) t->n_field[0].csym
+#define Impl0(t) t->n_field[0].ip
+#define Impl1(t) t->n_field[1].ip
+#define Rec1(t) t->n_field[1].rec
+#define Proc1(t) t->n_field[1].proc
+#define Typ4(t) t->n_field[4].typ
+
+/*
+ * External declarations.
+ */
+
+extern nodeptr yylval; /* parser's current token value */
+extern struct node tok_loc; /* "model" token holding current location */
+
+/*
+ * Node types.
+ */
+
+#define N_Activat 1 /* activation control structure */
+#define N_Alt 2 /* alternation operator */
+#define N_Apply 3 /* procedure application */
+#define N_Augop 4 /* augmented operator */
+#define N_Bar 5 /* generator control structure */
+#define N_Break 6 /* break statement */
+#define N_Case 7 /* case statement */
+#define N_Ccls 8 /* case clause */
+#define N_Clist 9 /* list of case clauses */
+#define N_Create 10 /* create control structure */
+#define N_Cset 11 /* cset literal */
+#define N_Elist 12 /* list of expressions */
+#define N_Empty 13 /* empty expression or statement */
+#define N_Field 14 /* record field reference */
+#define N_Id 15 /* identifier token */
+#define N_If 16 /* if-then-else statement */
+#define N_Int 17 /* integer literal */
+#define N_Invok 18 /* invocation */
+#define N_InvOp 19 /* invoke operation */
+#define N_InvProc 20 /* invoke operation */
+#define N_InvRec 21 /* invoke operation */
+#define N_Limit 22 /* LIMIT control structure */
+#define N_Loop 23 /* while, until, every, or repeat */
+#define N_Next 24 /* next statement */
+#define N_Not 25 /* not prefix control structure */
+#define N_Op 26 /* operator token */
+#define N_Proc 27 /* procedure */
+#define N_Real 28 /* real literal */
+#define N_Res 29 /* reserved word token */
+#define N_Ret 30 /* fail, return, or succeed */
+#define N_Scan 31 /* scan-using statement */
+#define N_Sect 32 /* s[i:j] (section) */
+#define N_Slist 33 /* list of statements */
+#define N_Str 34 /* string literal */
+#define N_SmplAsgn 35 /* simple assignment to named var */
+#define N_SmplAug 36 /* simple assignment to named var */
+
+#define AsgnDirect 0 /* rhs of special := can compute directly into var */
+#define AsgnCopy 1 /* special := must copy result into var */
+#define AsgnDeref 2 /* special := must dereference result into var */
+
+
+/*
+ * Macros for constructing basic nodes.
+ */
+
+#define CsetNode(a,b) i_str_leaf(N_Cset,&tok_loc,a,b)
+#define IdNode(a) c_str_leaf(N_Id,&tok_loc,a)
+#define IntNode(a) c_str_leaf(N_Int,&tok_loc,a)
+#define OpNode(a) int_leaf(N_Op,&tok_loc,a)
+#define RealNode(a) c_str_leaf(N_Real,&tok_loc,a)
+#define ResNode(a) int_leaf(N_Res,&tok_loc,a)
+#define StrNode(a,b) i_str_leaf(N_Str,&tok_loc,a,b)
+
+/*
+ * MultiUnary - create subtree from an operator symbol that represents
+ * multiple unary operators.
+ */
+#define MultiUnary(a,b) multiunary(optab[Val0(a)].tok.t_word, a, b)
diff --git a/src/iconc/dbase.c b/src/iconc/dbase.c
new file mode 100644
index 0000000..fdd3e50
--- /dev/null
+++ b/src/iconc/dbase.c
@@ -0,0 +1,196 @@
+/*
+ * dbase.c - routines to access data base of implementation information
+ * produced by rtt.
+ */
+#include "../h/gsupport.h"
+#include "../h/lexdef.h"
+#include "ctrans.h"
+#include "csym.h"
+#include "ctree.h"
+#include "ccode.h"
+#include "cproto.h"
+#include "cglobals.h"
+
+/*
+ * Prototypes.
+ */
+static int chck_spec (struct implement *ip);
+static int acpt_op (struct implement *ip);
+
+
+static struct optab *optr; /* pointer into operator table */
+
+/*
+ * readdb - read data base produced by rtt.
+ */
+void readdb(db_name)
+char *db_name;
+ {
+ char *op, *s;
+ int i;
+ struct implement *ip;
+ char buf[MaxPath]; /* file name construction buffer */
+ struct fileparts *fp;
+ unsigned hashval;
+
+ fp = fparse(db_name);
+ if (*fp->ext == '\0')
+ db_name = salloc(makename(buf, NULL, db_name, DBSuffix));
+ else if (!smatch(fp->ext, DBSuffix))
+ quitf("bad data base name: %s", db_name);
+
+ if (!db_open(db_name, &s))
+ db_err1(1, "cannot open data base");
+
+ if (largeints && (*s == 'N')) {
+ twarn("Warning, run-time system does not support large integers", NULL);
+ largeints = 0;
+ }
+
+ /*
+ * Read information about functions.
+ */
+ db_tbl("functions", bhash);
+
+ /*
+ * Read information about operators.
+ */
+ optr = optab;
+
+ /*
+ * read past operators header.
+ */
+ db_chstr("operators", "operators");
+
+ while ((op = db_string()) != NULL) {
+ if ((ip = db_impl('O')) == NULL)
+ db_err2(1, "no implementation information for operator", op);
+ ip->op = op;
+ if (acpt_op(ip)) {
+ db_code(ip);
+ hashval = IHasher(op);
+ ip->blink = ohash[hashval];
+ ohash[hashval] = ip;
+ db_chstr("end", "end");
+ }
+ else
+ db_dscrd(ip);
+ }
+ db_chstr("endsect", "endsect");
+
+ /*
+ * Read information about keywords.
+ */
+ db_tbl("keywords", khash);
+
+ db_close();
+
+ /*
+ * If error conversion is supported, make sure it is reflected in
+ * the minimum result sequence of operations.
+ */
+ if (err_conv) {
+ for (i = 0; i < IHSize; ++i)
+ for (ip = bhash[i]; ip != NULL; ip = ip->blink)
+ if (ip->ret_flag & DoesEFail)
+ ip->min_result = 0;
+ for (i = 0; i < IHSize; ++i)
+ for (ip = ohash[i]; ip != NULL; ip = ip->blink)
+ if (ip->ret_flag & DoesEFail)
+ ip->min_result = 0;
+ for (i = 0; i < IHSize; ++i)
+ for (ip = khash[i]; ip != NULL; ip = ip->blink)
+ if (ip->ret_flag & DoesEFail)
+ ip->min_result = 0;
+ }
+ }
+
+/*
+ * acpt_opt - given a data base entry for an operator determine if it
+ * is in iconc's operator table.
+ */
+static int acpt_op(ip)
+struct implement *ip;
+ {
+ register char *op;
+ register int opcmp;
+
+ /*
+ * Calls to this function are in lexical order by operator symbol continue
+ * searching operator table from where we left off.
+ */
+ op = ip->op;
+ for (;;) {
+ /*
+ * optab has augmented assignments out of lexical order. Skip anything
+ * which does not expect an implementation. This gets augmented
+ * assignments out of the way.
+ */
+ while (optr->expected == 0 && optr->tok.t_word != NULL)
+ ++optr;
+ if (optr->tok.t_word == NULL)
+ return chck_spec(ip);
+ opcmp = strcmp(op, optr->tok.t_word);
+ if (opcmp > 0)
+ ++optr;
+ else if (opcmp < 0)
+ return chck_spec(ip);
+ else {
+ if (ip->nargs == 1 && (optr->expected & Unary)) {
+ if (optr->unary == NULL) {
+ optr->unary = ip;
+ return 1;
+ }
+ else
+ return 0;
+ }
+ else if (ip->nargs == 2 && (optr->expected & Binary)) {
+ if (optr->binary == NULL) {
+ optr->binary = ip;
+ return 1;
+ }
+ else
+ return 0;
+ }
+ else
+ return chck_spec(ip);
+ }
+ }
+ }
+
+/*
+ * chck_spec - check whether the operator is one that does not use standard
+ * unary or binary syntax.
+ */
+static int chck_spec(ip)
+struct implement *ip;
+ {
+ register char *op;
+ int indx;
+
+ indx = -1;
+ op = ip->op;
+ if (strcmp(op, "...") == 0) {
+ if (ip->nargs == 2)
+ indx = ToOp;
+ else
+ indx = ToByOp;
+ }
+ else if (strcmp(op, "[:]") == 0)
+ indx = SectOp;
+ else if (strcmp(op, "[]") == 0)
+ indx = SubscOp;
+ else if (strcmp(op, "[...]") == 0)
+ indx = ListOp;
+
+ if (indx == -1) {
+ db_err2(0, "unexpected operator (or arity),", op);
+ return 0;
+ }
+ if (spec_op[indx] == NULL) {
+ spec_op[indx] = ip;
+ return 1;
+ }
+ else
+ return 0;
+ }
diff --git a/src/iconc/fixcode.c b/src/iconc/fixcode.c
new file mode 100644
index 0000000..b8c06e0
--- /dev/null
+++ b/src/iconc/fixcode.c
@@ -0,0 +1,372 @@
+/*
+ * fixcode.c - routines to "fix code" by determining what signals are returned
+ * by continuations and what must be done when they are. Also perform
+ * optional control flow optimizations.
+ */
+#include "../h/gsupport.h"
+#include "ctrans.h"
+#include "cglobals.h"
+#include "ccode.h"
+#include "ctree.h"
+#include "csym.h"
+#include "cproto.h"
+
+/*
+ * Prototypes for static functions.
+ */
+static struct code *ck_unneed (struct code *cd, struct code *lbl);
+static void clps_brch (struct code *branch);
+static void dec_refs (struct code *cd);
+static void rm_unrch (struct code *cd);
+
+/*
+ * fix_fncs - go through the generated C functions, determine how calls
+ * handle signals, in-line trivial functions where possible, remove
+ * goto's which immediately precede their labels, and remove unreachable
+ * code.
+ */
+void fix_fncs(fnc)
+struct c_fnc *fnc;
+ {
+ struct code *cd, *cd1;
+ struct code *contbody;
+ struct sig_act *sa;
+ struct sig_lst *sl;
+ struct code *call;
+ struct code *create;
+ struct code *ret_sig;
+ struct code *sig;
+ struct c_fnc *calledcont;
+ int no_break;
+ int collapse;
+
+ /*
+ * Fix any called functions and decide how the calls handle the
+ * returned signals.
+ */
+ fnc->flag |= CF_Mark;
+ for (call = fnc->call_lst; call != NULL; call = call->NextCall) {
+ calledcont = call->Cont;
+ if (calledcont != NULL) {
+ if (!(calledcont->flag & CF_Mark))
+ fix_fncs(calledcont);
+ if (calledcont->flag & CF_ForeignSig) {
+ call->Flags |= ForeignSig;
+ fnc->flag |= CF_ForeignSig;
+ }
+ }
+
+
+ /*
+ * Try to collapse call chains of continuations.
+ */
+ if (opt_cntrl && calledcont != NULL) {
+ contbody = calledcont->cd.next;
+ if (call->OperName == NULL && contbody->cd_id == C_RetSig) {
+ /*
+ * A direct call of a continuation which consists of just a
+ * return. Replace call with code to handle the returned signal.
+ */
+ ret_sig = contbody->SigRef->sig;
+ if (ret_sig == &resume)
+ cd1 = sig_cd(call->ContFail, fnc);
+ else
+ cd1 = sig_cd(ret_sig, fnc);
+ cd1->prev = call->prev;
+ cd1->prev->next = cd1;
+ cd1->next = call->next;
+ if (cd1->next != NULL)
+ cd1->next->prev = cd1;
+ --calledcont->ref_cnt;
+ continue; /* move on to next call */
+ }
+ else if (contbody->cd_id == C_CallSig && contbody->next == NULL) {
+ /*
+ * The called continuation contains only a call.
+ */
+ if (call->OperName == NULL) {
+ /*
+ * We call the continuation directly, so we can in-line it.
+ * We must replace signal returns with appropriate actions.
+ */
+ if (--calledcont->ref_cnt != 0 && contbody->Cont != NULL)
+ ++contbody->Cont->ref_cnt;
+ call->OperName = contbody->OperName;
+ call->ArgLst = contbody->ArgLst;
+ call->Cont = contbody->Cont;
+ call->Flags = contbody->Flags;
+ for (sa = contbody->SigActs; sa != NULL; sa = sa->next) {
+ ret_sig = sa->cd->SigRef->sig;
+ if (ret_sig == &resume)
+ cd1 = sig_cd(call->ContFail, fnc);
+ else
+ cd1 = sig_cd(ret_sig, fnc);
+ call->SigActs = new_sgact(sa->sig, cd1, call->SigActs);
+ }
+ continue; /* move on to next call */
+ }
+ else if (contbody->OperName == NULL) {
+ /*
+ * The continuation simply calls another continuation. We can
+ * eliminate the intermediate continuation as long as we can
+ * move signal conversions to the other side of the operation.
+ * The operation only intercepts resume signals.
+ */
+ collapse = 1;
+ for (sa = contbody->SigActs; sa != NULL; sa = sa->next) {
+ ret_sig = sa->cd->SigRef->sig;
+ if (sa->sig != ret_sig && (sa->sig == &resume ||
+ ret_sig == &resume))
+ collapse = 0;
+ }
+ if (collapse) {
+ if (--calledcont->ref_cnt != 0 && contbody->Cont != NULL)
+ ++contbody->Cont->ref_cnt;
+ call->Cont = contbody->Cont;
+ for (sa = contbody->SigActs; sa != NULL; sa = sa->next) {
+ ret_sig = sa->cd->SigRef->sig;
+ if (ret_sig != &resume)
+ call->SigActs = new_sgact(sa->sig, sig_cd(ret_sig, fnc),
+ call->SigActs);
+ }
+ continue; /* move on to next call */
+ }
+ }
+ }
+ }
+
+ /*
+ * We didn't do any optimizations. We must still figure out
+ * out how to handle signals returned by the continuation.
+ */
+ if (calledcont != NULL) {
+ for (sl = calledcont->sig_lst; sl != NULL; sl = sl->next) {
+ if (sl->ref_cnt > 0) {
+ sig = sl->sig;
+ /*
+ * If an operation is being called, it handles failure from the
+ * continuation.
+ */
+ if (sig != &resume || call->OperName == NULL) {
+ if (sig == &resume)
+ cd1 = sig_cd(call->ContFail, fnc);
+ else
+ cd1 = sig_cd(sig, fnc);
+ call->SigActs = new_sgact(sig, cd1, call->SigActs);
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * fix up the signal handling in the functions implementing co-expressions.
+ */
+ for (create = fnc->creatlst; create != NULL; create = create->NextCreat)
+ fix_fncs(create->Cont);
+
+ if (!opt_cntrl)
+ return; /* control flow optimizations disabled. */
+ /*
+ * Collapse branch chains and remove unreachable code.
+ */
+ for (cd = &(fnc->cd); cd != NULL; cd = cd->next) {
+ switch (cd->cd_id) {
+ case C_CallSig:
+ no_break = 1;
+ for (sa = cd->SigActs; sa != NULL; sa = sa->next) {
+ if (sa->cd->cd_id == C_Break) {
+ switch (cd->next->cd_id) {
+ case C_Goto:
+ sa->cd->cd_id = cd->next->cd_id;
+ sa->cd->Lbl = cd->next->Lbl;
+ ++sa->cd->Lbl->RefCnt;
+ break;
+ case C_RetSig:
+ sa->cd->cd_id = cd->next->cd_id;
+ sa->cd->SigRef= cd->next->SigRef;
+ ++sa->cd->SigRef->ref_cnt;
+ break;
+ default:
+ no_break = 0;
+ }
+ }
+ if (sa->cd->cd_id == C_Goto)
+ clps_brch(sa->cd);
+ }
+ if (no_break)
+ rm_unrch(cd);
+ /*
+ * Try converting gotos into breaks.
+ */
+ for (sa = cd->SigActs; sa != NULL; sa = sa->next)
+ if (sa->cd->cd_id == C_Goto) {
+ cd1 = cd->next;
+ while (cd1 != NULL && (cd1->cd_id == C_Label ||
+ cd1->cd_id == C_RBrack)) {
+ if (cd1 == sa->cd->Lbl) {
+ sa->cd->cd_id = C_Break;
+ --cd1->RefCnt;
+ break;
+ }
+ cd1 = cd1->next;
+ }
+ }
+ break;
+
+ case C_Goto:
+ clps_brch(cd);
+ rm_unrch(cd);
+ if (cd->cd_id == C_Goto)
+ ck_unneed(cd, cd->Lbl);
+ break;
+
+ case C_If:
+ if (cd->ThenStmt->cd_id == C_Goto) {
+ clps_brch(cd->ThenStmt);
+ if (cd->ThenStmt->cd_id == C_Goto)
+ ck_unneed(cd, cd->ThenStmt->Lbl);
+ }
+ break;
+
+ case C_PFail:
+ case C_PRet:
+ case C_RetSig:
+ rm_unrch(cd);
+ break;
+ }
+ }
+
+ /*
+ * If this function only contains a return, indicate that we can
+ * call a shared signal returning function instead of it. This is
+ * a special case of "common subROUTINE elimination".
+ */
+ if (fnc->cd.next->cd_id == C_RetSig)
+ fnc->flag |= CF_SigOnly;
+ }
+
+/*
+ * clps_brch - collapse branch chains.
+ */
+static void clps_brch(branch)
+struct code *branch;
+ {
+ struct code *cd;
+ int save_id;
+
+ cd = branch->Lbl->next;
+ while (cd->cd_id == C_Label)
+ cd = cd->next;
+
+ /*
+ * Avoid infinite recursion on empty infinite loops.
+ */
+ save_id = branch->cd_id;
+ branch->cd_id = 0;
+ if (cd->cd_id == C_Goto)
+ clps_brch(cd);
+ branch->cd_id = save_id;
+
+ switch (cd->cd_id) {
+ case C_Goto:
+ --branch->Lbl->RefCnt;
+ ++cd->Lbl->RefCnt;
+ branch->Lbl = cd->Lbl;
+ break;
+ case C_RetSig:
+ /*
+ * This optimization requires that C_Goto have as many fields
+ * as C_RetSig.
+ */
+ --branch->Lbl->RefCnt;
+ ++cd->SigRef->ref_cnt;
+ branch->cd_id = C_RetSig;
+ branch->SigRef = cd->SigRef;
+ break;
+ }
+ }
+
+/*
+ * rm_unrch - any code after the given point up to the next label is
+ * unreachable. Remove it.
+ */
+static void rm_unrch(cd)
+struct code *cd;
+ {
+ struct code *cd1;
+
+ for (cd1 = cd->next; cd1 != NULL && cd1->cd_id != C_LBrack &&
+ (cd1->cd_id != C_Label || cd1->RefCnt == 0); cd1 = cd1->next) {
+ if (cd1->cd_id == C_RBrack) {
+ /*
+ * Continue deleting past a '}', but don't delete the '}' itself.
+ */
+ cd->next = cd1;
+ cd1->prev = cd;
+ cd = cd1;
+ }
+ else
+ dec_refs(cd1);
+ }
+ cd->next = cd1;
+ if (cd1 != NULL)
+ cd1->prev = cd;
+ }
+
+/*
+ * dec_refs - decrement reference counts for things this code references.
+ */
+static void dec_refs(cd)
+struct code *cd;
+ {
+ struct sig_act *sa;
+
+ if (cd == NULL)
+ return;
+ switch (cd->cd_id) {
+ case C_Goto:
+ --cd->Lbl->RefCnt;
+ return;
+ case C_RetSig:
+ --cd->SigRef->ref_cnt;
+ return;
+ case C_CallSig:
+ if (cd->Cont != NULL)
+ --cd->Cont->ref_cnt;
+ for (sa = cd->SigActs; sa != NULL; sa = sa->next)
+ dec_refs(sa->cd);
+ return;
+ case C_If:
+ dec_refs(cd->ThenStmt);
+ return;
+ case C_Create:
+ --cd->Cont->ref_cnt;
+ return;
+ }
+ }
+
+/*
+ * ck_unneed - if there is nothing between a goto and its label, except
+ * perhaps other labels or '}', it is useless, so remove it.
+ */
+static struct code *ck_unneed(cd, lbl)
+struct code *cd;
+struct code *lbl;
+ {
+ struct code *cd1;
+
+ cd1 = cd->next;
+ while (cd1 != NULL && (cd1->cd_id == C_Label || cd1->cd_id == C_RBrack)) {
+ if (cd1 == lbl) {
+ cd = cd->prev;
+ cd->next = cd->next->next;
+ cd->next->prev = cd;
+ --lbl->RefCnt;
+ break;
+ }
+ cd1 = cd1->next;
+ }
+ return cd;
+ }
+
diff --git a/src/iconc/incheck.c b/src/iconc/incheck.c
new file mode 100644
index 0000000..d4110f9
--- /dev/null
+++ b/src/iconc/incheck.c
@@ -0,0 +1,802 @@
+/*
+ * incheck.c - analyze a run-time operation using type information.
+ * Determine wither the operation can be in-lined and what kinds
+ * of parameter passing optimizations can be done.
+ */
+#include "../h/gsupport.h"
+#include "ctrans.h"
+#include "cglobals.h"
+#include "csym.h"
+#include "ctree.h"
+#include "ccode.h"
+#include "cproto.h"
+
+struct op_symentry *cur_symtab; /* symbol table for current operation */
+
+/*
+ * Prototypes for static functions.
+ */
+static struct code *and_cond (struct code *cd1, struct code *cd2);
+static int cnv_anlz (unsigned int typcd, struct il_code *src,
+ struct il_c *dflt, struct il_c *dest,
+ struct code **cdp);
+static int defer_il (struct il_code *il);
+static int if_anlz (struct il_code *il);
+static void ilc_anlz (struct il_c *ilc);
+static int il_anlz (struct il_code *il);
+static void ret_anlz (struct il_c *ilc);
+static int tc_anlz (struct il_code *il, int has_dflt);
+
+static int n_branches; /* number branches caused by run-time type checking */
+static int side_effect; /* abstract clause indicates side-effect */
+static int n_vararg; /* size of variable part of arg list to operation */
+static int n_susp; /* number of suspends */
+static int n_ret; /* number of returns */
+
+/*
+ * do_inlin - determine if this operation can be in-lined at the current
+ * invocation. Also gather information about how arguments are used,
+ * and determine where the success continuation for the operation
+ * should be put.
+ */
+int do_inlin(impl, n, cont_loc, symtab, n_va)
+struct implement *impl;
+nodeptr n;
+int *cont_loc;
+struct op_symentry *symtab;
+int n_va;
+ {
+ int nsyms;
+ int i;
+
+ /*
+ * Copy arguments needed by other functions into globals and
+ * initialize flags and counters for information to be gathered
+ * during analysis.
+ */
+ cur_symtyps = n->symtyps; /* mapping from arguments to types */
+ cur_symtab = symtab; /* parameter info to be filled in */
+ n_vararg = n_va;
+ n_branches = 0;
+ side_effect = 0;
+ n_susp = 0;
+ n_ret = 0;
+
+ /*
+ * Analyze the code for this operation using type information for
+ * the arguments to the invocation.
+ */
+ il_anlz(impl->in_line);
+
+
+ /*
+ * Don't in-line if there is more than one decision made based on
+ * run-time type checks (this is a heuristic).
+ */
+ if (n_branches > 1)
+ return 0;
+
+ /*
+ * If the operation (after eliminating code not used in this context)
+ * has one suspend and no returns, the "success continuation" can
+ * be placed in-line at the suspend site. Otherwise, any suspends
+ * require a separate function for the continuation.
+ */
+ if (n_susp == 1 && n_ret == 0)
+ *cont_loc = SContIL; /* in-line continuation */
+ else if (n_susp > 0)
+ *cont_loc = SepFnc; /* separate function for continuation */
+ else
+ *cont_loc = EndOper; /* place "continuation" after the operation */
+
+ /*
+ * When an argument at the source level is an Icon variable, it is
+ * sometimes safe to use it directly in the generated code as the
+ * argument to the operation. However, it is NOT safe under the
+ * following conditions:
+ *
+ * - if the operation modifies the argument.
+ * - if the operation suspends and resumes so that intervening
+ * changes to the variable would be visible as changes to the
+ * argument.
+ * - if the operation has side effects that might involve the
+ * variable and be visible as changes to the argument.
+ */
+ nsyms = (cur_symtyps == NULL ? 0 : cur_symtyps->nsyms);
+ for (i = 0; i < nsyms; ++i)
+ if (symtab[i].n_mods == 0 && n->intrnl_lftm == n && !side_effect)
+ symtab[i].var_safe = 1;
+
+ return 1;
+ }
+
+/*
+ * il_anlz - analyze a piece of RTL code. Return an indication of
+ * whether execution can continue beyond it.
+ */
+static int il_anlz(il)
+struct il_code *il;
+ {
+ int fall_thru;
+ int ncases;
+ int condition;
+ int indx;
+ int i, j;
+
+ if (il == NULL)
+ return 1;
+
+ switch (il->il_type) {
+ case IL_Const: /* should have been replaced by literal node */
+ return 1;
+
+ case IL_If1:
+ /*
+ * if-then statement. Determine whether the condition may
+ * succeed or fail. Analyze the then clause if needed.
+ */
+ condition = if_anlz(il->u[0].fld);
+ fall_thru = 0;
+ if (condition & MaybeTrue)
+ fall_thru |= il_anlz(il->u[1].fld);
+ if (condition & MaybeFalse)
+ fall_thru = 1;
+ return fall_thru;
+
+ case IL_If2:
+ /*
+ * if-then-else statement. Determine whether the condition may
+ * succeed or fail. Analyze the "then" clause and the "else"
+ * clause if needed.
+ */
+ condition = if_anlz(il->u[0].fld);
+ fall_thru = 0;
+ if (condition & MaybeTrue)
+ fall_thru |= il_anlz(il->u[1].fld);
+ if (condition & MaybeFalse)
+ fall_thru |= il_anlz(il->u[2].fld);
+ return fall_thru;
+
+ case IL_Tcase1:
+ /*
+ * type_case statement with no default clause.
+ */
+ return tc_anlz(il, 0);
+
+ case IL_Tcase2:
+ /*
+ * type_case statement with a default clause.
+ */
+ return tc_anlz(il, 1);
+
+ case IL_Lcase:
+ /*
+ * len_case statement. Determine which case matches the number
+ * of arguments.
+ */
+ ncases = il->u[0].n;
+ indx = 1;
+ for (i = 0; i < ncases; ++i) {
+ if (il->u[indx++].n == n_vararg) /* selection number */
+ return il_anlz(il->u[indx].fld); /* action */
+ ++indx;
+ }
+ return il_anlz(il->u[indx].fld); /* default */
+
+ case IL_Acase: {
+ /*
+ * arith_case statement.
+ */
+ struct il_code *var1;
+ struct il_code *var2;
+ int maybe_int;
+ int maybe_dbl;
+ int chk1;
+ int chk2;
+
+ var1 = il->u[0].fld;
+ var2 = il->u[1].fld;
+ arth_anlz(var1, var2, &maybe_int, &maybe_dbl, &chk1, NULL,
+ &chk2, NULL);
+
+ /*
+ * Analyze the selected case (note, large integer code is not
+ * currently in-lined and can be ignored).
+ */
+ fall_thru = 0;
+ if (maybe_int)
+ fall_thru |= il_anlz(il->u[2].fld); /* C_integer action */
+ if (maybe_dbl)
+ fall_thru |= il_anlz(il->u[4].fld); /* C_double action */
+ return fall_thru;
+ }
+
+ case IL_Err1:
+ /*
+ * runerr() with no offending value.
+ */
+ return 0;
+
+ case IL_Err2:
+ /*
+ * runerr() with an offending value. Note the reference to
+ * the offending value descriptor.
+ */
+ indx = il->u[1].fld->u[0].n; /* symbol table index of variable */
+ if (indx < cur_symtyps->nsyms)
+ ++cur_symtab[indx].n_refs;
+ return 0;
+
+ case IL_Block:
+ /*
+ * inline {...} statement.
+ */
+ i = il->u[1].n + 2; /* skip declaration stuff */
+ ilc_anlz(il->u[i].c_cd); /* body of block */
+ return il->u[0].n;
+
+ case IL_Call:
+ /*
+ * call to body function.
+ */
+ if (il->u[3].n & DoesSusp)
+ n_susp = 2; /* force continuation into separate function */
+
+ /*
+ * Analyze the C code for prototype parameter declarations
+ * and actual arguments. There are twice as many pieces of
+ * C code to look at as there are parameters.
+ */
+ j = 2 * il->u[7].n;
+ i = 8; /* index of first piece of C code */
+ while (j--)
+ ilc_anlz(il->u[i++].c_cd);
+ return ((il->u[3].n & DoesFThru) != 0);
+
+ case IL_Lst:
+ /*
+ * Two consecutive pieces of RTL code.
+ */
+ fall_thru = il_anlz(il->u[0].fld);
+ if (fall_thru)
+ fall_thru = il_anlz(il->u[1].fld);
+ return fall_thru;
+
+ case IL_Abstr:
+ /*
+ * abstract type computation. See if it indicates side effects.
+ */
+ if (il->u[0].fld != NULL)
+ side_effect = 1;
+ return 1;
+
+ default:
+ fprintf(stderr, "compiler error: unknown info in data base\n");
+ exit(EXIT_FAILURE);
+ /* NOTREACHED */
+ }
+ }
+
+/*
+ * if_anlz - analyze the condition of an if statement.
+ */
+static int if_anlz(il)
+struct il_code *il;
+ {
+ int cond;
+ int cond1;
+
+ if (il->il_type == IL_Bang) {
+ /*
+ * ! <condition>, negate the result of the condition
+ */
+ cond1 = cond_anlz(il->u[0].fld, NULL);
+ cond = 0;
+ if (cond1 & MaybeTrue)
+ cond = MaybeFalse;
+ if (cond1 & MaybeFalse)
+ cond |= MaybeTrue;
+ }
+ else
+ cond = cond_anlz(il, NULL);
+ if (cond == (MaybeTrue | MaybeFalse))
+ ++n_branches; /* must make a run-time decision */
+ return cond;
+ }
+
+/*
+ * cond_anlz - analyze a simple condition or the conjunction of two
+ * conditions. If cdp is not NULL, use it to return a pointer code
+ * that implements the condition.
+ */
+int cond_anlz(il, cdp)
+struct il_code *il;
+struct code **cdp;
+ {
+ struct code *cd1;
+ struct code *cd2;
+ int cond1;
+ int cond2;
+ int indx;
+
+ switch (il->il_type) {
+ case IL_And:
+ /*
+ * <cond> && <cond>
+ */
+ cond1 = cond_anlz(il->u[0].fld, (cdp == NULL ? NULL : &cd1));
+ if (cond1 & MaybeTrue) {
+ cond2 = cond_anlz(il->u[1].fld, (cdp == NULL ? NULL : &cd2));
+ if (cdp != NULL) {
+ if (!(cond2 & MaybeTrue))
+ *cdp = NULL;
+ else
+ *cdp = and_cond(cd1, cd2);
+ }
+ return (cond1 & MaybeFalse) | cond2;
+ }
+ else {
+ if (cdp != NULL)
+ *cdp = cd1;
+ return cond1;
+ }
+
+ case IL_Cnv1:
+ /*
+ * cnv:<dest-type>(<source>)
+ */
+ return cnv_anlz(il->u[0].n, il->u[1].fld, NULL, NULL, cdp);
+
+ case IL_Cnv2:
+ /*
+ * cnv:<dest-type>(<source>,<destination>)
+ */
+ return cnv_anlz(il->u[0].n, il->u[1].fld, NULL, il->u[2].c_cd, cdp);
+
+ case IL_Def1:
+ /*
+ * def:<dest-type>(<source>,<default-value>)
+ */
+ return cnv_anlz(il->u[0].n, il->u[1].fld, il->u[2].c_cd, NULL, cdp);
+
+ case IL_Def2:
+ /*
+ * def:<dest-type>(<source>,<default-value>,<destination>)
+ */
+ return cnv_anlz(il->u[0].n, il->u[1].fld, il->u[2].c_cd, il->u[3].c_cd,
+ cdp);
+
+ case IL_Is:
+ /*
+ * is:<type-name>(<variable>)
+ */
+ indx = il->u[1].fld->u[0].n;
+ cond1 = eval_is(il->u[0].n, indx);
+ if (cdp == NULL) {
+ if (indx < cur_symtyps->nsyms && cond1 == (MaybeTrue | MaybeFalse))
+ ++cur_symtab[indx].n_refs;
+ }
+ else {
+ if (cond1 == (MaybeTrue | MaybeFalse))
+ *cdp = typ_chk(il->u[1].fld, il->u[0].n);
+ else
+ *cdp = NULL;
+ }
+ return cond1;
+
+ default:
+ fprintf(stderr, "compiler error: unknown info in data base\n");
+ exit(EXIT_FAILURE);
+ /* NOTREACHED */
+ }
+ }
+
+
+/*
+ * and_cond - construct && of two conditions, either of which may have
+ * been optimized away.
+ */
+static struct code *and_cond(cd1, cd2)
+struct code *cd1;
+struct code *cd2;
+ {
+ struct code *cd;
+
+ if (cd1 == NULL)
+ return cd2;
+ else if (cd2 == NULL)
+ return cd1;
+ else {
+ cd = alc_ary(3);
+ cd->ElemTyp(0) = A_Ary;
+ cd->Array(0) = cd1;
+ cd->ElemTyp(1) = A_Str;
+ cd->Str(1) = " && ";
+ cd->ElemTyp(2) = A_Ary;
+ cd->Array(2) = cd2;
+ return cd;
+ }
+ }
+
+/*
+ * cnv_anlz - analyze a type conversion. Determine whether it can succeed
+ * and, if requested, produce code to perform the conversion. Also
+ * gather information about the variables it uses.
+ */
+static int cnv_anlz(typcd, src, dflt, dest, cdp)
+unsigned int typcd;
+struct il_code *src;
+struct il_c *dflt;
+struct il_c *dest;
+struct code **cdp;
+ {
+ struct val_loc *src_loc;
+ int cond;
+ int cnv_flags;
+ int indx;
+
+ /*
+ * Find out what is going on in the default and destination subexpressions.
+ * (The information is used elsewhere.)
+ */
+ ilc_anlz(dflt);
+ ilc_anlz(dest);
+
+ if (cdp != NULL)
+ *cdp = NULL; /* clear code pointer in case it is not set below */
+
+ /*
+ * Determine whether the conversion may succeed, whether it may fail,
+ * and whether it may actually convert a value or use the default
+ * value when it succeeds.
+ */
+ indx = src->u[0].n; /* symbol table index for source of conversion */
+ cond = eval_cnv(typcd, indx, dflt != NULL, &cnv_flags);
+
+ /*
+ * Many optimizations are possible depending on whether a conversion
+ * is actually needed, whether type checking is needed, whether defaulting
+ * is done, and whether there is an explicit destination. Several
+ * optimizations are performed here; more may be added in the future.
+ */
+ if (!(cnv_flags & MayDefault))
+ dflt = NULL; /* demote defaulting to simple conversion */
+
+ if (cond & MaybeTrue) {
+ if (cnv_flags == MayKeep && dest == NULL) {
+ /*
+ * No type conversion, defaulting, or copying is needed.
+ */
+ if (cond & MaybeFalse) {
+ /*
+ * A type check is needed.
+ */
+ ++cur_symtab[indx].n_refs; /* non-modifying reference to source. */
+ if (cdp != NULL) {
+ switch (typcd) {
+ case TypECInt:
+ *cdp = typ_chk(src, TypCInt);
+ break;
+ case TypEInt:
+ *cdp = typ_chk(src, int_typ);
+ break;
+ case TypTStr:
+ *cdp = typ_chk(src, str_typ);
+ break;
+ case TypTCset:
+ *cdp = typ_chk(src, cset_typ);
+ break;
+ default:
+ *cdp = typ_chk(src, typcd);
+ }
+ }
+ }
+
+ if (cdp != NULL) {
+ /*
+ * Conversion from an integer to a C_integer can be done without
+ * any executable code; this is not considered a real conversion.
+ * It is accomplished by changing the symbol table so only the
+ * dword of the descriptor is accessed.
+ */
+ switch (typcd) {
+ case TypCInt:
+ case TypECInt:
+ cur_symtab[indx].loc = loc_cpy(cur_symtab[indx].loc, M_CInt);
+ break;
+ }
+ }
+ }
+ else if (dest != NULL && cnv_flags == MayKeep && cond == MaybeTrue) {
+ /*
+ * There is an explicit destination, but no conversion, defaulting,
+ * or type checking is needed. Just copy the value to the
+ * destination.
+ */
+ ++cur_symtab[indx].n_refs; /* non-modifying reference to source */
+ if (cdp != NULL) {
+ src_loc = cur_symtab[indx].loc;
+ switch (typcd) {
+ case TypCInt:
+ case TypECInt:
+ /*
+ * The value is in the dword of the descriptor.
+ */
+ src_loc = loc_cpy(src_loc, M_CInt);
+ break;
+ }
+ *cdp = il_copy(dest, src_loc);
+ }
+ }
+ else if (cnv_flags == MayDefault) {
+ /*
+ * The default value is used.
+ */
+ if (dest == NULL)
+ ++cur_symtab[indx].n_mods; /* modifying reference */
+ if (cdp != NULL)
+ *cdp = il_dflt(typcd, src, dflt, dest);
+ }
+ else {
+ /*
+ * Produce code to do the actual conversion.
+ * Determine whether the source location is being modified
+ * or just referenced.
+ */
+ if (dest == NULL) {
+ /*
+ * "In place" conversion.
+ */
+ switch (typcd) {
+ case TypCDbl:
+ case TypCInt:
+ case TypECInt:
+ /*
+ * not really converted in-place.
+ */
+ ++cur_symtab[indx].n_refs; /* non-modifying reference */
+ break;
+ default:
+ ++cur_symtab[indx].n_mods; /* modifying reference */
+ }
+ }
+ else
+ ++cur_symtab[indx].n_refs; /* non-modifying reference */
+
+ if (cdp != NULL)
+ *cdp = il_cnv(typcd, src, dflt, dest);
+ }
+ }
+ return cond;
+ }
+
+/*
+ * ilc_anlz - gather information about in-line C code.
+ */
+static void ilc_anlz(ilc)
+struct il_c *ilc;
+ {
+ while (ilc != NULL) {
+ switch(ilc->il_c_type) {
+ case ILC_Ref:
+ /*
+ * Non-modifying reference to variable
+ */
+ if (ilc->n != RsltIndx) {
+ ++cur_symtab[ilc->n].n_refs;
+ }
+ break;
+
+ case ILC_Mod:
+ /*
+ * Modifying reference to variable
+ */
+ if (ilc->n != RsltIndx) {
+ ++cur_symtab[ilc->n].n_mods;
+ }
+ break;
+
+ case ILC_Ret:
+ /*
+ * Return statement.
+ */
+ ++n_ret;
+ ret_anlz(ilc);
+ break;
+
+ case ILC_Susp:
+ /*
+ * Suspend statement.
+ */
+ ++n_susp;
+ ret_anlz(ilc);
+ break;
+
+ case ILC_CGto:
+ /*
+ * Conditional goto.
+ */
+ ilc_anlz(ilc->code[0]);
+ break;
+ }
+ ilc = ilc->next;
+ }
+ }
+
+/*
+ * ret_anlz - gather information about the in-line C code associated
+ * with a return or suspend.
+ */
+static void ret_anlz(ilc)
+struct il_c *ilc;
+ {
+ int i;
+ int j;
+
+ /*
+ * See if the code is simply returning a parameter.
+ */
+ if (ilc->n == RetDesc && ilc->code[0]->il_c_type == ILC_Ref &&
+ ilc->code[0]->next == NULL) {
+ j = ilc->code[0]->n;
+ ++cur_symtab[j].n_refs;
+ ++cur_symtab[j].n_rets;
+ }
+ else {
+ for (i = 0; i < 3 && ilc->code[i] != NULL; ++i)
+ ilc_anlz(ilc->code[i]);
+ }
+ }
+
+/*
+ * deref_il - dummy routine to pass to a code walk.
+ */
+/*ARGSUSED*/
+static int defer_il(il)
+struct il_code *il;
+ {
+ /*
+ * Called for each case in a type_case statement that might be selected.
+ * However, the actual analysis of the case, if it is needed,
+ * is done elsewhere, so just return.
+ */
+ return 0;
+ }
+
+/*
+ * findcases - determine how many cases of an type_case statement may
+ * be true. If there are two or less, determine the "if" statement
+ * that can be used (if there are more than two, the code is not
+ * in-lined).
+ */
+void findcases(il, has_dflt, case_anlz)
+struct il_code *il;
+int has_dflt;
+struct case_anlz *case_anlz;
+ {
+ int i;
+
+ case_anlz->n_cases = 0;
+ case_anlz->typcd = -1;
+ case_anlz->il_then = NULL;
+ case_anlz->il_else = NULL;
+ i = type_case(il, defer_il, case_anlz);
+ /*
+ * See if the explicit cases have accounted for all possible
+ * types that might be present.
+ */
+ if (i == -1) { /* all types accounted for */
+ if (case_anlz->il_else == NULL && case_anlz->il_then != NULL) {
+ /*
+ * We don't need to actually check the type.
+ */
+ case_anlz->il_else = case_anlz->il_then;
+ case_anlz->il_then = NULL;
+ case_anlz->typcd = -1;
+ }
+ }
+ else { /* not all types accounted for */
+ if (case_anlz->il_else != NULL)
+ case_anlz->n_cases = 3; /* force no inlining */
+ else if (has_dflt)
+ case_anlz->il_else = il->u[i].fld; /* default */
+ }
+
+ if (case_anlz->n_cases > 2)
+ n_branches = 2; /* no in-lining */
+ else if (case_anlz->il_then != NULL)
+ ++n_branches;
+ }
+
+
+/*
+ * tc_anlz - analyze a type_case statement. It is only of interest for
+ * in-lining if it can be reduced to an "if" statement or an
+ * unconditional statement.
+ */
+static int tc_anlz(il, has_dflt)
+struct il_code *il;
+int has_dflt;
+ {
+ struct case_anlz case_anlz;
+ int fall_thru;
+ int indx;
+
+ findcases(il, has_dflt, &case_anlz);
+
+ if (case_anlz.il_else == NULL)
+ fall_thru = 1; /* either no code at all or condition with no "else" */
+ else
+ fall_thru = 0; /* either unconditional or if-then-else: check code */
+
+ if (case_anlz.il_then != NULL) {
+ fall_thru |= il_anlz(case_anlz.il_then);
+ indx = il->u[0].fld->u[0].n; /* symbol table index of variable */
+ if (indx < cur_symtyps->nsyms)
+ ++cur_symtab[indx].n_refs;
+ }
+ if (case_anlz.il_else != NULL)
+ fall_thru |= il_anlz(case_anlz.il_else);
+ return fall_thru;
+ }
+
+/*
+ * arth_anlz - analyze the type checking of an arith_case statement.
+ */
+void arth_anlz(var1, var2, maybe_int, maybe_dbl, chk1, conv1p, chk2, conv2p)
+struct il_code *var1;
+struct il_code *var2;
+int *maybe_int;
+int *maybe_dbl;
+int *chk1;
+struct code **conv1p;
+int *chk2;
+struct code **conv2p;
+ {
+ int cond;
+ int cnv_typ;
+
+
+ /*
+ * First do an analysis to find out which cases are needed. This is
+ * more accurate than analysing the conversions separately, but does
+ * not get all the information we need.
+ */
+ eval_arith(var1->u[0].n, var2->u[0].n, maybe_int, maybe_dbl);
+
+ if (*maybe_int & (largeints | *maybe_dbl)) {
+ /*
+ * Too much type checking; don't bother with these cases. Force no
+ * in-lining.
+ */
+ n_branches += 2;
+ }
+ else {
+ if (*maybe_int)
+ cnv_typ = TypCInt;
+ else
+ cnv_typ = TypCDbl;
+
+ /*
+ * See exactly what kinds of conversions/type checks are needed and,
+ * if requested, generate code for them.
+ */
+ *chk1 = 0;
+ *chk2 = 0;
+
+ cond = cnv_anlz(cnv_typ, var1, NULL, NULL, conv1p);
+ if (cond & MaybeFalse) {
+ ++n_branches; /* run-time decision */
+ *chk1 = 1;
+ if (var1->u[0].n < cur_symtyps->nsyms)
+ ++cur_symtab[var1->u[0].n].n_refs; /* used in runerr2() */
+ }
+ cond = cnv_anlz(cnv_typ, var2, NULL, NULL, conv2p);
+ if (cond & MaybeFalse) {
+ ++n_branches; /* run-time decision */
+ *chk2 = 1;
+ if (var2->u[0].n < cur_symtyps->nsyms)
+ ++cur_symtab[var2->u[0].n].n_refs; /* used in runerr2() */
+ }
+ }
+ }
diff --git a/src/iconc/inline.c b/src/iconc/inline.c
new file mode 100644
index 0000000..234229c
--- /dev/null
+++ b/src/iconc/inline.c
@@ -0,0 +1,2007 @@
+/*
+ * inline.c - routines to put run-time routines in-line.
+ */
+#include "../h/gsupport.h"
+#include "ctrans.h"
+#include "ccode.h"
+#include "csym.h"
+#include "ctree.h"
+#include "cproto.h"
+#include "cglobals.h"
+
+/*
+ * Prototypes for static functions.
+ */
+static void arth_arg ( struct il_code *var,
+ struct val_loc *v_orig, int chk,
+ struct code *cnv);
+static int body_fnc (struct il_code *il);
+static void chkforblk (void);
+static void cnv_dest (int loc, int is_cstr,
+ struct il_code *src, int sym_indx,
+ struct il_c *dest, struct code *cd, int i);
+static void dwrd_asgn (struct val_loc *vloc, char *typ);
+static struct il_c *line_ilc (struct il_c *ilc);
+static int gen_if (struct code *cond_cd,
+ struct il_code *il_then,
+ struct il_code *il_else,
+ struct val_loc **locs);
+static int gen_il (struct il_code *il);
+static void gen_ilc (struct il_c *il);
+static void gen_ilret (struct il_c *ilc);
+static int gen_tcase (struct il_code *il, int has_dflt);
+static void il_var (struct il_code *il, struct code *cd,
+ int indx);
+static void mrg_locs (struct val_loc **locs);
+static struct code *oper_lbl (char *s);
+static void part_asgn (struct val_loc *vloc, char *asgn,
+ struct il_c *value);
+static void rstr_locs (struct val_loc **locs);
+static struct val_loc **sav_locs (void);
+static void sub_ilc (struct il_c *ilc, struct code *cd, int indx);
+
+/*
+ * There are many parameters that are shared by multiple routines. There
+ * are copied into statics.
+ */
+static struct val_loc *rslt; /* result location */
+static struct code **scont_strt; /* label following operation code */
+static struct code **scont_fail; /* resumption label for in-line suspend */
+static struct c_fnc *cont; /* success continuation */
+static struct implement *impl; /* data base entry for operation */
+static int nsyms; /* number symbols in operation symbol table */
+static int n_vararg; /* size of variable part of arg list */
+static nodeptr intrnl_lftm; /* lifetime of internal variables */
+static struct val_loc **tended; /* array of tended locals */
+
+/*
+ * gen_inlin - generate in-line code for an operation.
+ */
+void gen_inlin(il, r, strt, fail, c, ip, ns, st, n, dcl_var, n_va)
+struct il_code *il;
+struct val_loc *r;
+struct code **strt;
+struct code **fail;
+struct c_fnc *c;
+struct implement *ip;
+int ns;
+struct op_symentry *st;
+nodeptr n;
+int dcl_var;
+int n_va;
+ {
+ struct code *cd;
+ struct val_loc *tnd;
+ int i;
+
+ /*
+ * Copy arguments in to globals.
+ */
+ rslt = r;
+ scont_strt = strt;
+ scont_fail = fail;
+ cont = c;
+ impl = ip;
+ nsyms = ns;
+ cur_symtab = st;
+ intrnl_lftm = n->intrnl_lftm;
+ cur_symtyps = n->symtyps;
+ n_vararg = n_va;
+
+ /*
+ * Generate code to initialize local tended descriptors and determine
+ * how to access the descriptors.
+ */
+ for (i = 0; i < impl->ntnds; ++i) {
+ if (cur_symtab[dcl_var].n_refs + cur_symtab[dcl_var].n_mods > 0) {
+ tnd = chk_alc(NULL, n->intrnl_lftm);
+ switch (impl->tnds[i].var_type) {
+ case TndDesc:
+ cur_symtab[dcl_var].loc = tnd;
+ break;
+ case TndStr:
+ cd = alc_ary(2);
+ cd->ElemTyp(0) = A_ValLoc;
+ cd->ValLoc(0) = tnd;
+ cd->ElemTyp(1) = A_Str;
+ cd->Str(1) = " = emptystr;";
+ cd_add(cd);
+ cur_symtab[dcl_var].loc = loc_cpy(tnd, M_CharPtr);
+ break;
+ case TndBlk:
+ cd = alc_ary(2);
+ cd->ElemTyp(0) = A_ValLoc;
+ cd->ValLoc(0) = tnd;
+ cd->ElemTyp(1) = A_Str;
+ cd->Str(1) = " = nullptr;";
+ cd_add(cd);
+ cur_symtab[dcl_var].loc = loc_cpy(tnd, M_BlkPtr);
+ cur_symtab[dcl_var].loc->blk_name = impl->tnds[i].blk_name;
+ break;
+ }
+ if (impl->tnds[i].init != NULL) {
+ cd = alc_ary(4);
+ cd->ElemTyp(0) = A_ValLoc;
+ cd->ValLoc(0) = cur_symtab[dcl_var].loc;
+ cd->ElemTyp(1) = A_Str;
+ cd->Str(1) = " = ";
+ sub_ilc(impl->tnds[i].init, cd, 2);
+ cd->ElemTyp(3) = A_Str;
+ cd->Str(3) = ";";
+ cd_add(cd);
+ }
+ }
+ ++dcl_var;
+ }
+
+ /*
+ * If there are local non-tended variables, generate code for the
+ * declarations, placing everything in braces.
+ */
+ if (impl->nvars > 0) {
+ cd = NewCode(0);
+ cd->cd_id = C_LBrack; /* { */
+ cd_add(cd);
+ for (i = 0; i < impl->nvars; ++i) {
+ if (cur_symtab[dcl_var].n_refs + cur_symtab[dcl_var].n_mods > 0) {
+ gen_ilc(impl->vars[i].dcl);
+ cur_symtab[dcl_var].loc = cvar_loc(impl->vars[i].name);
+ }
+ ++dcl_var;
+ }
+ }
+
+ gen_il(il); /* generate executable code */
+
+ if (impl->nvars > 0) {
+ cd = NewCode(0);
+ cd->cd_id = C_RBrack; /* } */
+ cd_add(cd);
+ }
+ }
+
+/*
+ * gen_il - generate code from a sub-tree of in-line code from the data
+ * base. Determine if execution can continue past this code.
+ *
+ */
+static int gen_il(il)
+struct il_code *il;
+ {
+ struct code *cd;
+ struct code *cd1;
+ struct il_code *il_cond;
+ struct il_code *il_then;
+ struct il_code *il_else;
+ struct il_code *il_t;
+ struct val_loc **locs;
+ struct val_loc **locs1;
+ struct val_loc *tnd;
+ int fall_thru;
+ int cond;
+ int ncases;
+ int indx;
+ int ntended;
+ int i;
+
+ if (il == NULL)
+ return 1;
+
+ switch (il->il_type) {
+ case IL_Const: /* should have been replaced by literal node */
+ return 1;
+
+ case IL_If1:
+ case IL_If2:
+ /*
+ * if-then or if-then-else statement.
+ */
+ il_then = il->u[1].fld;
+ if (il->il_type == IL_If2)
+ il_else = il->u[2].fld;
+ else
+ il_else = NULL;
+ il_cond = il->u[0].fld;
+ if (il->u[0].fld->il_type == IL_Bang) {
+ il_cond = il_cond->u[0].fld;
+ il_t = il_then;
+ il_then = il_else;
+ il_else = il_t;
+ }
+ locs = sav_locs();
+ cond = cond_anlz(il_cond, &cd1);
+ if (cond == (MaybeTrue | MaybeFalse))
+ fall_thru = gen_if(cd1, il_then, il_else, locs);
+ else {
+ if (cd1 != NULL) {
+ cd_add(cd1); /* condition contains needed conversions */
+ cd = alc_ary(1);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = ";";
+ cd_add(cd);
+ }
+ if (cond == MaybeTrue)
+ fall_thru = gen_il(il_then);
+ else if (cond == MaybeFalse) {
+ locs1 = sav_locs();
+ rstr_locs(locs);
+ locs = locs1;
+ fall_thru = gen_il(il_else);
+ }
+ mrg_locs(locs);
+ }
+ return fall_thru;
+
+ case IL_Tcase1:
+ /*
+ * type_case statement with no default clause.
+ */
+ return gen_tcase(il, 0);
+
+ case IL_Tcase2:
+ /*
+ * type_case statement with a default clause.
+ */
+ return gen_tcase(il, 1);
+
+ case IL_Lcase:
+ /*
+ * len_case statement. Determine which case matches the number
+ * of arguments.
+ */
+ ncases = il->u[0].n;
+ indx = 1;
+ for (i = 0; i < ncases; ++i) {
+ if (il->u[indx++].n == n_vararg) /* selection number */
+ return gen_il(il->u[indx].fld); /* action */
+ ++indx;
+ }
+ return gen_il(il->u[indx].fld); /* default */
+
+ case IL_Acase: {
+ /*
+ * arith_case statement.
+ */
+ struct il_code *var1;
+ struct il_code *var2;
+ struct val_loc *v_orig1;
+ struct val_loc *v_orig2;
+ struct code *cnv1;
+ struct code *cnv2;
+ int maybe_int;
+ int maybe_dbl;
+ int chk1;
+ int chk2;
+
+ var1 = il->u[0].fld;
+ var2 = il->u[1].fld;
+ v_orig1 = cur_symtab[var1->u[0].n].loc; /* remember for error msgs */
+ v_orig2 = cur_symtab[var2->u[0].n].loc; /* remember for error msgs */
+ arth_anlz(var1, var2, &maybe_int, &maybe_dbl, &chk1, &cnv1,
+ &chk2, &cnv2);
+
+ /*
+ * This statement is in-lined if there is only C integer
+ * arithmetic, only C double arithmetic, or only a run-time
+ * error.
+ */
+ arth_arg(var1, v_orig1, chk1, cnv1);
+ arth_arg(var2, v_orig2, chk2, cnv2);
+ if (maybe_int)
+ return gen_il(il->u[2].fld); /* C_integer action */
+ else if (maybe_dbl)
+ return gen_il(il->u[4].fld); /* C_double action */
+ else
+ return 0;
+ }
+
+ case IL_Err1:
+ /*
+ * runerr() with no offending value.
+ */
+ cd = alc_ary(3);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "err_msg(";
+ cd->ElemTyp(1) = A_Intgr;
+ cd->Intgr(1) = il->u[0].n;
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = ", NULL);";
+ cd_add(cd);
+ if (err_conv)
+ cd_add(sig_cd(on_failure, cur_fnc));
+ for (i = 0; i < nsyms; ++i)
+ cur_symtab[i].loc = NULL;
+ return 0;
+
+ case IL_Err2:
+ /*
+ * runerr() with an offending value. Note the reference to
+ * the offending value descriptor.
+ */
+ cd = alc_ary(5);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "err_msg(";
+ cd->ElemTyp(1) = A_Intgr;
+ cd->Intgr(1) = il->u[0].n;
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = ", &(";
+ il_var(il->u[1].fld, cd, 3);
+ cd->ElemTyp(4) = A_Str;
+ cd->Str(4) = "));";
+ cd_add(cd);
+ if (err_conv)
+ cd_add(sig_cd(on_failure, cur_fnc));
+ for (i = 0; i < nsyms; ++i)
+ cur_symtab[i].loc = NULL;
+ return 0;
+
+ case IL_Lst:
+ /*
+ * Two consecutive pieces of RTL code.
+ */
+ fall_thru = gen_il(il->u[0].fld);
+ if (fall_thru)
+ fall_thru = gen_il(il->u[1].fld);
+ return fall_thru;
+
+ case IL_Block:
+ /*
+ * inline {...} statement.
+ *
+ * Allocate and initialize any tended locals.
+ */
+ ntended = il->u[1].n;
+ if (ntended > 0)
+ tended = (struct val_loc **)alloc((unsigned int)
+ sizeof(struct val_loc *) * ntended);
+ for (i = 2; i - 2 < ntended; ++i) {
+ tnd = chk_alc(NULL, intrnl_lftm);
+ tended[i - 2] = tnd;
+ switch (il->u[i].n) {
+ case TndDesc:
+ break;
+ case TndStr:
+ cd = alc_ary(2);
+ cd->ElemTyp(0) = A_ValLoc;
+ cd->ValLoc(0) = tnd;
+ cd->ElemTyp(1) = A_Str;
+ cd->Str(1) = " = emptystr;";
+ cd_add(cd);
+ break;
+ case TndBlk:
+ cd = alc_ary(2);
+ cd->ElemTyp(0) = A_ValLoc;
+ cd->ValLoc(0) = tnd;
+ cd->ElemTyp(1) = A_Str;
+ cd->Str(1) = " = nullptr;";
+ cd_add(cd);
+ break;
+ }
+ }
+ gen_ilc(il->u[i].c_cd); /* body of block */
+ /*
+ * See if execution can fall through this code.
+ */
+ if (il->u[0].n)
+ return 1;
+ else {
+ for (i = 0; i < nsyms; ++i)
+ cur_symtab[i].loc = NULL;
+ return 0;
+ }
+
+ case IL_Call:
+ /*
+ * call to body function.
+ */
+ return body_fnc(il);
+
+ case IL_Abstr:
+ /*
+ * abstract type computation. Only used by type inference.
+ */
+ return 1;
+
+ default:
+ fprintf(stderr, "compiler error: unknown info in data base\n");
+ exit(1);
+ /* NOTREACHED */
+ }
+ }
+
+/*
+ * arth_arg - in-line code to check a conversion for an arith_case statement.
+ */
+static void arth_arg(var, v_orig, chk, cnv)
+struct il_code *var;
+struct val_loc *v_orig;
+int chk;
+struct code *cnv;
+ {
+ struct code *lbl;
+ struct code *cd;
+
+ if (chk) {
+ /*
+ * Must check the conversion.
+ */
+ lbl = oper_lbl("converted");
+ cd_add(lbl);
+ cur_fnc->cursor = lbl->prev; /* code goes before label */
+ if (cnv != NULL) {
+ cd = NewCode(2);
+ cd->cd_id = C_If;
+ cd->Cond = cnv;
+ cd->ThenStmt = mk_goto(lbl);
+ cd_add(cd);
+ }
+ cd = alc_ary(3);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "err_msg(102, &(";
+ cd->ElemTyp(1) = A_ValLoc;
+ cd->ValLoc(1) = v_orig; /* var location before conversion */
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = "));";
+ cd_add(cd);
+ if (err_conv)
+ cd_add(sig_cd(on_failure, cur_fnc));
+ cur_fnc->cursor = lbl;
+ }
+ else if (cnv != NULL) {
+ cd_add(cnv); /* conversion cannot fail */
+ cd = alc_ary(1);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = ";";
+ cd_add(cd);
+ }
+ }
+
+/*
+ * body_fnc - generate code to call a body function.
+ */
+static int body_fnc(il)
+struct il_code *il;
+ {
+ struct code *arg_lst;
+ struct code *cd;
+ struct c_fnc *cont1;
+ char *oper_nm;
+ int ret_val;
+ int ret_flag;
+ int need_rslt;
+ int num_sbuf;
+ int num_cbuf;
+ int expl_args;
+ int arglst_sz; /* size of arg list in number of code pieces */
+ int il_indx;
+ int cd_indx;
+ int proto_prt;
+ int i;
+
+ /*
+ * Determine if a function prototype has been printed yet for this
+ * body function.
+ */
+ proto_prt = il->u[0].n;
+ il->u[0].n = 1;
+
+ /*
+ * Construct the name of the body function.
+ */
+ oper_nm = (char *)alloc((unsigned int)(strlen(impl->name) + 6));
+ sprintf(oper_nm, "%c%c%c%c_%s", impl->oper_typ, impl->prefix[0],
+ impl->prefix[1], (char)il->u[1].n, impl->name);
+
+ /*
+ * Extract from the call the flags and other information describing
+ * the function, then use this information to deduce the arguments
+ * needed by the function.
+ */
+ ret_val = il->u[2].n;
+ ret_flag = il->u[3].n;
+ need_rslt = il->u[4].n;
+ num_sbuf = il->u[5].n;
+ num_cbuf = il->u[6].n;
+ expl_args = il->u[7].n;
+
+ /*
+ * determine how large the argument list is.
+ */
+ arglst_sz = 2 * expl_args - 1;
+ if (num_sbuf > 0)
+ arglst_sz += 3;
+ if (num_cbuf > 0)
+ arglst_sz += 2;
+ if (need_rslt)
+ arglst_sz += 3;
+ if (arglst_sz > 0)
+ arg_lst = alc_ary(arglst_sz);
+ else
+ arg_lst = alc_ary(0);
+
+ if (!proto_prt) {
+ /*
+ * Determine whether the body function returns a C integer, double,
+ * no value, or a signal.
+ */
+ switch (ret_val) {
+ case RetInt:
+ fprintf(inclfile, "C_integer %s (", oper_nm);
+ break;
+ case RetDbl:
+ fprintf(inclfile, "double %s (", oper_nm);
+ break;
+ case RetNoVal:
+ fprintf(inclfile, "void %s (", oper_nm);
+ break;
+ case RetSig:
+ fprintf(inclfile, "int %s (", oper_nm);
+ break;
+ }
+ }
+
+ /*
+ * Produce prototype and code for the explicit arguments in the
+ * function call. Note that the call entry contains C code for both.
+ */
+ il_indx = 8;
+ cd_indx = 0;
+ while (expl_args--) {
+ if (cd_indx > 0) {
+ /*
+ * Not first entry, precede by ','.
+ */
+ arg_lst->ElemTyp(cd_indx) = A_Str; /* , */
+ arg_lst->Str(cd_indx) = ", ";
+ if (!proto_prt)
+ fprintf(inclfile, ", ");
+ ++cd_indx;
+ }
+ if (!proto_prt)
+ fprintf(inclfile, "%s", il->u[il_indx].c_cd->s); /* parameter dcl */
+ ++il_indx;
+ sub_ilc(il->u[il_indx++].c_cd, arg_lst, cd_indx++);
+ }
+
+ /*
+ * If string buffers are needed, allocate them and pass pointer to
+ * function.
+ */
+ if (num_sbuf > 0) {
+ if (cd_indx > 0) {
+ /*
+ * Not first entry, precede by ','.
+ */
+ arg_lst->ElemTyp(cd_indx) = A_Str; /* , */
+ arg_lst->Str(cd_indx) = ", ";
+ if (!proto_prt)
+ fprintf(inclfile, ", ");
+ ++cd_indx;
+ }
+ arg_lst->ElemTyp(cd_indx) = A_Str;
+ arg_lst->Str(cd_indx) = "(char (*)[MaxCvtLen])";
+ ++cd_indx;
+ arg_lst->ElemTyp(cd_indx) = A_SBuf;
+ arg_lst->Intgr(cd_indx) = alc_sbufs(num_sbuf, intrnl_lftm);
+ if (!proto_prt)
+ fprintf(inclfile, "char (*r_sbuf)[MaxCvtLen]");
+ ++cd_indx;
+ }
+
+ /*
+ * If cset buffers are needed, allocate them and pass pointer to
+ * function.
+ */
+ if (num_cbuf > 0) {
+ if (cd_indx > 0) {
+ /*
+ * Not first entry, precede by ','.
+ */
+ arg_lst->ElemTyp(cd_indx) = A_Str; /* , */
+ arg_lst->Str(cd_indx) = ", ";
+ if (!proto_prt)
+ fprintf(inclfile, ", ");
+ ++cd_indx;
+ }
+ arg_lst->ElemTyp(cd_indx) = A_CBuf;
+ arg_lst->Intgr(cd_indx) = alc_cbufs(num_cbuf, intrnl_lftm);
+ if (!proto_prt)
+ fprintf(inclfile, "struct b_cset *r_cbuf");
+ ++cd_indx;
+ }
+
+ /*
+ * See if the function needs a pointer to the result location
+ * of the operation.
+ */
+ if (need_rslt) {
+ if (cd_indx > 0) {
+ /*
+ * Not first entry, precede by ','.
+ */
+ arg_lst->ElemTyp(cd_indx) = A_Str; /* , */
+ arg_lst->Str(cd_indx) = ", ";
+ if (!proto_prt)
+ fprintf(inclfile, ", ");
+ ++cd_indx;
+ }
+ arg_lst->ElemTyp(cd_indx) = A_Str; /* location of result */
+ arg_lst->Str(cd_indx) = "&";
+ ++cd_indx;
+ arg_lst->ElemTyp(cd_indx) = A_ValLoc;
+ arg_lst->ValLoc(cd_indx) = rslt;
+ if (!proto_prt)
+ fprintf(inclfile, "dptr rslt");
+ ++cd_indx;
+ }
+
+ if (!proto_prt) {
+ /*
+ * The last possible argument is the success continuation.
+ * If there are no arguments, indicate this in the prototype.
+ */
+ if (ret_flag & DoesSusp) {
+ if (cd_indx > 0)
+ fprintf(inclfile, ", ");
+ fprintf(inclfile, "continuation succ_cont");
+ }
+ else if (cd_indx == 0)
+ fprintf(inclfile, "void");
+ fprintf(inclfile, ");\n");
+ }
+
+ /*
+ * Does this call need the success continuation for the operation.
+ */
+ if (ret_flag & DoesSusp)
+ cont1 = cont;
+ else
+ cont1 = NULL;
+
+ switch (ret_val) {
+ case RetInt:
+ /*
+ * The body function returns a C integer.
+ */
+ cd = alc_ary(6);
+ cd->ElemTyp(0) = A_ValLoc;
+ cd->ValLoc(0) = rslt;
+ cd->ElemTyp(1) = A_Str;
+ cd->Str(1) = ".vword.integr = ";
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = oper_nm;
+ cd->ElemTyp(3) = A_Str;
+ cd->Str(3) = "(";
+ cd->ElemTyp(4) = A_Ary;
+ cd->Array(4) = arg_lst;
+ cd->ElemTyp(5) = A_Str;
+ cd->Str(5) = ");";
+ cd_add(cd);
+ dwrd_asgn(rslt, "Integer");
+ cd_add(mk_goto(*scont_strt));
+ break;
+ case RetDbl:
+ /*
+ * The body function returns a C double.
+ */
+ cd = alc_ary(6);
+ cd->ElemTyp(0) = A_ValLoc;
+ cd->ValLoc(0) = rslt;
+ cd->ElemTyp(1) = A_Str;
+ cd->Str(1) = ".vword.bptr = (union block *)alcreal(";
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = oper_nm;
+ cd->ElemTyp(3) = A_Str;
+ cd->Str(3) = "(";
+ cd->ElemTyp(4) = A_Ary;
+ cd->Array(4) = arg_lst;
+ cd->ElemTyp(5) = A_Str;
+ cd->Str(5) = "));";
+ cd_add(cd);
+ dwrd_asgn(rslt, "Real");
+ chkforblk(); /* make sure the block allocation succeeded */
+ cd_add(mk_goto(*scont_strt));
+ break;
+ case RetNoVal:
+ /*
+ * The body function does not directly return a value.
+ */
+ cd = alc_ary(4);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = oper_nm;
+ cd->ElemTyp(1) = A_Str;
+ cd->Str(1) = "(";
+ cd->ElemTyp(2) = A_Ary;
+ cd->Array(2) = arg_lst;
+ cd->ElemTyp(3) = A_Str;
+ cd->Str(3) = ");";
+ cd_add(cd);
+ if (ret_flag & DoesFail | (err_conv && (ret_flag & DoesEFail)))
+ cd_add(sig_cd(on_failure, cur_fnc));
+ else if (ret_flag & DoesRet)
+ cd_add(mk_goto(*scont_strt));
+ break;
+ case RetSig:
+ /*
+ * The body function returns a signal.
+ */
+ callo_add(oper_nm, ret_flag, cont1, 0, arg_lst, mk_goto(*scont_strt));
+ break;
+ }
+ /*
+ * See if execution can fall through this call.
+ */
+ if (ret_flag & DoesFThru)
+ return 1;
+ else {
+ for (i = 0; i < nsyms; ++i)
+ cur_symtab[i].loc = NULL;
+ return 0;
+ }
+ }
+
+
+/*
+ * il_var - generate code for a possibly subscripted variable into
+ * an element of a code array.
+ */
+static void il_var(il, cd, indx)
+struct il_code *il;
+struct code *cd;
+int indx;
+ {
+ struct code *cd1;
+
+ if (il->il_type == IL_Subscr) {
+ /*
+ * Subscripted variable.
+ */
+ cd1 = cd;
+ cd = alc_ary(4);
+ cd1->ElemTyp(indx) = A_Ary;
+ cd1->Array(indx) = cd;
+ indx = 0;
+ cd->ElemTyp(1) = A_Str;
+ cd->Str(1) = "[";
+ cd->ElemTyp(2) = A_Intgr;
+ cd->Intgr(2) = il->u[1].n;
+ cd->ElemTyp(3) = A_Str;
+ cd->Str(3) = "]";
+ }
+
+ /*
+ * See if this is the result location of the operation or an ordinary
+ * variable.
+ */
+ cd->ElemTyp(indx) = A_ValLoc;
+ if (il->u[0].n == RsltIndx)
+ cd->ValLoc(indx) = rslt;
+ else
+ cd->ValLoc(indx) = cur_symtab[il->u[0].n].loc;
+ }
+
+/*
+ * part_asgn - generate code for an assignment to (part of) a descriptor.
+ */
+static void part_asgn(vloc, asgn, value)
+struct val_loc *vloc;
+char *asgn;
+struct il_c *value;
+ {
+ struct code *cd;
+
+ cd = alc_ary(4);
+ cd->ElemTyp(0) = A_ValLoc;
+ cd->ValLoc(0) = vloc;
+ cd->ElemTyp(1) = A_Str;
+ cd->Str(1) = asgn;
+ sub_ilc(value, cd, 2); /* value */
+ cd->ElemTyp(3) = A_Str;
+ cd->Str(3) = ";";
+ cd_add(cd);
+ }
+
+/*
+ * dwrd_asgn - generate code to assign a type code to the dword of a descriptor.
+ */
+static void dwrd_asgn(vloc, typ)
+struct val_loc *vloc;
+char *typ;
+ {
+ struct code *cd;
+
+ cd = alc_ary(4);
+ cd->ElemTyp(0) = A_ValLoc;
+ cd->ValLoc(0) = vloc;
+ cd->ElemTyp(1) = A_Str;
+ cd->Str(1) = ".dword = D_";
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = typ;
+ cd->ElemTyp(3) = A_Str;
+ cd->Str(3) = ";";
+ cd_add(cd);
+ }
+
+/*
+ * sub_ilc - generate code from a sequence of C code and place it
+ * in a slot in a code array.
+ */
+static void sub_ilc(ilc, cd, indx)
+struct il_c *ilc;
+struct code *cd;
+int indx;
+ {
+ struct il_c *ilc1;
+ struct code *cd1;
+ int n;
+
+ /*
+ * Count the number of pieces of C code to process.
+ */
+ n = 0;
+ for (ilc1 = ilc; ilc1 != NULL; ilc1 = ilc1->next)
+ ++n;
+
+ /*
+ * If there is only one piece of code, place it directly in the
+ * slot of the array. Otherwise allocate a sub-array and place it
+ * in the slot.
+ */
+ if (n > 1) {
+ cd1 = cd;
+ cd = alc_ary(n);
+ cd1->ElemTyp(indx) = A_Ary;
+ cd1->Array(indx) = cd;
+ indx = 0;
+ }
+
+ while (ilc != NULL) {
+ switch (ilc->il_c_type) {
+ case ILC_Ref:
+ case ILC_Mod:
+ /*
+ * Reference to variable in symbol table.
+ */
+ cd->ElemTyp(indx) = A_ValLoc;
+ if (ilc->n == RsltIndx)
+ cd->ValLoc(indx) = rslt;
+ else {
+ if (ilc->s == NULL)
+ cd->ValLoc(indx) = cur_symtab[ilc->n].loc;
+ else {
+ /*
+ * Access the entire descriptor.
+ */
+ cd->ValLoc(indx) = loc_cpy(cur_symtab[ilc->n].loc, M_None);
+ }
+ }
+ break;
+
+ case ILC_Tend:
+ /*
+ * Reference to a tended variable.
+ */
+ cd->ElemTyp(indx) = A_ValLoc;
+ cd->ValLoc(indx) = tended[ilc->n];
+ break;
+
+ case ILC_Str:
+ /*
+ * String representing C code.
+ */
+ cd->ElemTyp(indx) = A_Str;
+ cd->Str(indx) = ilc->s;
+ break;
+
+ case ILC_SBuf:
+ /*
+ * String buffer for a conversion.
+ */
+ cd->ElemTyp(indx) = A_SBuf;
+ cd->Intgr(indx) = alc_sbufs(1, intrnl_lftm);
+ break;
+
+ case ILC_CBuf:
+ /*
+ * Cset buffer for a conversion.
+ */
+ cd->ElemTyp(indx) = A_CBuf;
+ cd->Intgr(indx) = alc_cbufs(1, intrnl_lftm);
+ break;
+
+
+ default:
+ fprintf(stderr, "compiler error: unknown info in data base\n");
+ exit(1);
+ }
+ ilc = ilc->next;
+ ++indx;
+ }
+
+ }
+
+/*
+ * gen_ilret - generate code to set the result value from a suspend or
+ * return.
+ */
+static void gen_ilret(ilc)
+struct il_c *ilc;
+ {
+ struct il_c *ilc0;
+ struct code *cd;
+ char *cap_id;
+ int typcd;
+
+ if (rslt == &ignore)
+ return; /* Don't bother computing the result; it's never used */
+
+ ilc0 = ilc->code[0];
+ typcd = ilc->n;
+
+ if (typcd < 0) {
+ /*
+ * RTL returns that do not look like function calls to standard Icon
+ * type name.
+ */
+ switch (typcd) {
+ case TypCInt:
+ /*
+ * return/suspend C_integer <expr>;
+ */
+ part_asgn(rslt, ".vword.integr = ", ilc0);
+ dwrd_asgn(rslt, "Integer");
+ break;
+ case TypCDbl:
+ /*
+ * return/suspend C_double <expr>;
+ */
+ cd = alc_ary(4);
+ cd->ElemTyp(0) = A_ValLoc;
+ cd->ValLoc(0) = rslt;
+ cd->ElemTyp(1) = A_Str;
+ cd->Str(1) = ".vword.bptr = (union block *)alcreal(";
+ sub_ilc(ilc0, cd, 2); /* value */
+ cd->ElemTyp(3) = A_Str;
+ cd->Str(3) = ");";
+ cd_add(cd);
+ dwrd_asgn(rslt, "Real");
+ chkforblk(); /* make sure the block allocation succeeded */
+ break;
+ case TypCStr:
+ /*
+ * return/suspend C_string <expr>;
+ */
+ cd = alc_ary(5);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "AsgnCStr(";
+ cd->ElemTyp(1) = A_ValLoc;
+ cd->ValLoc(1) = rslt;
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = ", ";
+ sub_ilc(ilc0, cd, 3); /* <expr> */
+ cd->ElemTyp(4) = A_Str;
+ cd->Str(4) = ");";
+ cd_add(cd);
+ break;
+ case RetDesc:
+ /*
+ * return/suspend <expr>;
+ */
+ part_asgn(rslt, " = ", ilc0);
+ break;
+ case RetNVar:
+ /*
+ * return/suspend named_var(<desc-pntr>);
+ */
+ part_asgn(rslt, ".vword.descptr = ", ilc0);
+ dwrd_asgn(rslt, "Var");
+ break;
+ case RetSVar:
+ /*
+ * return/suspend struct_var(<desc-pntr>, <block_pntr>);
+ */
+ part_asgn(rslt, ".vword.descptr = (dptr)", ilc->code[1]);
+ cd = alc_ary(6);
+ cd->ElemTyp(0) = A_ValLoc;
+ cd->ValLoc(0) = rslt;
+ cd->ElemTyp(1) = A_Str;
+ cd->Str(1) = ".dword = D_Var + ((word *)";
+ sub_ilc(ilc0, cd, 2); /* value */
+ cd->ElemTyp(3) = A_Str;
+ cd->Str(3) = " - (word *)";
+ cd->ElemTyp(4) = A_ValLoc;
+ cd->ValLoc(4) = rslt;
+ cd->ElemTyp(5) = A_Str;
+ cd->Str(5) = ".vword.descptr);";
+ cd_add(cd);
+ break;
+ case RetNone:
+ /*
+ * return/suspend result;
+ *
+ * Result already set, do nothing.
+ */
+ break;
+ default:
+ fprintf(stderr,
+ "compiler error: unknown RLT return in data base\n");
+ exit(1);
+ /* NOTREACHED */
+ }
+ }
+ else {
+ /*
+ * RTL returns that look like function calls to standard Icon type
+ * names.
+ */
+ cap_id = icontypes[typcd].cap_id;
+ switch (icontypes[typcd].rtl_ret) {
+ case TRetBlkP:
+ /*
+ * return/suspend <type>(<block-pntr>);
+ */
+ part_asgn(rslt, ".vword.bptr = (union block *)", ilc0);
+ dwrd_asgn(rslt, cap_id);
+ break;
+ case TRetDescP:
+ /*
+ * return/suspend <type>(<descriptor-pntr>);
+ */
+ part_asgn(rslt, ".vword.descptr = (dptr)", ilc0);
+ dwrd_asgn(rslt, cap_id);
+ break;
+ case TRetCharP:
+ /*
+ * return/suspend <type>(<char-pntr>);
+ */
+ part_asgn(rslt, ".vword.sptr = (char *)", ilc0);
+ dwrd_asgn(rslt, cap_id);
+ break;
+ case TRetCInt:
+ /*
+ * return/suspend <type>(<integer>);
+ */
+ part_asgn(rslt, ".vword.integr = (word)", ilc0);
+ dwrd_asgn(rslt, cap_id);
+ break;
+ case TRetSpcl:
+ /*
+ * RTL returns that look like function calls to standard type
+ * names but take more than one argument.
+ */
+ if (typcd == str_typ) {
+ /*
+ * return/suspend string(<len>, <char-pntr>);
+ */
+ part_asgn(rslt, ".vword.sptr = ", ilc->code[1]);
+ part_asgn(rslt, ".dword = ", ilc0);
+ }
+ else if (typcd == stv_typ) {
+ /*
+ * return/suspend substr(<desc-pntr>, <start>, <len>);
+ */
+ cd = alc_ary(9);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "SubStr(&";
+ cd->ElemTyp(1) = A_ValLoc;
+ cd->ValLoc(1) = rslt;
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = ", ";
+ sub_ilc(ilc0, cd, 3);
+ cd->ElemTyp(4) = A_Str;
+ cd->Str(4) = ", ";
+ sub_ilc(ilc->code[2], cd, 5);
+ cd->ElemTyp(6) = A_Str;
+ cd->Str(6) = ", ";
+ sub_ilc(ilc->code[1], cd, 7);
+ cd->ElemTyp(8) = A_Str;
+ cd->Str(8) = ");";
+ cd_add(cd);
+ chkforblk(); /* make sure the block allocation succeeded */
+ }
+ else {
+ fprintf(stderr,
+ "compiler error: unknown RLT return in data base\n");
+ exit(1);
+ /* NOTREACHED */
+ }
+ break;
+ default:
+ fprintf(stderr,
+ "compiler error: unknown RLT return in data base\n");
+ exit(1);
+ /* NOTREACHED */
+ }
+ }
+ }
+
+/*
+ * chkforblk - generate code to make sure the allocation of a block
+ * for the result descriptor was successful.
+ */
+static void chkforblk()
+ {
+ struct code *cd;
+ struct code *cd1;
+ struct code *lbl;
+
+ lbl = alc_lbl("got allocation", 0);
+ cd_add(lbl);
+ cur_fnc->cursor = lbl->prev; /* code goes before label */
+ cd = NewCode(2);
+ cd->cd_id = C_If;
+ cd1 = alc_ary(3);
+ cd1->ElemTyp(0) = A_Str;
+ cd1->Str(0) = "(";
+ cd1->ElemTyp(1) = A_ValLoc;
+ cd1->ValLoc(1) = rslt;
+ cd1->ElemTyp(2) = A_Str;
+ cd1->Str(2) = ").vword.bptr != NULL";
+ cd->Cond = cd1;
+ cd->ThenStmt = mk_goto(lbl);
+ cd_add(cd);
+ cd = alc_ary(1);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "err_msg(307, NULL);";
+ cd_add(cd);
+ if (err_conv)
+ cd_add(sig_cd(on_failure, cur_fnc));
+ cur_fnc->cursor = lbl;
+ }
+
+/*
+ * gen_ilc - generate code for an sequence of in-line C code.
+ */
+static void gen_ilc(ilc)
+struct il_c *ilc;
+ {
+ struct il_c *ilc1;
+ struct code *cd;
+ struct code *cd1;
+ struct code *lbl1;
+ struct code *fail_sav;
+ struct code **lbls;
+ int max_lbl;
+ int i;
+
+ /*
+ * Determine how many labels there are in the code and allocate an
+ * array to map from label numbers to labels in the code.
+ */
+ max_lbl = -1;
+ for (ilc1 = ilc; ilc1 != NULL; ilc1 = ilc1->next) {
+ switch(ilc1->il_c_type) {
+ case ILC_CGto:
+ case ILC_Goto:
+ case ILC_Lbl:
+ if (ilc1->n > max_lbl)
+ max_lbl = ilc1->n;
+ }
+ }
+ ++max_lbl; /* adjust for 0 indexing */
+ if (max_lbl > 0) {
+ lbls = (struct code **)alloc((unsigned int) sizeof(struct code *) *
+ max_lbl);
+ for (i = 0; i < max_lbl; ++i)
+ lbls[i] = NULL;
+ }
+
+ while (ilc != NULL) {
+ switch(ilc->il_c_type) {
+ case ILC_Ref:
+ case ILC_Mod:
+ case ILC_Tend:
+ case ILC_SBuf:
+ case ILC_CBuf:
+ case ILC_Str:
+ /*
+ * The beginning of a sequence of code fragments that can be
+ * place on one line.
+ */
+ ilc = line_ilc(ilc);
+ break;
+
+ case ILC_Fail:
+ /*
+ * fail - perform failure action.
+ */
+ cd_add(sig_cd(on_failure, cur_fnc));
+ break;
+
+ case ILC_EFail:
+ /*
+ * errorfail - same as fail if error conversion is supported.
+ */
+ if (err_conv)
+ cd_add(sig_cd(on_failure, cur_fnc));
+ break;
+
+ case ILC_Ret:
+ /*
+ * return - set result location and jump out of operation.
+ */
+ gen_ilret(ilc);
+ cd_add(mk_goto(*scont_strt));
+ break;
+
+ case ILC_Susp:
+ /*
+ * suspend - set result location. If there is a success
+ * continuation, call it. Otherwise the "continuation"
+ * will be generated in-line, so set up a resumption label.
+ */
+ gen_ilret(ilc);
+ if (cont == NULL)
+ *scont_strt = cur_fnc->cursor;
+ lbl1 = oper_lbl("end suspend");
+ cd_add(lbl1);
+ if (cont == NULL)
+ *scont_fail = lbl1;
+ else {
+ cur_fnc->cursor = lbl1->prev;
+ fail_sav = on_failure;
+ on_failure = lbl1;
+ callc_add(cont);
+ on_failure = fail_sav;
+ cur_fnc->cursor = lbl1;
+ }
+ break;
+
+ case ILC_LBrc:
+ /*
+ * non-deletable '{'
+ */
+ cd = NewCode(0);
+ cd->cd_id = C_LBrack;
+ cd_add(cd);
+ break;
+
+ case ILC_RBrc:
+ /*
+ * non-deletable '}'
+ */
+ cd = NewCode(0);
+ cd->cd_id = C_RBrack;
+ cd_add(cd);
+ break;
+
+ case ILC_CGto:
+ /*
+ * Conditional goto.
+ */
+ i = ilc->n;
+ if (lbls[i] == NULL)
+ lbls[i] = oper_lbl("within");
+ cd = NewCode(2);
+ cd->cd_id = C_If;
+ cd1 = alc_ary(1);
+ sub_ilc(ilc->code[0], cd1, 0);
+ cd->Cond = cd1;
+ cd->ThenStmt = mk_goto(lbls[i]);
+ cd_add(cd);
+ break;
+
+ case ILC_Goto:
+ /*
+ * Goto.
+ */
+ i = ilc->n;
+ if (lbls[i] == NULL)
+ lbls[i] = oper_lbl("within");
+ cd_add(mk_goto(lbls[i]));
+ break;
+
+ case ILC_Lbl:
+ /*
+ * Label.
+ */
+ i = ilc->n;
+ if (lbls[i] == NULL)
+ lbls[i] = oper_lbl("within");
+ cd_add(lbls[i]);
+ break;
+
+ default:
+ fprintf(stderr, "compiler error: unknown info in data base\n");
+ exit(1);
+ }
+ ilc = ilc->next;
+ }
+
+ if (max_lbl > 0)
+ free((char *)lbls);
+ }
+
+/*
+ * line_ilc - gather a line of in-line code.
+ */
+static struct il_c *line_ilc(ilc)
+struct il_c *ilc;
+ {
+ struct il_c *ilc1;
+ struct il_c *last;
+ struct code *cd;
+ int n;
+ int i;
+
+ /*
+ * Count the number of pieces in the line. Determine the last
+ * piece in the sequence; this is returned to the caller.
+ */
+ n = 0;
+ ilc1 = ilc;
+ while (ilc1 != NULL) {
+ switch(ilc1->il_c_type) {
+ case ILC_Ref:
+ case ILC_Mod:
+ case ILC_Tend:
+ case ILC_SBuf:
+ case ILC_CBuf:
+ case ILC_Str:
+ ++n;
+ last = ilc1;
+ ilc1 = ilc1->next;
+ break;
+ default:
+ ilc1 = NULL;
+ }
+ }
+
+ /*
+ * Construct the line.
+ */
+ cd = alc_ary(n);
+ for (i = 0; i < n; ++i) {
+ switch(ilc->il_c_type) {
+ case ILC_Ref:
+ case ILC_Mod:
+ /*
+ * Reference to variable in symbol table.
+ */
+ cd->ElemTyp(i) = A_ValLoc;
+ if (ilc->n == RsltIndx)
+ cd->ValLoc(i) = rslt;
+ else
+ cd->ValLoc(i) = cur_symtab[ilc->n].loc;
+ break;
+
+ case ILC_Tend:
+ /*
+ * Reference to a tended variable.
+ */
+ cd->ElemTyp(i) = A_ValLoc;
+ cd->ValLoc(i) = tended[ilc->n];
+ break;
+
+ case ILC_SBuf:
+ /*
+ * String buffer for a conversion.
+ */
+ cd->ElemTyp(i) = A_SBuf;
+ cd->Intgr(i) = alc_sbufs(1, intrnl_lftm);
+ break;
+
+ case ILC_CBuf:
+ /*
+ * Cset buffer for a conversion.
+ */
+ cd->ElemTyp(i) = A_CBuf;
+ cd->Intgr(i) = alc_cbufs(1, intrnl_lftm);
+ break;
+
+ case ILC_Str:
+ /*
+ * String representing C code.
+ */
+ cd->ElemTyp(i) = A_Str;
+ cd->Str(i) = ilc->s;
+ break;
+
+ default:
+ ilc = NULL;
+ }
+ ilc = ilc->next;
+ }
+
+ cd_add(cd);
+ return last;
+ }
+
+/*
+ * generate code to perform simple type checking.
+ */
+struct code *typ_chk(var, typcd)
+struct il_code *var;
+int typcd;
+ {
+ struct code *cd;
+
+ if (typcd == int_typ && largeints) {
+ /*
+ * Handle large integer support specially.
+ */
+ cd = alc_ary(5);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "((";
+ il_var(var, cd, 1); /* value */
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = ").dword == D_Integer || (";
+ il_var(var, cd, 3); /* value */
+ cd->ElemTyp(4) = A_Str;
+ cd->Str(4) = ").dword == D_Lrgint)";
+ return cd;
+ }
+ else if (typcd < 0) {
+ /*
+ * Not a standard Icon type name.
+ */
+ cd = alc_ary(3);
+ cd->ElemTyp(0) = A_Str;
+ switch (typcd) {
+ case TypVar:
+ cd->Str(0) = "(((";
+ il_var(var, cd, 1); /* value */
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = ").dword & D_Var) == D_Var)";
+ break;
+ case TypCInt:
+ cd->Str(0) = "((";
+ il_var(var, cd, 1); /* value */
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = ").dword == D_Integer)";
+ break;
+ }
+ }
+ else if (typcd == str_typ) {
+ cd = alc_ary(3);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "(!((";
+ il_var(var, cd, 1); /* value */
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = ").dword & F_Nqual))";
+ }
+ else {
+ cd = alc_ary(5);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "((";
+ il_var(var, cd, 1); /* value */
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = ").dword == D_";
+ cd->ElemTyp(3) = A_Str;
+ cd->Str(3) = icontypes[typcd].cap_id; /* type name */
+ cd->ElemTyp(4) = A_Str;
+ cd->Str(4) = ")";
+ }
+
+ return cd;
+ }
+
+/*
+ * oper_lbl - generate a label with an associated comment that includes
+ * the operation name.
+ */
+static struct code *oper_lbl(s)
+char *s;
+ {
+ char *sbuf;
+
+ sbuf = (char *)alloc((unsigned int)(strlen(s) + strlen(impl->name) + 3));
+ sprintf(sbuf, "%s: %s", s, impl->name);
+ return alc_lbl(sbuf, 0);
+ }
+
+/*
+ * sav_locs - save the current interpretation of symbols that may
+ * be affected by conversions.
+ */
+static struct val_loc **sav_locs()
+ {
+ struct val_loc **locs;
+ int i;
+
+ if (nsyms == 0)
+ return NULL;
+
+ locs = (struct val_loc **)alloc((unsigned int)(nsyms *
+ sizeof(struct val_loc *)));
+ for (i = 0; i < nsyms; ++i)
+ locs[i] = cur_symtab[i].loc;
+ return locs;
+ }
+
+/*
+ * rstr_locs - restore the interpretation of symbols that may
+ * have been affected by conversions.
+ */
+static void rstr_locs(locs)
+struct val_loc **locs;
+ {
+ int i;
+
+ for (i = 0; i < nsyms; ++i)
+ cur_symtab[i].loc = locs[i];
+ free((char *)locs);
+ }
+
+/*
+ * mrg_locs - merge the interpretations of symbols along two execution
+ * paths. Any ambiguity is caught by rtt, so differences only occur
+ * if one path involves program termination so that the symbols
+ * no longer have an interpretation along that path.
+ */
+static void mrg_locs(locs)
+struct val_loc **locs;
+ {
+ int i;
+
+ for (i = 0; i < nsyms; ++i)
+ if (cur_symtab[i].loc == NULL)
+ cur_symtab[i].loc = locs[i];
+ free((char *)locs);
+ }
+
+/*
+ * il_cnv - generate code for an in-line conversion.
+ */
+struct code *il_cnv(typcd, src, dflt, dest)
+int typcd;
+struct il_code *src;
+struct il_c *dflt;
+struct il_c *dest;
+ {
+ struct code *cd;
+ struct code *cd1;
+ int dflt_to_ptr;
+ int loc;
+ int is_cstr;
+ int sym_indx;
+ int n;
+ int i;
+
+ sym_indx = src->u[0].n;
+
+ /*
+ * Determine whether the address must be taken of a default value and
+ * whether the interpretation of the symbol in an in-place conversion
+ * changes.
+ */
+ dflt_to_ptr = 0;
+ loc = PrmTend;
+ is_cstr = 0;
+ switch (typcd) {
+ case TypCInt:
+ case TypECInt:
+ loc = PrmInt;
+ break;
+ case TypCDbl:
+ loc = PrmDbl;
+ break;
+ case TypCStr:
+ is_cstr = 1;
+ break;
+ case TypEInt:
+ break;
+ case TypTStr:
+ case TypTCset:
+ dflt_to_ptr = 1;
+ break;
+ default:
+ /*
+ * Cset, real, integer, or string
+ */
+ if (typcd == cset_typ || typcd == str_typ)
+ dflt_to_ptr = 1;
+ break;
+ }
+
+ if (typcd == TypCDbl && !(eval_is(real_typ, sym_indx) & MaybeFalse)) {
+ /*
+ * Conversion from Icon real to C double. Just copy the C value
+ * from the block.
+ */
+ cd = alc_ary(5);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "(GetReal(&(";
+ il_var(src, cd, 1);
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = "), ";
+ cnv_dest(loc, is_cstr, src, sym_indx, dest, cd, 3);
+ cd->ElemTyp(4) = A_Str;
+ cd->Str(4) = "), 1)";
+ }
+ else if (typcd == TypCDbl && !largeints &&
+ !(eval_is(int_typ, sym_indx) & MaybeFalse)) {
+ /*
+ * Conversion from Icon integer (not large integer) to C double.
+ * Do as a C conversion by an assigment.
+ */
+ cd = alc_ary(5);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "(";
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = " = IntVal( ";
+ cd->ElemTyp(4) = A_Str;
+ cd->Str(4) = "), 1)";
+ /*
+ * Note that cnv_dest() must be called after the source is output
+ * in case it changes the location of the parameter.
+ */
+ il_var(src, cd, 3);
+ cnv_dest(loc, is_cstr, src, sym_indx, dest, cd, 1);
+ }
+ else {
+ /*
+ * Compute the number of code fragments required to construct the
+ * call to the conversion routine.
+ */
+ n = 7;
+ if (dflt != NULL)
+ n += 2;
+
+ cd = alc_ary(n);
+
+ /*
+ * The names of simple conversions are distinguished from defaulting
+ * conversions by a prefix of "cnv_" or "def_".
+ */
+ cd->ElemTyp(0) = A_Str;
+ if (dflt == NULL)
+ cd->Str(0) = "cnv_";
+ else
+ cd->Str(0) = "def_";
+
+ /*
+ * Determine the name of the conversion routine.
+ */
+ cd->ElemTyp(1) = A_Str; /* may be overridden */
+ switch (typcd) {
+ case TypCInt:
+ cd->Str(1) = "c_int(&(";
+ break;
+ case TypCDbl:
+ cd->Str(1) = "c_dbl(&(";
+ break;
+ case TypCStr:
+ cd->Str(1) = "c_str(&(";
+ break;
+ case TypEInt:
+ cd->Str(1) = "eint(&(";
+ break;
+ case TypECInt:
+ cd->Str(1) = "ec_int(&(";
+ break;
+ case TypTStr:
+ /*
+ * Allocate a string buffer.
+ */
+ cd1 = alc_ary(3);
+ cd1->ElemTyp(0) = A_Str;
+ cd1->Str(0) = "tstr(";
+ cd1->ElemTyp(1) = A_SBuf;
+ cd1->Intgr(1) = alc_sbufs(1, intrnl_lftm);
+ cd1->ElemTyp(2) = A_Str;
+ cd1->Str(2) = ", (&";
+ cd->ElemTyp(1) = A_Ary;
+ cd->Array(1) = cd1;
+ break;
+ case TypTCset:
+ /*
+ * Allocate a cset buffer.
+ */
+ cd1 = alc_ary(3);
+ cd1->ElemTyp(0) = A_Str;
+ cd1->Str(0) = "tcset(";
+ cd1->ElemTyp(1) = A_CBuf;
+ cd1->Intgr(1) = alc_cbufs(1, intrnl_lftm);
+ cd1->ElemTyp(2) = A_Str;
+ cd1->Str(2) = ", &(";
+ cd->ElemTyp(1) = A_Ary;
+ cd->Array(1) = cd1;
+ break;
+ default:
+ /*
+ * Cset, real, integer, or string
+ */
+ if (typcd == cset_typ)
+ cd->Str(1) = "cset(&(";
+ else if (typcd == real_typ)
+ cd->Str(1) = "real(&(";
+ else if (typcd == int_typ)
+ cd->Str(1) = "int(&(";
+ else if (typcd == str_typ)
+ cd->Str(1) = "str(&(";
+ break;
+ }
+
+ il_var(src, cd, 2);
+
+ cd->ElemTyp(3) = A_Str;
+ if (dflt != NULL && dflt_to_ptr)
+ cd->Str(3) = "), &(";
+ else
+ cd->Str(3) = "), ";
+
+
+ /*
+ * Determine if this conversion has a default value.
+ */
+ i = 4;
+ if (dflt != NULL) {
+ sub_ilc(dflt, cd, i);
+ ++i;
+ cd->ElemTyp(i) = A_Str;
+ if (dflt_to_ptr)
+ cd->Str(i) = "), ";
+ else
+ cd->Str(i) = ", ";
+ ++i;
+ }
+
+ cd->ElemTyp(i) = A_Str;
+ cd->Str(i) = "&(";
+ ++i;
+ cnv_dest(loc, is_cstr, src, sym_indx, dest, cd, i);
+ ++i;
+ cd->ElemTyp(i) = A_Str;
+ cd->Str(i) = "))";
+ }
+ return cd;
+ }
+
+/*
+ * il_dflt - generate code for a defaulting conversion that always defaults.
+ */
+struct code *il_dflt(typcd, src, dflt, dest)
+int typcd;
+struct il_code *src;
+struct il_c *dflt;
+struct il_c *dest;
+ {
+ struct code *cd;
+ int sym_indx;
+
+ sym_indx = src->u[0].n;
+
+ if (typcd == TypCDbl) {
+ cd = alc_ary(5);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "(";
+ cnv_dest(PrmDbl, 0, src, sym_indx, dest, cd, 1); /* variable */
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = " = ";
+ sub_ilc(dflt, cd, 3); /* default */
+ cd->ElemTyp(4) = A_Str;
+ cd->Str(4) = ", 1)";
+ }
+ else if (typcd == TypCInt || typcd == TypECInt) {
+ cd = alc_ary(5);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "(";
+ cnv_dest(PrmInt, 0, src, sym_indx, dest, cd, 1); /* variable */
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = " = ";
+ sub_ilc(dflt, cd, 3); /* default */
+ cd->ElemTyp(4) = A_Str;
+ cd->Str(4) = ", 1)";
+ }
+ else if (typcd == TypTStr || typcd == str_typ) {
+ cd = alc_ary(5);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "(";
+ cnv_dest(0, 0, src, sym_indx, dest, cd, 1); /* variable */
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = " = ";
+ sub_ilc(dflt, cd, 3); /* default */
+ cd->ElemTyp(4) = A_Str;
+ cd->Str(4) = ", 1)";
+ }
+ else if (typcd == TypCStr) {
+ cd = alc_ary(5);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "(AsgnCStr(";
+ cnv_dest(0, 1, src, sym_indx, dest, cd, 1); /* variable */
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = ", ";
+ sub_ilc(dflt, cd, 3); /* default */
+ cd->ElemTyp(4) = A_Str;
+ cd->Str(4) = "), 1)";
+ }
+ else if (typcd == TypTCset || typcd == cset_typ) {
+ cd = alc_ary(7);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "(BlkLoc(";
+ cnv_dest(0, 0, src, sym_indx, dest, cd, 1); /* variable */
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = ") = (union block *)&";
+ sub_ilc(dflt, cd, 3); /* default */
+ cd->ElemTyp(4) = A_Str;
+ cd->Str(4) = ", ";
+ cnv_dest(0, 0, src, sym_indx, dest, cd, 5); /* variable */
+ cd->ElemTyp(6) = A_Str;
+ cd->Str(6) = ".dword = D_Cset, 1)";
+ }
+ else if (typcd == TypEInt || typcd == int_typ) {
+ cd = alc_ary(7);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "(IntVal(";
+ cnv_dest(0, 0, src, sym_indx, dest, cd, 1); /* variable */
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = ") = ";
+ sub_ilc(dflt, cd, 3); /* default */
+ cd->ElemTyp(4) = A_Str;
+ cd->Str(4) = ", ";
+ cnv_dest(0, 0, src, sym_indx, dest, cd, 5); /* variable */
+ cd->ElemTyp(6) = A_Str;
+ cd->Str(6) = ".dword = D_Integer, 1)";
+ }
+ else if (typcd == real_typ) {
+ cd = alc_ary(7);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "((BlkLoc(";
+ cnv_dest(0, 0, src, sym_indx, dest, cd, 1); /* variable */
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = ") = (union block *)alcreal(";
+ sub_ilc(dflt, cd, 3); /* default */
+ cd->ElemTyp(4) = A_Str;
+ cd->Str(4) = ")) == NULL ? (fatalerr(0,NULL), 0) : (";
+ cnv_dest(0, 0, src, sym_indx, dest, cd, 5); /* variable */
+ cd->ElemTyp(6) = A_Str;
+ cd->Str(6) = ".dword = D_Real, 1))";
+ }
+
+ return cd;
+ }
+
+/*
+ * cnv_dest - output the destination of a conversion.
+ */
+static void cnv_dest(loc, is_cstr, src, sym_indx, dest, cd, i)
+int loc;
+int is_cstr;
+struct il_code *src;
+int sym_indx;
+struct il_c *dest;
+struct code *cd;
+int i;
+ {
+ if (dest == NULL) {
+ /*
+ * Convert "in place", changing the location of a parameter if needed.
+ */
+ switch (loc) {
+ case PrmInt:
+ if (cur_symtab[sym_indx].itmp_indx < 0)
+ cur_symtab[sym_indx].itmp_indx = alc_itmp(intrnl_lftm);
+ cur_symtab[sym_indx].loc = itmp_loc(cur_symtab[sym_indx].itmp_indx);
+ break;
+ case PrmDbl:
+ if (cur_symtab[sym_indx].dtmp_indx < 0)
+ cur_symtab[sym_indx].dtmp_indx = alc_dtmp(intrnl_lftm);
+ cur_symtab[sym_indx].loc = dtmp_loc(cur_symtab[sym_indx].dtmp_indx);
+ break;
+ }
+ il_var(src, cd, i);
+ if (is_cstr)
+ cur_symtab[sym_indx].loc = loc_cpy(cur_symtab[sym_indx].loc,M_CharPtr);
+ }
+ else {
+ if (is_cstr && dest->il_c_type == ILC_Mod && dest->next == NULL &&
+ dest->n != RsltIndx && cur_symtab[dest->n].loc->mod_access != M_None) {
+ /*
+ * We are converting to a C string. The destination variable
+ * is not defined as a simple descriptor, but must be accessed
+ * as such for this conversion.
+ */
+ cd->ElemTyp(i) = A_ValLoc;
+ cd->ValLoc(i) = loc_cpy(cur_symtab[dest->n].loc, M_None);
+ }
+ else
+ sub_ilc(dest, cd, i);
+ }
+
+ }
+
+/*
+ * il_copy - produce code for an optimized "conversion" that always succeeds
+ * and just copies a value from one place to another.
+ */
+struct code *il_copy(dest, src)
+struct il_c *dest;
+struct val_loc *src;
+ {
+ struct code *cd;
+
+ cd = alc_ary(5);
+ cd->ElemTyp(0) = A_Str;
+ cd->Str(0) = "(";
+ sub_ilc(dest, cd, 1);
+ cd->ElemTyp(2) = A_Str;
+ cd->Str(2) = " = ";
+ cd->ElemTyp(3) = A_ValLoc;
+ cd->ValLoc(3) = src;
+ cd->ElemTyp(4) = A_Str;
+ cd->Str(4) = ", 1)";
+ return cd;
+ }
+
+/*
+ * loc_cpy - make a copy of a reference to a value location, but change
+ * the way the location is accessed.
+ */
+struct val_loc *loc_cpy(loc, mod_access)
+struct val_loc *loc;
+int mod_access;
+ {
+ struct val_loc *new_loc;
+
+ if (loc == NULL)
+ return NULL;
+ new_loc = NewStruct(val_loc);
+ *new_loc = *loc;
+ new_loc->mod_access = mod_access;
+ return new_loc;
+ }
+
+/*
+ * gen_tcase - generate in-line code for a type_case statement.
+ */
+static int gen_tcase(il, has_dflt)
+struct il_code *il;
+int has_dflt;
+ {
+ struct case_anlz case_anlz;
+
+ /*
+ * We can only get here if the type_case statement can be implemented
+ * with a no more than one type check. Determine how simple the
+ * code can be.
+ */
+ findcases(il, has_dflt, &case_anlz);
+ if (case_anlz.il_then == NULL) {
+ if (case_anlz.il_else == NULL)
+ return 1;
+ else
+ return gen_il(case_anlz.il_else);
+ }
+ else
+ return gen_if(typ_chk(il->u[0].fld, case_anlz.typcd), case_anlz.il_then,
+ case_anlz.il_else, sav_locs());
+ }
+
+/*
+ * gen_if - generate code to test a condition that might be true
+ * of false. Determine if execution can continue past this if statement.
+ */
+static int gen_if(cond_cd, il_then, il_else, locs)
+struct code *cond_cd;
+struct il_code *il_then;
+struct il_code *il_else;
+struct val_loc **locs;
+ {
+ struct val_loc **locs1;
+ struct code *lbl_then;
+ struct code *lbl_end;
+ struct code *else_loc;
+ struct code *cd;
+ int fall_thru;
+
+ lbl_then = oper_lbl("then");
+ lbl_end = oper_lbl("end if");
+ cd = NewCode(2);
+ cd->cd_id = C_If;
+ cd->Cond = cond_cd;
+ cd->ThenStmt = mk_goto(lbl_then);
+ cd_add(cd);
+ else_loc = cur_fnc->cursor;
+ cd_add(lbl_then);
+ fall_thru = gen_il(il_then);
+ cd_add(lbl_end);
+ locs1 = sav_locs();
+ rstr_locs(locs);
+ cur_fnc->cursor = else_loc; /* go back for the else clause */
+ fall_thru |= gen_il(il_else);
+ cd_add(mk_goto(lbl_end));
+ cur_fnc->cursor = lbl_end;
+ mrg_locs(locs1);
+ return fall_thru;
+ }
diff --git a/src/iconc/ivalues.c b/src/iconc/ivalues.c
new file mode 100644
index 0000000..4fbb288
--- /dev/null
+++ b/src/iconc/ivalues.c
@@ -0,0 +1,51 @@
+/*
+ * ivalues.c - routines for manipulating Icon values.
+ */
+#include "../h/gsupport.h"
+#include "ctrans.h"
+#include "csym.h"
+#include "ctree.h"
+#include "ccode.h"
+#include "cproto.h"
+#include "cglobals.h"
+
+
+/*
+ * iconint - convert the string representation of an Icon integer to a C long.
+ * Return -1 if the number is too big and large integers are supported.
+ */
+long iconint(image)
+char *image;
+ {
+ register int c;
+ register int r;
+ register char *s;
+ long n, n1;
+ int overflow;
+
+ s = image;
+ overflow = 0;
+ n = 0L;
+ while ((c = *s++) >= '0' && c <= '9') {
+ n1 = n * 10 + (c - '0');
+ if (n != n1 / 10)
+ overflow = 1;
+ n = n1;
+ }
+ if (c == 'r' || c == 'R') {
+ r = n;
+ n = 0L;
+ while ((c = *s++) != '\0') {
+ n1 = n * r + tonum(c);
+ if (n != n1 / r)
+ overflow = 1;
+ n = n1;
+ }
+ }
+ if (overflow)
+ if (largeints)
+ n = -1;
+ else
+ tfatal("large integer option required", image);
+ return n;
+ }
diff --git a/src/iconc/lifetime.c b/src/iconc/lifetime.c
new file mode 100644
index 0000000..9a4a7b5
--- /dev/null
+++ b/src/iconc/lifetime.c
@@ -0,0 +1,496 @@
+/*
+ * lifetime.c - perform liveness analysis to determine lifetime of intermediate
+ * results.
+ */
+#include "../h/gsupport.h"
+#include "../h/lexdef.h"
+#include "ctrans.h"
+#include "cglobals.h"
+#include "ctree.h"
+#include "ctoken.h"
+#include "csym.h"
+#include "ccode.h"
+#include "cproto.h"
+
+/*
+ * Prototypes for static functions.
+ */
+static void arg_life (nodeptr n, long min_result, long max_result,
+ int resume, int frst_arg, int nargs, nodeptr resumer,
+ nodeptr *failer, int *gen);
+
+static int postn = -1; /* relative position in execution order (all neg) */
+
+/*
+ * liveness - compute lifetimes of intermediate results.
+ */
+void liveness(n, resumer, failer, gen)
+nodeptr n;
+nodeptr resumer;
+nodeptr *failer;
+int *gen;
+ {
+ struct loop {
+ nodeptr resumer;
+ int gen;
+ nodeptr lifetime;
+ int every_cntrl;
+ struct loop *prev;
+ } loop_info;
+ struct loop *loop_sav;
+ static struct loop *cur_loop = NULL;
+ nodeptr failer1;
+ nodeptr failer2;
+ int gen1 = 0;
+ int gen2 = 0;
+ struct node *cases;
+ struct node *clause;
+ long min_result; /* minimum result sequence length */
+ long max_result; /* maximum result sequence length */
+ int resume; /* flag - resumption possible after last result */
+
+ n->postn = postn--;
+
+ switch (n->n_type) {
+ case N_Activat:
+ /*
+ * Activation can fail or succeed.
+ */
+ arg_life(n, 0L, 1L, 0, 1, 2, resumer, failer, gen);
+ break;
+
+ case N_Alt:
+ Tree1(n)->lifetime = n->lifetime;
+ Tree0(n)->lifetime = n->lifetime;
+ liveness(Tree1(n), resumer, &failer2, &gen2);
+ liveness(Tree0(n), resumer, &failer1, &gen1);
+ *failer = failer2;
+ *gen = 1;
+ break;
+
+ case N_Apply:
+ /*
+ * Assume operation can suspend or fail.
+ */
+ arg_life(n, 0L, UnbndSeq, 1, 0, 2, resumer, failer, gen);
+ break;
+
+ case N_Augop:
+ /*
+ * Impl0(n) is assignment. Impl1(n) is the augmented operation.
+ */
+ min_result = Impl0(n)->min_result * Impl1(n)->min_result;
+ max_result = Impl0(n)->max_result * Impl1(n)->max_result;
+ resume = Impl0(n)->resume | Impl1(n)->resume;
+ arg_life(n, min_result, max_result, resume, 2, 2, resumer, failer,
+ gen);
+ break;
+
+ case N_Bar:
+ if (resumer == NULL)
+ n->intrnl_lftm = n;
+ else
+ n->intrnl_lftm = resumer;
+ Tree0(n)->lifetime = n->lifetime;
+ liveness(Tree0(n), resumer, failer, &gen1);
+ *gen = 1;
+ break;
+
+ case N_Break:
+ if (cur_loop == NULL) {
+ nfatal(n, "invalid context for break", NULL);
+ return;
+ }
+ Tree0(n)->lifetime = cur_loop->lifetime;
+ loop_sav = cur_loop;
+ cur_loop = cur_loop->prev;
+ liveness(Tree0(n), loop_sav->resumer, &failer1, &gen1);
+ cur_loop = loop_sav;
+ cur_loop->gen |= gen1;
+ *failer = NULL;
+ *gen = 0;
+ break;
+
+ case N_Case:
+ *failer = resumer;
+ *gen = 0;
+
+ cases = Tree1(n);
+ while (cases != NULL) {
+ if (cases->n_type == N_Ccls) {
+ clause = cases;
+ cases = NULL;
+ }
+ else {
+ clause = Tree1(cases);
+ cases = Tree0(cases);
+ }
+
+ /*
+ * Body.
+ */
+ Tree1(clause)->lifetime = n->lifetime;
+ liveness(Tree1(clause), resumer, &failer2, &gen2);
+ if (resumer == NULL && failer2 != NULL)
+ *failer = n;
+ *gen |= gen2;
+
+ /*
+ * The expression being compared can be resumed.
+ */
+ Tree0(clause)->lifetime = clause;
+ liveness(Tree0(clause), clause, &failer1, &gen1);
+ }
+
+ if (Tree2(n) == NULL) {
+ if (resumer == NULL)
+ *failer = n;
+ }
+ else {
+ Tree2(n)->lifetime = n->lifetime;
+ liveness(Tree2(n), resumer, &failer2, &gen2); /* default */
+ if (resumer == NULL && failer2 != NULL)
+ *failer = n;
+ *gen |= gen2;
+ }
+
+ /*
+ * control clause is bounded
+ */
+ Tree0(n)->lifetime = n;
+ liveness(Tree0(n), NULL, &failer1, &gen1);
+ if (failer1 != NULL && *failer == NULL)
+ *failer = failer1;
+ break;
+
+ case N_Create:
+ Tree0(n)->lifetime = n;
+ loop_sav = cur_loop;
+ cur_loop = NULL; /* check for invalid break and next */
+ liveness(Tree0(n), n, &failer1, &gen1);
+ cur_loop = loop_sav;
+ *failer = NULL;
+ *gen = 0;
+ break;
+
+ case N_Cset:
+ case N_Empty:
+ case N_Id:
+ case N_Int:
+ case N_Real:
+ case N_Str:
+ *failer = resumer;
+ *gen = 0;
+ break;
+
+ case N_Field:
+ Tree0(n)->lifetime = n;
+ liveness(Tree0(n), resumer, failer, gen);
+ break;
+
+ case N_If:
+ Tree1(n)->lifetime = n->lifetime;
+ liveness(Tree1(n), resumer, failer, gen);
+ if (Tree2(n)->n_type != N_Empty) {
+ Tree2(n)->lifetime = n->lifetime;
+ liveness(Tree2(n), resumer, &failer2, &gen2);
+ if (failer2 != NULL) {
+ if (*failer == NULL)
+ *failer = failer2;
+ else {
+ if ((*failer)->postn < failer2->postn)
+ *failer = failer2;
+ if ((*failer)->postn < n->postn)
+ *failer = n;
+ }
+ }
+ *gen |= gen2;
+ }
+ /*
+ * control clause is bounded
+ */
+ Tree0(n)->lifetime = NULL;
+ liveness(Tree0(n), NULL, &failer1, &gen1);
+ if (Tree2(n)->n_type == N_Empty && failer1 != NULL && *failer == NULL)
+ *failer = failer1;
+ break;
+
+ case N_Invok:
+ /*
+ * Assume operation can suspend and fail.
+ */
+ arg_life(n, 0L, UnbndSeq, 1, 1, Val0(n) + 1, resumer, failer, gen);
+ break;
+
+ case N_InvOp:
+ arg_life(n, Impl1(n)->min_result, Impl1(n)->max_result,
+ Impl1(n)->resume, 2, Val0(n), resumer, failer, gen);
+ break;
+
+ case N_InvProc:
+ if (Proc1(n)->ret_flag & DoesFail)
+ min_result = 0L;
+ else
+ min_result = 1L;
+ if (Proc1(n)->ret_flag & DoesSusp) {
+ max_result = UnbndSeq;
+ resume = 1;
+ }
+ else {
+ max_result = 1L;
+ resume = 0;
+ }
+ arg_life(n, min_result, max_result, resume, 2, Val0(n), resumer,
+ failer, gen);
+ break;
+
+ case N_InvRec:
+ arg_life(n, err_conv ? 0L : 1L, 1L, 1, 2, Val0(n), resumer, failer,
+ gen);
+ break;
+
+ case N_Limit:
+ if (resumer == NULL)
+ n->intrnl_lftm = n;
+ else
+ n->intrnl_lftm = resumer;
+ Tree0(n)->lifetime = n->lifetime;
+ liveness(Tree0(n), resumer, &failer1, &gen1);
+ Tree1(n)->lifetime = n;
+ liveness(Tree1(n), failer1 == NULL ? n : failer1, &failer2, &gen2);
+ *failer = failer2;
+ *gen = gen1 | gen2;
+ break;
+
+ case N_Loop: {
+ loop_info.prev = cur_loop;
+ loop_info.resumer = resumer;
+ loop_info.gen = 0;
+ loop_info.every_cntrl = 0;
+ loop_info.lifetime = n->lifetime;
+ cur_loop = &loop_info;
+ switch ((int)Val0(Tree0(n))) {
+ case EVERY:
+ /*
+ * The body is bounded. The control clause is resumed
+ * by the control structure.
+ */
+ Tree2(n)->lifetime = NULL;
+ liveness(Tree2(n), NULL, &failer2, &gen2);
+ loop_info.every_cntrl = 1;
+ Tree1(n)->lifetime = NULL;
+ liveness(Tree1(n), n, &failer1, &gen1);
+ break;
+
+ case REPEAT:
+ /*
+ * The body is bounded.
+ */
+ Tree1(n)->lifetime = NULL;
+ liveness(Tree1(n), NULL, &failer1, &gen1);
+ break;
+
+ case SUSPEND:
+ /*
+ * The body is bounded. The control clause is resumed
+ * by the control structure.
+ */
+ Tree2(n)->lifetime = NULL;
+ liveness(Tree2(n), NULL, &failer2, &gen2);
+ loop_info.every_cntrl = 1;
+ Tree1(n)->lifetime = n;
+ liveness(Tree1(n), n, &failer1, &gen1);
+ break;
+
+ case WHILE:
+ case UNTIL:
+ /*
+ * The body and the control clause are each bounded.
+ */
+ Tree2(n)->lifetime = NULL;
+ liveness(Tree2(n), NULL, &failer1, &gen1);
+ Tree1(n)->lifetime = NULL;
+ liveness(Tree1(n), NULL, &failer1, &gen1);
+ break;
+ }
+ *failer = (resumer == NULL ? n : resumer); /* assume a loop can fail */
+ *gen = cur_loop->gen;
+ cur_loop = cur_loop->prev;
+ }
+ break;
+
+ case N_Next:
+ if (cur_loop == NULL) {
+ nfatal(n, "invalid context for next", NULL);
+ return;
+ }
+ if (cur_loop->every_cntrl)
+ *failer = n;
+ else
+ *failer = NULL;
+ *gen = 0;
+ break;
+
+ case N_Not:
+ /*
+ * The expression is bounded.
+ */
+ Tree0(n)->lifetime = NULL;
+ liveness(Tree0(n), NULL, &failer1, &gen1);
+ *failer = (resumer == NULL ? n : resumer);
+ *gen = 0;
+ break;
+
+ case N_Ret:
+ if (Val0(Tree0(n)) == RETURN) {
+ /*
+ * The expression is bounded.
+ */
+ Tree1(n)->lifetime = n;
+ liveness(Tree1(n), NULL, &failer1, &gen1);
+ }
+ *failer = NULL;
+ *gen = 0;
+ break;
+
+ case N_Scan: {
+ struct implement *asgn_impl;
+
+ if (resumer == NULL)
+ n->intrnl_lftm = n;
+ else
+ n->intrnl_lftm = resumer;
+
+ if (optab[Val0(Tree0(n))].tok.t_type == AUGQMARK) {
+ asgn_impl = optab[asgn_loc].binary;
+ arg_life(n, asgn_impl->min_result, asgn_impl->max_result,
+ asgn_impl->resume, 1, 2, resumer, failer, gen);
+ }
+ else {
+ Tree2(n)->lifetime = n->lifetime;
+ liveness(Tree2(n), resumer, &failer2, &gen2); /* body */
+ Tree1(n)->lifetime = n;
+ liveness(Tree1(n), failer2, &failer1, &gen1); /* subject */
+ *failer = failer1;
+ *gen = gen1 | gen2;
+ }
+ }
+ break;
+
+ case N_Sect:
+ /*
+ * Impl0(n) is sectioning.
+ */
+ min_result = Impl0(n)->min_result;
+ max_result = Impl0(n)->max_result;
+ resume = Impl0(n)->resume;
+ if (Impl1(n) != NULL) {
+ /*
+ * Impl1(n) is plus or minus.
+ */
+ min_result *= Impl1(n)->min_result;
+ max_result *= Impl1(n)->max_result;
+ resume |= Impl1(n)->resume;
+ }
+ arg_life(n, min_result, max_result, resume, 2, 3, resumer, failer,
+ gen);
+ break;
+
+ case N_Slist:
+ /*
+ * expr1 is not bounded, expr0 is bounded.
+ */
+ Tree1(n)->lifetime = n->lifetime;
+ liveness(Tree1(n), resumer, failer, gen);
+ Tree0(n)->lifetime = NULL;
+ liveness(Tree0(n), NULL, &failer1, &gen1);
+ break;
+
+ case N_SmplAsgn:
+ Tree3(n)->lifetime = n;
+ liveness(Tree3(n), resumer, failer, gen); /* 2nd operand */
+ Tree2(n)->lifetime = n->lifetime; /* may be result of := */
+ liveness(Tree2(n), *failer, &failer1, &gen1); /* 1st operand */
+ break;
+
+ case N_SmplAug:
+ /*
+ * Impl1(n) is the augmented operation.
+ */
+ arg_life(n, Impl1(n)->min_result, Impl1(n)->max_result,
+ Impl1(n)->resume, 2, 2, resumer, failer, gen);
+ break;
+
+ default:
+ fprintf(stderr, "compiler error: node type %d unknown\n", n->n_type);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+/*
+ * arg_life - compute the lifetimes of an argument list.
+ */
+static void arg_life(n, min_result, max_result, resume, frst_arg, nargs,
+ resumer, failer, gen)
+nodeptr n;
+long min_result; /* minimum result sequence length */
+long max_result; /* maximum result sequence length */
+int resume; /* flag - resumption possible after last result */
+int frst_arg;
+int nargs;
+nodeptr resumer;
+nodeptr *failer;
+int *gen;
+ {
+ nodeptr failer1;
+ nodeptr failer2;
+ nodeptr lifetime;
+ int inv_fail; /* failure after operation in invoked */
+ int reuse;
+ int gen2;
+ int i;
+
+ /*
+ * Determine what, if anything, can resume the rightmost argument.
+ */
+ if (resumer == NULL && min_result == 0)
+ failer1 = n;
+ else
+ failer1 = resumer;
+ if (failer1 == NULL)
+ inv_fail = 0;
+ else
+ inv_fail = 1;
+
+ /*
+ * If the operation can be resumed, variables internal to the operation
+ * have and extended lifetime.
+ */
+ if (resumer != NULL && (max_result > 1 || max_result == UnbndSeq || resume))
+ n->intrnl_lftm = resumer;
+ else
+ n->intrnl_lftm = n;
+
+ /*
+ * Go through the parameter list right to left, propagating resumption
+ * information, computing lifetimes, and determining whether anything
+ * can generate.
+ */
+ lifetime = n;
+ reuse = 0;
+ *gen = 0;
+ for (i = frst_arg + nargs - 1; i >= frst_arg; --i) {
+ n->n_field[i].n_ptr->lifetime = lifetime;
+ n->n_field[i].n_ptr->reuse = reuse;
+ liveness(n->n_field[i].n_ptr, failer1, &failer2, &gen2);
+ if (resumer != NULL && gen2)
+ lifetime = resumer;
+ if (inv_fail && gen2)
+ reuse = 1;
+ failer1 = failer2;
+ *gen |= gen2;
+ }
+ *failer = failer1;
+ if (max_result > 1 || max_result == UnbndSeq)
+ *gen = 1;
+ }
diff --git a/src/iconc/types.c b/src/iconc/types.c
new file mode 100644
index 0000000..cd3a3ef
--- /dev/null
+++ b/src/iconc/types.c
@@ -0,0 +1,893 @@
+/*
+ * typinfer.c - routines to perform type inference.
+ */
+#include "../h/gsupport.h"
+#include "../h/lexdef.h"
+#include "ctrans.h"
+#include "csym.h"
+#include "ctree.h"
+#include "ctoken.h"
+#include "cglobals.h"
+#include "ccode.h"
+#include "cproto.h"
+#ifdef TypTrc
+#ifdef HighResTime
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif /* HighResTime */
+#endif /* TypTrc */
+
+extern unsigned int null_bit; /* bit for null type */
+extern unsigned int str_bit; /* bit for string type */
+extern unsigned int cset_bit; /* bit for cset type */
+extern unsigned int int_bit; /* bit for integer type */
+extern unsigned int real_bit; /* bit for real type */
+extern unsigned int n_icntyp; /* number of non-variable types */
+extern unsigned int n_intrtyp; /* number of types in intermediate values */
+extern unsigned int val_mask; /* mask for non-var types in last int of type*/
+extern struct typ_info *type_array;
+
+/*
+ * free_struct_typinfo - frees a struct typinfo structure by placing
+ * it one a list of free structures
+ */
+#ifdef OptimizeType
+extern struct typinfo *start_typinfo;
+extern struct typinfo *high_typinfo;
+extern struct typinfo *low_typinfo;
+extern struct typinfo *free_typinfo;
+
+void free_struct_typinfo(struct typinfo *typ) {
+
+ typ->bits = (unsigned int *)free_typinfo;
+ free_typinfo = typ;
+}
+#endif /* OptimizeType */
+
+/*
+ * alloc_typ - allocate a compressed type structure and initializes
+ * the members to zero or NULL.
+ */
+#ifdef OptimizeType
+struct typinfo *alloc_typ(n_types)
+#else /* OptimizeType */
+unsigned int *alloc_typ(n_types)
+#endif /* OptimizeType */
+int n_types;
+{
+#ifdef OptimizeType
+ struct typinfo *typ;
+ int i;
+ unsigned int init = 0;
+
+ if ((free_typinfo == NULL) && (high_typinfo == low_typinfo)) {
+ /*
+ * allocate a large block of memory used to parcel out struct typinfo
+ * structures from
+ */
+ start_typinfo = (struct typinfo *)alloc(sizeof(struct typinfo) * TYPINFO_BLOCK);
+ high_typinfo = start_typinfo;
+ low_typinfo = start_typinfo + TYPINFO_BLOCK;
+ free_typinfo = NULL;
+ typ = start_typinfo;
+ high_typinfo++;
+ }
+ else if (free_typinfo != NULL) {
+ /*
+ * get a typinfo stucture from the list of free structures
+ */
+ typ = free_typinfo;
+ free_typinfo = (struct typinfo *)free_typinfo->bits;
+ }
+ else {
+ /*
+ * get a typinfo structure from the chunk of memory allocated
+ * previously
+ */
+ typ = high_typinfo;
+ high_typinfo++;
+ }
+ typ->packed = n_types;
+ if (!do_typinfer)
+ typ->bits = alloc_mem_typ(n_types);
+ else
+ typ->bits= NULL;
+ return typ;
+#else /* OptimizeType */
+ int n_ints;
+ unsigned int *typ;
+ int i;
+ unsigned int init = 0;
+
+ n_ints = NumInts(n_types);
+ typ = (unsigned int *)alloc((unsigned int)((n_ints)*sizeof(unsigned int)));
+
+ /*
+ * Initialization: if we are doing inference, start out assuming no types.
+ * If we are not doing inference, assume any type.
+ */
+ if (!do_typinfer)
+ init = ~init;
+ for (i = 0; i < n_ints; ++i)
+ typ[i] = init;
+ return typ;
+#endif /* OptimizeType */
+}
+
+/*
+ * alloc_mem_typ - actually allocates a full sized bit vector.
+ */
+#ifdef OptimizeType
+unsigned int *alloc_mem_typ(n_types)
+unsigned int n_types;
+{
+ int n_ints;
+ unsigned int *typ;
+ int i;
+ unsigned int init = 0;
+
+ n_ints = NumInts(n_types);
+ typ = (unsigned int *)alloc((unsigned int)((n_ints)*sizeof(unsigned int)));
+ if (!do_typinfer)
+ init = ~init;
+ for(i=0; i < n_ints ;++i)
+ typ[i] = init;
+ return typ;
+}
+#endif /* OptimizeType */
+
+/*
+ * set_typ - set a particular type bit in a type bit vector.
+ */
+void set_typ(type, bit)
+#ifdef OptimizeType
+struct typinfo *type;
+#else /* OptimizeType */
+unsigned int *type;
+#endif /* OptimizeType */
+unsigned int bit;
+{
+ unsigned int indx;
+ unsigned int mask;
+
+#ifdef OptimizeType
+ if (type->bits == NULL) {
+ if (bit == null_bit)
+ type->packed |= NULL_T;
+ else if (bit == real_bit)
+ type->packed |= REAL_T;
+ else if (bit == int_bit)
+ type->packed |= INT_T;
+ else if (bit == cset_bit)
+ type->packed |= CSET_T;
+ else if (bit == str_bit)
+ type->packed |= STR_T;
+ else {
+ /*
+ * if the bit to set is not one of the five builtin types
+ * then allocate a whole bit vector, copy the packed
+ * bits over, and set the requested bit
+ */
+ type->bits = alloc_mem_typ(DecodeSize(type->packed));
+ xfer_packed_types(type);
+ indx = bit / IntBits;
+ mask = 1;
+ mask <<= bit % IntBits;
+ type->bits[indx] |= mask;
+ }
+ }
+ else {
+ indx = bit / IntBits;
+ mask = 1;
+ mask <<= bit % IntBits;
+ type->bits[indx] |= mask;
+ }
+#else /* OptimizeType */
+ indx = bit / IntBits;
+ mask = 1;
+ mask <<= bit % IntBits;
+ type[indx] |= mask;
+#endif /* OptimizeType */
+}
+
+/*
+ * clr_type - clear a particular type bit in a type bit vector.
+ */
+void clr_typ(type, bit)
+#ifdef OptimizeType
+struct typinfo *type;
+#else /* OptimizeType */
+unsigned int *type;
+#endif /* OptimizeType */
+unsigned int bit;
+{
+ unsigned int indx;
+ unsigned int mask;
+
+#ifdef OptimizeType
+ if (type->bits == NULL) {
+ /*
+ * can only clear one of five builtin types
+ */
+ if (bit == null_bit)
+ type->packed &= ~NULL_T;
+ else if (bit == real_bit)
+ type->packed &= ~REAL_T;
+ else if (bit == int_bit)
+ type->packed &= ~INT_T;
+ else if (bit == cset_bit)
+ type->packed &= ~CSET_T;
+ else if (bit == str_bit)
+ type->packed &= ~STR_T;
+ }
+ else {
+ /*
+ * build bit mask to clear requested type in full bit vector
+ */
+ indx = bit / IntBits;
+ mask = 1;
+ mask <<= bit % IntBits;
+ type->bits[indx] &= ~mask;
+ }
+#else /* OptimizeType */
+ indx = bit / IntBits;
+ mask = 1;
+ mask <<= bit % IntBits;
+ type[indx] &= ~mask;
+#endif /* OptimizeType */
+}
+
+/*
+ * has_type - determine if a bit vector representing types has any bits
+ * set that correspond to a specific type code from the data base. Also,
+ * if requested, clear any such bits.
+ */
+int has_type(typ, typcd, clear)
+#ifdef OptimizeType
+struct typinfo *typ;
+#else /* OptimizeType */
+unsigned int *typ;
+#endif /* OptimizeType */
+int typcd;
+int clear;
+{
+ int frst_bit, last_bit;
+ int i;
+ int found;
+
+ found = 0;
+ bitrange(typcd, &frst_bit, &last_bit);
+ for (i = frst_bit; i < last_bit; ++i) {
+ if (bitset(typ, i)) {
+ found = 1;
+ if (clear)
+ clr_typ(typ, i);
+ }
+ }
+ return found;
+}
+
+/*
+ * other_type - determine if a bit vector representing types has any bits
+ * set that correspond to a type *other* than specific type code from the
+ * data base.
+ */
+int other_type(typ, typcd)
+#ifdef OptimizeType
+struct typinfo *typ;
+#else /* OptimizeType */
+unsigned int *typ;
+#endif /* OptimizeType */
+int typcd;
+ {
+ int frst_bit, last_bit;
+ int i;
+
+ bitrange(typcd, &frst_bit, &last_bit);
+ for (i = 0; i < frst_bit; ++i)
+ if (bitset(typ, i))
+ return 1;
+ for (i = last_bit; i < n_intrtyp; ++i)
+ if (bitset(typ, i))
+ return 1;
+ return 0;
+ }
+
+/*
+ * bitrange - determine the range of bit positions in a type bit vector
+ * that correspond to a type code from the data base.
+ */
+void bitrange(typcd, frst_bit, last_bit)
+int typcd;
+int *frst_bit;
+int *last_bit;
+ {
+ if (typcd == TypVar) {
+ /*
+ * All variable types.
+ */
+ *frst_bit = n_icntyp;
+ *last_bit = n_intrtyp;
+ }
+ else {
+ *frst_bit = type_array[typcd].frst_bit;
+ *last_bit = *frst_bit + type_array[typcd].num_bits;
+ }
+ }
+
+/*
+ * typcd_bits - set the bits of a bit vector corresponding to a type
+ * code from the data base.
+ */
+void typcd_bits(typcd, typ)
+int typcd;
+struct type *typ;
+ {
+ int frst_bit;
+ int last_bit;
+ int i;
+
+ if (typcd == TypEmpty)
+ return; /* Do nothing. */
+
+ if (typcd == TypAny) {
+ /*
+ * Set bits corresponding to first-class types.
+ */
+#ifdef OptimizeType
+ /*
+ * allocate a full bit vector and copy over packed types first
+ */
+ if (typ->bits->bits == NULL) {
+ typ->bits->bits = alloc_mem_typ(DecodeSize(typ->bits->packed));
+ xfer_packed_types(typ->bits);
+ }
+ for (i = 0; i < NumInts(n_icntyp) - 1; ++i)
+ typ->bits->bits[i] |= ~(unsigned int)0;
+ typ->bits->bits[i] |= val_mask;
+#else /* OptimizeType */
+ for (i = 0; i < NumInts(n_icntyp) - 1; ++i)
+ typ->bits[i] |= ~(unsigned int)0;
+ typ->bits[i] |= val_mask;
+#endif /* OptimizeType */
+ return;
+ }
+
+ bitrange(typcd, &frst_bit, &last_bit);
+#ifdef OptimizeType
+ if (last_bit > DecodeSize(typ->bits->packed)) /* bad abstract type computation */
+ return;
+#endif /* OptimizeType */
+ for (i = frst_bit; i < last_bit; ++i)
+ set_typ(typ->bits, i);
+ }
+
+/*
+ * bitset - determine if a specific bit in a bit vector is set.
+ */
+int bitset(typ, bit)
+#ifdef OptimizeType
+struct typinfo *typ;
+#else /* OptimizeType */
+unsigned int *typ;
+#endif /* OptimizeType */
+int bit;
+{
+ int mask;
+ int indx;
+
+#ifdef OptimizeType
+ if (typ->bits == NULL) {
+ /*
+ * check to see if the requested bit is set in the packed representation
+ * if the requested bit is not one of the five builtins then the
+ * lookup fails no matter what
+ */
+ if (bit == null_bit)
+ return (typ->packed & NULL_T);
+ else if (bit == real_bit)
+ return (typ->packed & REAL_T);
+ else if (bit == int_bit)
+ return (typ->packed & INT_T);
+ else if (bit == cset_bit)
+ return (typ->packed & CSET_T);
+ else if (bit == str_bit)
+ return (typ->packed & STR_T);
+ else
+ return 0;
+ }
+ else {
+ /*
+ * create a mask to check to see if the requested type bit is
+ * set on
+ */
+ indx = bit / IntBits;
+ mask = 1;
+ mask <<= bit % IntBits;
+ return typ->bits[indx] & mask;
+ }
+#else /* OptimizeType */
+ indx = bit / IntBits;
+ mask = 1;
+ mask <<= bit % IntBits;
+ return typ[indx] & mask;
+#endif /* OptimizeType */
+}
+
+/*
+ * is_empty - determine if a type bit vector is empty.
+ */
+int is_empty(typ)
+#ifdef OptimizeType
+struct typinfo *typ;
+#else /* OptimizeType */
+unsigned int *typ;
+#endif /* OptimizeType */
+{
+ int i;
+
+#ifdef OptimizeType
+ if (typ->bits == NULL) {
+ /*
+ * if any bits are set on then the vector is not empty
+ */
+ if (DecodePacked(typ->packed))
+ return 0;
+ else
+ return 1;
+ }
+ else {
+ for (i = 0; i < NumInts(n_intrtyp); ++i) {
+ if (typ->bits[i] != 0)
+ return 0;
+ }
+ return 1;
+ }
+#else /* OptimizeType */
+ for (i = 0; i < NumInts(n_intrtyp); ++i) {
+ if (typ[i] != 0)
+ return 0;
+ }
+ return 1;
+#endif /* OptimizeType */
+}
+
+/*
+ * xfer_packed_types - transfers the packed type representation
+ * to a full length bit vector representation in the same
+ * struct typinfo structure.
+ */
+#ifdef OptimizeType
+void xfer_packed_types(type)
+struct typinfo *type;
+{
+ unsigned int indx, mask;
+
+ /*
+ * for each IF statement built a mask to set each of the five builtins
+ * if they are present in the packed representation
+ */
+ if (type->packed & NULL_T) {
+ indx = null_bit / IntBits;
+ mask = 1;
+ mask <<= null_bit % IntBits;
+ type->bits[indx] |= mask;
+ }
+ if (type->packed & REAL_T) {
+ indx = real_bit / IntBits;
+ mask = 1;
+ mask <<= real_bit % IntBits;
+ type->bits[indx] |= mask;
+ }
+ if (type->packed & INT_T) {
+ indx = int_bit / IntBits;
+ mask = 1;
+ mask <<= int_bit % IntBits;
+ type->bits[indx] |= mask;
+ }
+ if (type->packed & CSET_T) {
+ indx = cset_bit / IntBits;
+ mask = 1;
+ mask <<= cset_bit % IntBits;
+ type->bits[indx] |= mask;
+ }
+ if (type->packed & STR_T) {
+ indx = str_bit / IntBits;
+ mask = 1;
+ mask <<= str_bit % IntBits;
+ type->bits[indx] |= mask;
+ }
+}
+
+/*
+ * xfer_packed_to_bits - sets those type bits from the src typinfo structure
+ * to the dest typinfo structure AND the src is a packed representation
+ * while the dest is a bit vector. Returns the number of new bits that
+ * were set in the destination.
+ */
+int xfer_packed_to_bits(src, dest, nsize)
+struct typinfo *src;
+struct typinfo *dest;
+int nsize;
+{
+ unsigned int indx, mask, old, rnsize;
+ int changes[5] = {-1,-1,-1,-1,-1};
+ int ix, membr = 0, i;
+
+ ix = 0;
+ rnsize = NumInts(nsize);
+ /*
+ * for each possible type set in the packed vector, create a mask
+ * and apply it to the dest. check to see if there was actually
+ * a change in the dest vector.
+ */
+ if (src->packed & NULL_T) {
+ indx = null_bit / IntBits;
+ if (indx < rnsize) {
+ mask = 1;
+ mask <<= null_bit % IntBits;
+ old = dest->bits[indx];
+ dest->bits[indx] |= mask;
+ if (old != dest->bits[indx]) {
+ membr = 0;
+ for (i=0; i < 5 ;i++)
+ /*
+ * checks to see if the bit just set happens to be in the
+ * same word as any other of the five builtins. if they
+ * are then we only want to count this as one change
+ */
+ if (indx == changes[i]) {
+ membr = 1; break;
+ }
+ if (!membr)
+ changes[ix++] = indx;
+ }
+ }
+ }
+ if (src->packed & REAL_T) {
+ indx = real_bit / IntBits;
+ if (indx < rnsize) {
+ mask = 1;
+ mask <<= real_bit % IntBits;
+ old = dest->bits[indx];
+ dest->bits[indx] |= mask;
+ if (old != dest->bits[indx]) {
+ membr = 0;
+ for (i=0; i < 5 ;i++)
+ if (indx == changes[i]) {
+ membr = 1; break;
+ }
+ if (!membr)
+ changes[ix++] = indx;
+ }
+ }
+ }
+ if (src->packed & INT_T) {
+ indx = int_bit / IntBits;
+ if (indx < rnsize) {
+ mask = 1;
+ mask <<= int_bit % IntBits;
+ old = dest->bits[indx];
+ dest->bits[indx] |= mask;
+ if (old != dest->bits[indx]) {
+ membr = 0;
+ for (i=0; i < 5 ;i++)
+ if (indx == changes[i]) {
+ membr = 1; break;
+ }
+ if (!membr)
+ changes[ix++] = indx;
+ }
+ }
+ }
+ if (src->packed & CSET_T) {
+ indx = cset_bit / IntBits;
+ if (indx < rnsize) {
+ mask = 1;
+ mask <<= cset_bit % IntBits;
+ old = dest->bits[indx];
+ dest->bits[indx] |= mask;
+ if (old != dest->bits[indx]) {
+ membr = 0;
+ for (i=0; i < 5 ;i++)
+ if (indx == changes[i]) {
+ membr = 1; break;
+ }
+ if (!membr)
+ changes[ix++] = indx;
+ }
+ }
+ }
+ if (src->packed & STR_T) {
+ indx = str_bit / IntBits;
+ if (indx < rnsize) {
+ mask = 1;
+ mask <<= str_bit % IntBits;
+ old = dest->bits[indx];
+ dest->bits[indx] |= mask;
+ if (old != dest->bits[indx]) {
+ membr = 0;
+ for (i=0; i < 5 ;i++)
+ if (indx == changes[i]) {
+ membr = 1; break;
+ }
+ if (!membr)
+ changes[ix++] = indx;
+ }
+ }
+ }
+ return ix;
+}
+
+/*
+ * and_bits_to_packed - performs a bitwise AND of two typinfo structures
+ * taking into account of packed or full bit representation.
+ */
+void and_bits_to_packed(src, dest, size)
+struct typinfo *src;
+struct typinfo *dest;
+int size;
+{
+ unsigned int indx, mask, val, destsz;
+ int i;
+
+ if ((src->bits == NULL) && (dest->bits == NULL))
+ /* Both are packed */
+ dest->packed &= (0xFF000000 | src->packed);
+ else if ((src->bits == NULL) && (dest->bits != NULL)) {
+ /*
+ * built a bit mask for each type in the src and AND it too
+ * the bit vector in dest
+ */
+ for (i=0; i < NumInts(size) ;i++) {
+ val = get_bit_vector(src,i);
+ dest->bits[i] &= val;
+ }
+ }
+ else if ((src->bits != NULL) && (dest->bits == NULL)) {
+ /*
+ * because an AND is being performed only those bits in the dest
+ * have the possibility of remaining set (i.e. five builtins)
+ * therefore if the bit is set in the packed check to see if
+ * it is also set in the full vector, if so then set it in the
+ * resulting vector, otherwise don't
+ */
+ destsz = DecodeSize(dest->packed);
+ mask = 1; val = 0;
+ if (dest->packed & NULL_T) {
+ mask <<= (null_bit % IntBits);
+ if (src->bits[(null_bit/IntBits)] & mask)
+ val |= NULL_T;
+ }
+ mask = 1;
+ if (dest->packed & REAL_T) {
+ mask <<= (real_bit % IntBits);
+ if (src->bits[(real_bit/IntBits)] & mask)
+ val |= REAL_T;
+ }
+ mask = 1;
+ if (dest->packed & INT_T) {
+ mask <<= (int_bit % IntBits);
+ if (src->bits[(int_bit/IntBits)] & mask)
+ val |= INT_T;
+ }
+ mask = 1;
+ if (dest->packed & CSET_T) {
+ mask <<= (cset_bit % IntBits);
+ if (src->bits[(cset_bit/IntBits)] & mask)
+ val |= CSET_T;
+ }
+ mask = 1;
+ if (dest->packed & STR_T) {
+ mask <<= (str_bit % IntBits);
+ if (src->bits[(str_bit/IntBits)] & mask)
+ val |= STR_T;
+ }
+ dest->packed = val | destsz;
+ }
+ else
+ for (i=0; i < NumInts(size) ;i++)
+ dest->bits[i] &= src->bits[i];
+}
+
+
+/*
+ * get_bit_vector - returns a bit mask from the selected word of a bit
+ * vector. e.g. if pos == 2, then check to see if any of the five
+ * builtins fall in the second word of a normal bit vector, if so
+ * create a bit mask with those types that fall in that word.
+ */
+
+unsigned int get_bit_vector(src, pos)
+struct typinfo *src;
+int pos;
+{
+ unsigned int val = 0, mask;
+
+ val = 0;
+ if ((src->packed & NULL_T) && ((null_bit / IntBits) == pos)) {
+ mask = 1;
+ mask <<= null_bit % IntBits;
+ val |= mask;
+ }
+ if ((src->packed & REAL_T) && ((real_bit / IntBits) == pos)) {
+ mask = 1;
+ mask <<= real_bit % IntBits;
+ val |= mask;
+ }
+ if ((src->packed & INT_T) && ((int_bit / IntBits) == pos)) {
+ mask = 1;
+ mask <<= int_bit % IntBits;
+ val |= mask;
+ }
+ if ((src->packed & CSET_T) && ((cset_bit / IntBits) == pos)) {
+ mask = 1;
+ mask <<= cset_bit % IntBits;
+ val |= mask;
+ }
+ if ((src->packed & STR_T) && ((str_bit / IntBits) == pos)) {
+ mask = 1;
+ mask <<= str_bit % IntBits;
+ val |= mask;
+ }
+ return val;
+}
+
+
+/*
+ * clr_packed - clears all bits within the nsize-th word for a packed
+ * representation.
+ */
+
+void clr_packed(src, nsize)
+struct typinfo *src;
+int nsize;
+{
+ unsigned int rnsize;
+
+ rnsize = NumInts(nsize);
+ if ((null_bit / IntBits) < rnsize)
+ src->packed &= ~NULL_T;
+ if ((real_bit / IntBits) < rnsize)
+ src->packed &= ~REAL_T;
+ if ((int_bit / IntBits) < rnsize)
+ src->packed &= ~INT_T;
+ if ((cset_bit / IntBits) < rnsize)
+ src->packed &= ~CSET_T;
+ if ((str_bit / IntBits) < rnsize)
+ src->packed &= ~STR_T;
+}
+
+/*
+ * cpy_packed_to_packed - copies the packed bits from one bit vector
+ * to another.
+ */
+
+void cpy_packed_to_packed(src, dest, nsize)
+struct typinfo *src;
+struct typinfo *dest;
+int nsize;
+{
+ unsigned int indx, rnsize;
+
+ rnsize = NumInts(nsize);
+ /*
+ * for each of the possible builtin types, check to see if the bit is
+ * set in the src and if present set it in the dest.
+ */
+ dest->packed = DecodeSize(dest->packed);
+ if (src->packed & NULL_T) {
+ indx = null_bit / IntBits;
+ if (indx < rnsize)
+ dest->packed |= NULL_T;
+ }
+ if (src->packed & REAL_T) {
+ indx = real_bit / IntBits;
+ if (indx < rnsize)
+ dest->packed |= REAL_T;
+ }
+ if (src->packed & INT_T) {
+ indx = int_bit / IntBits;
+ if (indx < rnsize)
+ dest->packed |= INT_T;
+ }
+ if (src->packed & CSET_T) {
+ indx = cset_bit / IntBits;
+ if (indx < rnsize)
+ dest->packed |= CSET_T;
+ }
+ if (src->packed & STR_T) {
+ indx = str_bit / IntBits;
+ if (indx < rnsize)
+ dest->packed |= STR_T;
+ }
+}
+
+
+/*
+ * mrg_packed_to_packed - merges the packed type bits of a src and dest
+ * bit vector.
+ */
+int mrg_packed_to_packed(src, dest, nsize)
+struct typinfo *src;
+struct typinfo *dest;
+int nsize;
+{
+ unsigned int indx, rnsize;
+ int changes[5] = {-1,-1,-1,-1,-1};
+ int ix = 0, membr = 0, i;
+
+ rnsize = NumInts(nsize);
+ /*
+ * for each of the five possible types in the src, check to see if it
+ * is set in the src and not set in the dest. if so then set it in
+ * the dest vector.
+ */
+ if ((src->packed & NULL_T) && !(dest->packed & NULL_T)) {
+ indx = null_bit / IntBits;
+ if (indx < rnsize) {
+ dest->packed |= NULL_T;
+ for(i=0; i<5 ;i++) {
+ if (indx == changes[i]) {
+ membr = 1; break;
+ }
+ }
+ if (!membr)
+ changes[ix++] = indx;
+ }
+ }
+ if ((src->packed & REAL_T) && !(dest->packed & REAL_T)) {
+ indx = real_bit / IntBits;
+ if (indx < rnsize) {
+ dest->packed |= REAL_T;
+ for(i=0; i<5 ;i++) {
+ if (indx == changes[i]) {
+ membr = 1; break;
+ }
+ }
+ if (!membr)
+ changes[ix++] = indx;
+ }
+ }
+ if ((src->packed & INT_T) && !(dest->packed & INT_T)){
+ indx = int_bit / IntBits;
+ if (indx < rnsize) {
+ dest->packed |= INT_T;
+ for(i=0; i<5 ;i++) {
+ if (indx == changes[i]) {
+ membr = 1; break;
+ }
+ }
+ if (!membr)
+ changes[ix++] = indx;
+ }
+ }
+ if ((src->packed & CSET_T) && !(dest->packed & CSET_T)) {
+ indx = cset_bit / IntBits;
+ if (indx < rnsize) {
+ dest->packed |= CSET_T;
+ for(i=0; i<5 ;i++) {
+ if (indx == changes[i]) {
+ membr = 1; break;
+ }
+ }
+ if (!membr)
+ changes[ix++] = indx;
+ }
+ }
+ if ((src->packed & STR_T) && !(dest->packed & STR_T)) {
+ indx = str_bit / IntBits;
+ if (indx < rnsize) {
+ dest->packed |= STR_T;
+ for(i=0; i<5 ;i++) {
+ if (indx == changes[i]) {
+ membr = 1; break;
+ }
+ }
+ if (!membr)
+ changes[ix++] = indx;
+ }
+ }
+ return ix;
+}
+#endif /* OptimizeType */
diff --git a/src/iconc/typinfer.c b/src/iconc/typinfer.c
new file mode 100644
index 0000000..8a96e23
--- /dev/null
+++ b/src/iconc/typinfer.c
@@ -0,0 +1,5189 @@
+/*
+ * typinfer.c - routines to perform type inference.
+ */
+#include "../h/gsupport.h"
+#include "../h/lexdef.h"
+#include "ctrans.h"
+#include "csym.h"
+#include "ctree.h"
+#include "ctoken.h"
+#include "cglobals.h"
+#include "ccode.h"
+#include "cproto.h"
+#ifdef TypTrc
+#ifdef HighResTime
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif /* HighResTime */
+#endif /* TypTrc */
+
+/*
+ * Information about co-expressions is keep on a list.
+ */
+struct t_coexpr {
+ nodeptr n; /* code for co-expression */
+ int typ_indx; /* relative type number (index) */
+ struct store *in_store; /* store entry into co-expression via activation */
+ struct store *out_store; /* store at end of co-expression */
+#ifdef OptimizeType
+ struct typinfo *act_typ; /* types passed via co-expression activation */
+ struct typinfo *rslt_typ; /* types resulting from "co-expression return" */
+#else /* OptimizeType */
+ unsigned int *act_typ; /* types passed via co-expression activation */
+ unsigned int *rslt_typ; /* types resulting from "co-expression return" */
+#endif /* OptimizeType */
+ int iteration;
+ struct t_coexpr *next;
+ };
+
+struct t_coexpr *coexp_lst;
+
+#ifdef TypTrc
+extern int typealloc; /* flag to account for allocation */
+extern long typespace; /* amount of space for type inference */
+#endif /* TypTrc */
+
+struct symtyps *cur_symtyps; /* maps run-time routine symbols to types */
+
+/*
+ * argtyps is the an array of types large enough to accommodate the argument
+ * list of any operation.
+ */
+struct argtyps {
+ struct argtyps *next;
+#ifdef OptimizeType
+ struct typinfo *types[1]; /* actual size is max_prm */
+#else /* OptimizeType */
+ unsigned int *types[1]; /* actual size is max_prm */
+#endif /* OptimizeType */
+ };
+
+/*
+ * prototypes for static functions.
+ */
+#ifdef OptimizeType
+void and_bits_to_packed (struct typinfo *src,
+ struct typinfo *dest, int size);
+struct typinfo *alloc_typ (int n_types);
+unsigned int *alloc_mem_typ (unsigned int n_types);
+int bitset (struct typinfo *typ, int bit);
+void clr_typ (struct typinfo *type, unsigned int bit);
+void clr_packed (struct typinfo *src, int nsize);
+void cpy_packed_to_packed (struct typinfo *src,
+ struct typinfo *dest, int nsize);
+static void deref_lcl (struct typinfo *src,
+ struct typinfo *dest);
+static int findloops ( struct node *n, int resume,
+ struct typinfo *rslt_type);
+static void gen_inv (struct typinfo *prc_typ, nodeptr n);
+int has_type (struct typinfo *typ, int typcd, int clear);
+static void infer_impl (struct implement *impl,
+ nodeptr n, struct symtyps *symtyps,
+ struct typinfo *rslt_typ);
+int is_empty (struct typinfo *typ);
+int mrg_packed_to_packed (struct typinfo *src,
+ struct typinfo *dest, int nsize);
+int other_type (struct typinfo *typ, int typcd);
+static void set_ret (struct typinfo *typ);
+void set_typ (struct typinfo *type, unsigned int bit);
+void typcd_bits (int typcd, struct type *typ);
+static void typ_deref (struct typinfo *src,
+ struct typinfo *dest, int chk);
+int xfer_packed_to_bits (struct typinfo *src,
+ struct typinfo *dest, int nsize);
+#else /* OptimizeType */
+unsigned int *alloc_typ (int n_types);
+int bitset (unsigned int *typ, int bit);
+void clr_typ (unsigned int *type, unsigned int bit);
+static void deref_lcl (unsigned int *src, unsigned int *dest);
+static int findloops ( struct node *n, int resume,
+ unsigned int *rslt_type);
+static void gen_inv (unsigned int *prc_typ, nodeptr n);
+int has_type (unsigned int *typ, int typcd, int clear);
+static void infer_impl (struct implement *impl,
+ nodeptr n, struct symtyps *symtyps,
+ unsigned int *rslt_typ);
+int is_empty (unsigned int *typ);
+int other_type (unsigned int *typ, int typcd);
+static void set_ret (unsigned int *typ);
+void set_typ (unsigned int *type, unsigned int bit);
+void typcd_bits (int typcd, struct type *typ);
+static void typ_deref (unsigned int *src, unsigned int *dest, int chk);
+#endif /* OptimizeType */
+
+static void abstr_new (struct node *n, struct il_code *il);
+static void abstr_typ (struct il_code *il, struct type *typ);
+static struct store *alloc_stor (int stor_sz, int n_types);
+static void chk_succ (int ret_flag, struct store *susp_stor);
+static struct store *cpy_store (struct store *source);
+static int eval_cond (struct il_code *il);
+static void free_argtyp (struct argtyps *argtyps);
+static void free_store (struct store *store);
+static void free_wktyp (struct type *typ);
+static void find_new (struct node *n);
+static struct argtyps *get_argtyp (void);
+static struct store *get_store (int clear);
+static struct type *get_wktyp (void);
+static void infer_act (nodeptr n);
+static void infer_con (struct rentry *rec, nodeptr n);
+static int infer_il (struct il_code *il);
+static void infer_nd (nodeptr n);
+static void infer_prc (struct pentry *proc, nodeptr n);
+static void mrg_act (struct t_coexpr *coexp,
+ struct store *e_store,
+ struct type *rslt_typ);
+static void mrg_store (struct store *source, struct store *dest);
+static void side_effect (struct il_code *il);
+static struct symtyps *symtyps (int nsyms);
+
+#ifdef TypTrc
+static void prt_d_typ (FILE *file, struct typinfo *typ);
+static void prt_typ (FILE *file, struct typinfo *typ);
+#endif /* TypTrc */
+
+#define CanFail 1
+
+/*
+ * cur_coexp is non-null while performing type inference on code from a
+ * create expression. If it is null, the possible current co-expressions
+ * must be found from cur_proc.
+ */
+struct t_coexpr *cur_coexp = NULL;
+
+struct gentry **proc_map; /* map procedure types to symbol table entries */
+struct rentry **rec_map; /* map record types to record information */
+struct t_coexpr **coexp_map; /* map co-expression types to information */
+
+struct typ_info *type_array;
+
+static int num_new; /* number of types supporting "new" abstract type comp */
+
+/*
+ * Data base component codes are mapped to type inferencing information
+ * using an array.
+ */
+struct compnt_info {
+ int frst_bit; /* first bit in bit vector allocated to component */
+ int num_bits; /* number of bits allocated to this component */
+ struct store *store; /* maps component "reference" to the type it holds */
+ };
+static struct compnt_info *compnt_array;
+
+static unsigned int frst_fld; /* bit number of 1st record field */
+static unsigned int n_fld; /* number of record fields */
+static unsigned int frst_gbl; /* bit number of 1st global reference type */
+static unsigned int n_gbl; /* number of global variables */
+static unsigned int n_nmgbl; /* number of named global variables */
+static unsigned int frst_loc; /* bit number of 1st local reference type */
+static unsigned int n_loc; /* maximum number of locals in any procedure */
+
+static unsigned int nxt_bit; /* next unassigned bit in bit vector */
+unsigned int n_icntyp; /* number of non-variable types */
+unsigned int n_intrtyp; /* number of types in intermediate values */
+static unsigned int n_rttyp; /* number of types in runtime computations */
+unsigned int val_mask; /* mask for non-var types in last int of type */
+
+unsigned int null_bit; /* bit for null type */
+unsigned int str_bit; /* bit for string type */
+unsigned int cset_bit; /* bit for cset type */
+unsigned int int_bit; /* bit for integer type */
+unsigned int real_bit; /* bit for real type */
+
+static struct store *fld_stor; /* record fields */
+
+static int *cur_new; /* allocated types for current operation */
+
+static struct store *succ_store = NULL; /* current success store */
+static struct store *fail_store = NULL; /* current failure store */
+
+static struct store *dummy_stor;
+static struct store *store_pool = NULL; /* free list of store structs */
+
+static struct type *type_pool = NULL; /* free list of type structs */
+static struct type cur_rslt = {0, NULL, NULL}; /* result type of operation */
+
+static struct argtyps *argtyp_pool = NULL; /* free list of arg type arrays */
+static struct argtyps *arg_typs = NULL; /* current arg type array */
+
+static int num_args; /* number of arguments for current operation */
+static int n_vararg; /* size of variable part of arg list to run-time routine */
+
+#ifdef OptimizeType
+static struct typinfo *any_typ; /* type bit vector with all bits on */
+struct typinfo *free_typinfo = NULL;
+struct typinfo *start_typinfo = NULL;
+struct typinfo *high_typinfo = NULL;
+struct typinfo *low_typinfo = NULL;
+#else /* OptimizeType */
+static unsigned int *any_typ; /* type bit vector with all bits on */
+#endif /* OptimizeType */
+
+long changed; /* number of changes to type information in this iteration */
+int iteration; /* iteration number for type inferencing */
+
+#ifdef TypTrc
+static FILE *trcfile = NULL; /* output file pointer for tracing */
+static char *trcname = NULL; /* output file name for tracing */
+static char *trc_indent = "";
+#endif /* TypTrc */
+
+
+/*
+ * typeinfer - infer types of operands. If "do_typinfer" is set, actually
+ * do abstract interpretation, otherwise assume any type for all operands.
+ */
+void typeinfer()
+ {
+ struct gentry *gptr;
+ struct lentry *lptr;
+ nodeptr call_main;
+ struct pentry *p;
+ struct rentry *rec;
+ struct t_coexpr *coexp;
+ struct store *init_store;
+ struct store *f_store;
+#ifdef OptimizeType
+ struct typinfo *type;
+#else /* OptimizeType */
+ unsigned int *type;
+#endif /* OptimizeType */
+ struct implement *ip;
+ struct lentry **lhash;
+ struct lentry **vartypmap;
+ int i, j, k;
+ int size;
+ int flag;
+
+#ifdef TypTrc
+ /*
+ * Set up for type tracing.
+ */
+ long start_infer, end_infer;
+
+#ifdef HighResTime
+ struct rusage rusage;
+
+ getrusage(RUSAGE_SELF, &rusage);
+ start_infer = rusage.ru_utime.tv_sec*1000 + rusage.ru_utime.tv_usec/1000;
+#else /* HighResTime */
+ start_infer = millisec();
+#endif /* HighResTime */
+
+ typealloc = 1; /* note allocation in this phase */
+
+ trcname = getenv("TYPTRC");
+
+ if (trcname != NULL && strlen(trcname) != 0) {
+
+ if (trcname[0] == '|') {
+ FILE *popen();
+
+ trcfile = popen(trcname+1, "w");
+ }
+ else
+
+ trcfile = fopen(trcname, "w");
+
+ if (trcfile == NULL) {
+ fprintf(stderr, "TYPTRC: cannot open %s\n", trcname);
+ fflush(stderr);
+ exit(EXIT_FAILURE);
+ }
+ }
+#endif /* TypTrc */
+
+ /*
+ * Make sure max_prm is large enough for any run-time routine.
+ */
+ for (i = 0; i < IHSize; ++i)
+ for (ip = bhash[i]; ip != NULL; ip = ip->blink)
+ if (ip->nargs > max_prm)
+ max_prm = ip->nargs;
+ for (i = 0; i < IHSize; ++i)
+ for (ip = ohash[i]; ip != NULL; ip = ip->blink)
+ if (ip->nargs > max_prm)
+ max_prm = ip->nargs;
+
+ /*
+ * Allocate an arrays to map data base type codes and component codes
+ * to type inferencing information.
+ */
+ type_array = (struct typ_info *)alloc((unsigned int)(num_typs *
+ sizeof(struct typ_info)));
+ compnt_array = (struct compnt_info *)alloc((unsigned int)(num_cmpnts *
+ sizeof(struct compnt_info)));
+
+ /*
+ * Find those types that support the "new" abstract type computation
+ * assign to them locations in the arrays of allocated types associated
+ * with operation invocations. Also initialize the number of type bits.
+ * Types with no subtypes have one bit. Types allocated with the the "new"
+ * abstract have a default sub-type that is allocated here. Procedures
+ * have a subtype to for string invocable operators. Co-expressions
+ * have a subtype for &main. Records are handled below.
+ */
+ num_new = 0;
+ for (i = 0; i < num_typs; ++i) {
+ if (icontypes[i].support_new)
+ type_array[i].new_indx = num_new++;
+ type_array[i].num_bits = 1; /* reserve one type bit */
+ }
+ type_array[list_typ].num_bits = 2; /* default & list for arg to main() */
+
+ cur_coexp = NewStruct(t_coexpr);
+ cur_coexp->n = NULL;
+ cur_coexp->next = NULL;
+ coexp_lst = cur_coexp;
+
+ if (do_typinfer) {
+ /*
+ * Go through the syntax tree for each procedure locating program
+ * points that may create structures at run time. Allocate the
+ * appropriate structure type(s) to each such point.
+ */
+ for (p = proc_lst; p != NULL; p = p->next) {
+ if (p->nargs < 0)
+ p->arg_lst = type_array[list_typ].num_bits++; /* list for varargs */
+ find_new(Tree1(p->tree)); /* initial clause */
+ find_new(Tree2(p->tree)); /* body of procedure */
+ }
+ }
+
+ /*
+ * Allocate a type number for each record type (use record number for
+ * offset) and a variable type number for each field.
+ */
+ n_fld = 0;
+ if (rec_lst == NULL) {
+ type_array[rec_typ].num_bits = 0;
+ rec_map = NULL;
+ }
+ else {
+ type_array[rec_typ].num_bits = rec_lst->rec_num + 1;
+ rec_map = (struct rentry **)alloc(
+ (unsigned int)((rec_lst->rec_num + 1)*sizeof(struct rentry *)));
+ for (rec = rec_lst; rec != NULL; rec = rec->next) {
+ rec->frst_fld = n_fld;
+ n_fld += rec->nfields;
+ rec_map[rec->rec_num] = rec;
+ }
+ }
+
+ /*
+ * Allocate type numbers to global variables. Don't count those procedure
+ * variables that are no longer referenced in the syntax tree. Do count
+ * static variables. Also allocate types to procedures, built-in functions,
+ * record constructors.
+ */
+ n_gbl = 0;
+ for (i = 0; i < GHSize; i++)
+ for (gptr = ghash[i]; gptr != NULL; gptr = gptr->blink) {
+ flag = gptr->flag;
+ if (flag & F_SmplInv)
+ gptr->index = -1; /* unused: set to something not a valid type */
+ else {
+ gptr->index = n_gbl++;
+ if (flag & (F_Proc | F_Record | F_Builtin))
+ gptr->init_type = type_array[proc_typ].num_bits++;
+ }
+ if (flag & F_Proc) {
+ for (lptr = gptr->val.proc->statics; lptr != NULL;lptr = lptr->next)
+ lptr->val.index = n_gbl++;
+ }
+ }
+ n_nmgbl = n_gbl;
+
+ /*
+ * Determine relative bit numbers for predefined variable types that
+ * are treated as sets of global variables.
+ */
+ for (i = 0; i < num_typs; ++i)
+ if (icontypes[i].deref == DrfGlbl)
+ type_array[i].frst_bit = n_gbl++; /* converted to absolute later */
+
+ proc_map = (struct gentry **)alloc(
+ (unsigned int)((type_array[proc_typ].num_bits)*sizeof(struct gentry *)));
+ proc_map[0] = NULL; /* proc type for string invocable operators */
+ for (i = 0; i < GHSize; i++)
+ for (gptr = ghash[i]; gptr != NULL; gptr = gptr->blink) {
+ flag = gptr->flag;
+ if (!(flag & F_SmplInv) && (flag & (F_Proc | F_Record | F_Builtin)))
+ proc_map[gptr->init_type] = gptr;
+ }
+
+ /*
+ * Allocate type numbers to local variables. The same numbers are reused
+ * in different procedures.
+ */
+ n_loc = 0;
+ for (p = proc_lst; p != NULL; p = p->next) {
+ i = Abs(p->nargs);
+ for (lptr = p->args; lptr != NULL; lptr = lptr->next)
+ lptr->val.index = --i;
+ i = Abs(p->nargs);
+ for (lptr = p->dynams; lptr != NULL; lptr = lptr->next)
+ lptr->val.index = i++;
+ n_loc = Max(n_loc, i);
+
+ /*
+ * produce a mapping from the variable types used in this procedure
+ * to the corresponding symbol table entries.
+ */
+ if (n_gbl + n_loc == 0)
+ vartypmap = NULL;
+ else
+ vartypmap = (struct lentry **)alloc(
+ (unsigned int)((n_gbl + n_loc)*sizeof(struct lentry *)));
+ for (i = 0; i < n_gbl + n_loc; ++i)
+ vartypmap[i] = NULL; /* no entries for foreign statics */
+ p->vartypmap = vartypmap;
+ lhash = p->lhash;
+ for (i = 0; i < LHSize; ++i) {
+ for (lptr = lhash[i]; lptr != NULL; lptr = lptr->blink) {
+ switch (lptr->flag) {
+ case F_Global:
+ gptr = lptr->val.global;
+ if (!(gptr->flag & F_SmplInv))
+ vartypmap[gptr->index] = lptr;
+ break;
+ case F_Static:
+ vartypmap[lptr->val.index] = lptr;
+ break;
+ case F_Dynamic:
+ case F_Argument:
+ vartypmap[n_gbl + lptr->val.index] = lptr;
+ }
+ }
+ }
+ }
+
+ /*
+ * There is a component reference subtype for every subtype of the
+ * associated aggregate type.
+ */
+ for (i = 0; i < num_cmpnts; ++i)
+ compnt_array[i].num_bits = type_array[typecompnt[i].aggregate].num_bits;
+
+ /*
+ * Assign bits for non-variable (first-class) types.
+ */
+ nxt_bit = 0;
+ for (i = 0; i < num_typs; ++i)
+ if (icontypes[i].deref == DrfNone) {
+ type_array[i].frst_bit = nxt_bit;
+ nxt_bit += type_array[i].num_bits;
+ }
+
+ n_icntyp = nxt_bit; /* number of first-class types */
+
+ /*
+ * Load some commonly needed bit numbers into global variable.
+ */
+ null_bit = type_array[null_typ].frst_bit;
+ str_bit = type_array[str_typ].frst_bit;
+ cset_bit = type_array[cset_typ].frst_bit;
+ int_bit = type_array[int_typ].frst_bit;
+ real_bit = type_array[real_typ].frst_bit;
+
+ /*
+ * Assign bits for predefined variable types that are not treated as
+ * sets of globals.
+ */
+ for (i = 0; i < num_typs; ++i)
+ if (icontypes[i].deref == DrfCnst || icontypes[i].deref == DrfSpcl) {
+ type_array[i].frst_bit = nxt_bit;
+ nxt_bit += type_array[i].num_bits;
+ }
+
+ /*
+ * Assign bits to aggregate compontents that are variables.
+ */
+ for (i = 0; i < num_cmpnts; ++i)
+ if (typecompnt[i].var) {
+ compnt_array[i].frst_bit = nxt_bit;
+ nxt_bit += compnt_array[i].num_bits;
+ }
+
+ /*
+ * Assign bits to record fields and named variables.
+ */
+ frst_fld = nxt_bit;
+ nxt_bit += n_fld;
+ frst_gbl = nxt_bit;
+ nxt_bit += n_gbl;
+ frst_loc = nxt_bit;
+ nxt_bit += n_loc;
+
+ /*
+ * Convert from relative to ablsolute bit numbers for predefined variable
+ * types that are treated as sets of global variables.
+ */
+ for (i = 0; i < num_typs; ++i)
+ if (icontypes[i].deref == DrfGlbl)
+ type_array[i].frst_bit += frst_gbl;
+
+ n_intrtyp = nxt_bit; /* number of types for intermediate values */
+
+ /*
+ * Assign bits to aggregate compontents that are not variables. These
+ * are the runtime system's internal descriptor reference types.
+ */
+ for (i = 0; i < num_cmpnts; ++i)
+ if (!typecompnt[i].var) {
+ compnt_array[i].frst_bit = nxt_bit;
+ nxt_bit += compnt_array[i].num_bits;
+ }
+
+ n_rttyp = nxt_bit; /* total size of type system */
+
+#ifdef TypTrc
+ if (trcfile != NULL) {
+ /*
+ * Output a summary of the type system.
+ */
+ for (i = 0; i < num_typs; ++i) {
+ fprintf(trcfile, "%s", icontypes[i].id);
+ if (strcmp(icontypes[i].id, icontypes[i].abrv) != 0)
+ fprintf(trcfile, "(%s)", icontypes[i].abrv);
+ fprintf(trcfile, " sub-types: %d\n", type_array[i].num_bits);
+ }
+ }
+#endif /* TypTrc */
+
+ /*
+ * The division between bits for first-class types and variables types
+ * generally occurs in the middle of a word. Set up a mask for extracting
+ * the first-class types from this word.
+ */
+ val_mask = 0;
+ i = n_icntyp - (NumInts(n_icntyp) - 1) * IntBits;
+ while (i--)
+ val_mask = (val_mask << 1) | 1;
+
+ if (do_typinfer) {
+ /*
+ * Create stores large enough for the component references. These
+ * are global to the entire program, rather than being propagated
+ * from node to node in the syntax tree.
+ */
+ for (i = 0; i < num_cmpnts; ++i) {
+ if (i == str_var)
+ size = n_intrtyp;
+ else
+ size = n_icntyp;
+ compnt_array[i].store = alloc_stor(compnt_array[i].num_bits, size);
+ }
+ fld_stor = alloc_stor(n_fld, n_icntyp);
+
+ dummy_stor = get_store(0);
+
+ /*
+ * First list is arg to main: a list of strings.
+ */
+ set_typ(compnt_array[lst_elem].store->types[1], str_typ);
+ }
+
+ /*
+ * Set up a type bit vector with all bits on.
+ */
+#ifdef OptimizeType
+ any_typ = alloc_typ(n_rttyp);
+ any_typ->bits = alloc_mem_typ(DecodeSize(any_typ->packed));
+ for (i = 0; i < NumInts(n_rttyp); ++i)
+ any_typ->bits[i] = ~(unsigned int)0;
+#else /* OptimizeType */
+ any_typ = alloc_typ(n_rttyp);
+ for (i = 0; i < NumInts(n_rttyp); ++i)
+ any_typ[i] = ~(unsigned int)0;
+#endif /* OptimizeType */
+
+ /*
+ * Initialize stores and return values for procedures. Also initialize
+ * flag indicating whether the procedure can be executed.
+ */
+ call_main = NULL;
+ for (p = proc_lst; p != NULL; p = p->next) {
+ if (do_typinfer) {
+ p->iteration = 0;
+ p->ret_typ = alloc_typ(n_intrtyp);
+ p->coexprs = alloc_typ(n_icntyp);
+ p->in_store = alloc_stor(n_gbl + n_loc, n_icntyp);
+ if (p->ret_flag & DoesSusp)
+ p->susp_store = alloc_stor(n_gbl, n_icntyp);
+ else
+ p->susp_store = NULL;
+ for (i = Abs(p->nargs); i < n_loc; ++i)
+ set_typ(p->in_store->types[n_gbl + i], null_bit);
+ if (p->nargs < 0)
+ set_typ(p->in_store->types[n_gbl + Abs(p->nargs) - 1],
+ type_array[list_typ].frst_bit + p->arg_lst);
+ if (strcmp(p->name, "main") == 0) {
+ /*
+ * create a the initial call to main with one list argument.
+ */
+ call_main = invk_main(p);
+ call_main->type = alloc_typ(n_intrtyp);
+ Tree2(call_main)->type = alloc_typ(n_intrtyp);
+ set_typ(Tree2(call_main)->type, type_array[list_typ].frst_bit + 1);
+ call_main->store = alloc_stor(n_gbl + n_loc, n_icntyp);
+ }
+ p->out_store = alloc_stor(n_gbl, n_icntyp);
+ p->reachable = 0;
+ }
+ else
+ p->reachable = 1;
+ /*
+ * Analyze the code of the procedure to determine where to place stores
+ * that survive iterations of type inferencing. Note, both the initial
+ * clause and the body of the procedure are bounded.
+ */
+ findloops(Tree1(p->tree), 0, NULL);
+ findloops(Tree2(p->tree), 0, NULL);
+ }
+
+ /*
+ * If type inferencing is suppressed, we have set up very conservative
+ * type information and will do no inferencing.
+ */
+ if (!do_typinfer)
+ return;
+
+ if (call_main == NULL)
+ return; /* no main procedure, cannot continue */
+ if (tfatals > 0)
+ return; /* don't do inference if there are fatal errors */
+
+ /*
+ * Construct mapping from co-expression types to information
+ * about the co-expressions and finish initializing the information.
+ */
+ i = type_array[coexp_typ].num_bits;
+ coexp_map = (struct t_coexpr **)alloc(
+ (unsigned int)(i * sizeof(struct t_coexpr *)));
+ for (coexp = coexp_lst; coexp != NULL; coexp = coexp->next) {
+ coexp_map[--i] = coexp;
+ coexp->typ_indx = i;
+ coexp->in_store = alloc_stor(n_gbl + n_loc, n_icntyp);
+ coexp->out_store = alloc_stor(n_gbl + n_loc, n_icntyp);
+ coexp->act_typ = alloc_typ(n_intrtyp);
+ coexp->rslt_typ = alloc_typ(n_intrtyp);
+ coexp->iteration = 0;
+ }
+
+ /*
+ * initialize globals
+ */
+ init_store = get_store(1);
+ for (i = 0; i < GHSize; i++)
+ for (gptr = ghash[i]; gptr != NULL; gptr = gptr->blink) {
+ flag = gptr->flag;
+ if (!(flag & F_SmplInv)) {
+ type = init_store->types[gptr->index];
+ if (flag & (F_Proc | F_Record | F_Builtin))
+ set_typ(type, type_array[proc_typ].frst_bit + gptr->init_type);
+ else
+ set_typ(type, null_bit);
+ }
+ }
+
+ /*
+ * Initialize types for predefined variable types.
+ */
+ for (i = 0; i < num_typs; ++i) {
+ type = NULL;
+ switch (icontypes[i].deref) {
+ case DrfGlbl:
+ /*
+ * Treated as a global variable.
+ */
+ type = init_store->types[type_array[i].frst_bit - frst_gbl];
+ break;
+ case DrfCnst:
+ /*
+ * Type doesn't change so keep one copy.
+ */
+ type = alloc_typ(n_intrtyp);
+ type_array[i].typ = type;
+ break;
+ }
+ if (type != NULL) {
+ /*
+ * Determine which types are in the initial type for this variable.
+ */
+ for (j = 0; j < num_typs; ++j) {
+ if (icontypes[i].typ[j] != '.') {
+ for (k = 0; k < type_array[j].num_bits; ++k)
+ set_typ(type, type_array[j].frst_bit + k);
+ }
+ }
+ }
+ }
+
+ f_store = get_store(1);
+
+ /*
+ * Type inferencing iterates over the program until a fixed point is
+ * reached.
+ */
+ changed = 1L; /* force first iteration */
+ iteration = 0;
+ if (verbose > 1)
+ fprintf(stderr, "type inferencing: ");
+
+ while (changed > 0L) {
+ changed = 0L;
+ ++iteration;
+
+#ifdef TypTrc
+ if (trcfile != NULL)
+ fprintf(trcfile, "**** iteration %d ****\n", iteration);
+#endif /* TypTrc */
+
+ /*
+ * Start at the implicit initial call to the main procedure. Inferencing
+ * walks the call graph from here.
+ */
+ succ_store = cpy_store(init_store);
+ fail_store = f_store;
+ infer_nd(call_main);
+
+ /*
+ * If requested, monitor the progress of inferencing.
+ */
+ switch (verbose) {
+ case 0:
+ case 1:
+ break;
+ case 2:
+ fprintf(stderr, ".");
+ break;
+ default: /* > 2 */
+ if (iteration != 1)
+ fprintf(stderr, ", ");
+ fprintf(stderr, "%ld", changed);
+ }
+ }
+
+ /*
+ * Type inferencing is finished, complete any diagnostic output.
+ */
+ if (verbose > 1)
+ fprintf(stderr, "\n");
+
+#ifdef TypTrc
+ if (trcfile != NULL) {
+
+#ifdef HighResTime
+ getrusage(RUSAGE_SELF, &rusage);
+ end_infer = rusage.ru_utime.tv_sec*1000 + rusage.ru_utime.tv_usec/1000;
+#else /* HighResTime */
+ end_infer = millisec();
+#endif /* HighResTime */
+ fprintf(trcfile, "\n**** inferencing time: %ld milliseconds\n",
+ end_infer - start_infer);
+ fprintf(trcfile, "\n**** inferencing space: %ld bytes\n",typespace);
+ fclose(trcfile);
+ }
+ typealloc = 0;
+#endif /* TypTrc */
+ }
+
+/*
+ * find_new - walk the syntax tree allocating structure types where
+ * operations create new structures.
+ */
+static void find_new(n)
+struct node *n;
+ {
+ struct t_coexpr *coexp;
+ struct node *cases;
+ struct node *clause;
+ int nargs;
+ int i;
+
+ n->new_types = NULL;
+ switch (n->n_type) {
+ case N_Cset:
+ case N_Empty:
+ case N_Id:
+ case N_Int:
+ case N_Next:
+ case N_Real:
+ case N_Str:
+ break;
+
+ case N_Bar:
+ case N_Break:
+ case N_Field:
+ case N_Not:
+ find_new(Tree0(n));
+ break;
+
+ case N_Alt:
+ case N_Apply:
+ case N_Limit:
+ case N_Slist:
+ find_new(Tree0(n));
+ find_new(Tree1(n));
+ break;
+
+ case N_Activat:
+ find_new(Tree1(n));
+ find_new(Tree2(n));
+ break;
+
+ case N_If:
+ find_new(Tree0(n)); /* control clause */
+ find_new(Tree1(n)); /* then clause */
+ find_new(Tree2(n)); /* else clause, may be N_Empty */
+ break;
+
+ case N_Create:
+ /*
+ * Allocate a sub-type for the co-expressions created here.
+ */
+ n->new_types = (int *)alloc((unsigned int)(sizeof(int)));
+ n->new_types[0] = type_array[coexp_typ].num_bits++;
+ coexp = NewStruct(t_coexpr);
+ coexp->n = Tree0(n);
+ coexp->next = coexp_lst;
+ coexp_lst = coexp;
+ find_new(Tree0(n));
+ break;
+
+ case N_Augop:
+ abstr_new(n, Impl0(n)->in_line); /* assignment */
+ abstr_new(n, Impl1(n)->in_line); /* the operation */
+ find_new(Tree2(n)); /* 1st operand */
+ find_new(Tree3(n)); /* 2nd operand */
+ break;
+
+ case N_Case:
+ find_new(Tree0(n)); /* control clause */
+ cases = Tree1(n);
+ while (cases != NULL) {
+ if (cases->n_type == N_Ccls) {
+ clause = cases;
+ cases = NULL;
+ }
+ else {
+ clause = Tree1(cases);
+ cases = Tree0(cases);
+ }
+
+ find_new(Tree0(clause)); /* value of clause */
+ find_new(Tree1(clause)); /* body of clause */
+ }
+ if (Tree2(n) != NULL)
+ find_new(Tree2(n)); /* deflt */
+ break;
+
+ case N_Invok:
+ nargs = Val0(n); /* number of arguments */
+ find_new(Tree1(n)); /* thing being invoked */
+ for (i = 1; i <= nargs; ++i)
+ find_new(n->n_field[i+1].n_ptr); /* arg i */
+ break;
+
+ case N_InvOp:
+ /*
+ * This is a call to an operation, this is what we must
+ * check for "new" abstract type computation.
+ */
+ nargs = Val0(n); /* number of arguments */
+ abstr_new(n, Impl1(n)->in_line); /* operation */
+ for (i = 1; i <= nargs; ++i)
+ find_new(n->n_field[i+1].n_ptr); /* arg i */
+ break;
+
+ case N_InvProc:
+ case N_InvRec:
+ nargs = Val0(n); /* number of arguments */
+ for (i = 1; i <= nargs; ++i)
+ find_new(n->n_field[i+1].n_ptr); /* arg i */
+ break;
+
+ case N_Loop:
+ switch ((int)Val0(Tree0(n))) {
+ case EVERY:
+ case SUSPEND:
+ case WHILE:
+ case UNTIL:
+ find_new(Tree1(n)); /* control clause */
+ find_new(Tree2(n)); /* do clause - may be N_Empty*/
+ break;
+
+ case REPEAT:
+ find_new(Tree1(n)); /* clause */
+ break;
+ }
+
+ case N_Ret:
+ if (Val0(Tree0(n)) == RETURN)
+ find_new(Tree1(n)); /* value - may be N_Empty */
+ break;
+
+ case N_Scan:
+ if (optab[Val0(Tree0(n))].tok.t_type == AUGQMARK)
+ abstr_new(n, optab[asgn_loc].binary->in_line);
+ find_new(Tree1(n)); /* subject */
+ find_new(Tree2(n)); /* body */
+ break;
+
+ case N_Sect:
+ abstr_new(n, Impl0(n)->in_line); /* sectioning */
+ if (Impl1(n) != NULL)
+ abstr_new(n, Impl1(n)->in_line); /* plus, minus, or nothing */
+ find_new(Tree2(n)); /* 1st operand */
+ find_new(Tree3(n)); /* 2nd operand */
+ find_new(Tree4(n)); /* 3rd operand */
+ break;
+
+ case N_SmplAsgn:
+ case N_SmplAug:
+ find_new(Tree3(n));
+ break;
+
+ default:
+ fprintf(stderr, "compiler error: node type %d unknown\n", n->n_type);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+/*
+ * abstr_new - find the abstract clauses in the implementation of an operation.
+ * If they indicate that the operations creates structures, allocate a
+ * type for the structures and associate it with the node in the syntax tree.
+ */
+static void abstr_new(n, il)
+struct node *n;
+struct il_code *il;
+ {
+ int i;
+ int num_cases, indx;
+ struct typ_info *t_info;
+
+ if (il == NULL)
+ return;
+
+ switch (il->il_type) {
+ case IL_New:
+ /*
+ * We have found a "new" construct in an abstract type computation.
+ * Make sure an array has been created to hold the types allocated
+ * to this call, then allocate the indicated type if one has not
+ * already been allocated.
+ */
+ if (n->new_types == NULL) {
+ n->new_types = (int *)alloc((unsigned int)(num_new * sizeof(int)));
+ for (i = 0; i < num_new; ++i)
+ n->new_types[i] = -1;
+ }
+ t_info = &type_array[il->u[0].n]; /* index by type code */
+ if (n->new_types[t_info->new_indx] < 0) {
+ n->new_types[t_info->new_indx] = t_info->num_bits++;
+#ifdef TypTrc
+ if (trcfile != NULL)
+ fprintf(trcfile, "%s (%d,%d) %s\n", n->n_file, n->n_line,
+ n->n_col, icontypes[il->u[0].n].id);
+#endif /* TypTrc */
+ }
+ i = il->u[1].n; /* num args */
+ indx = 2;
+ while (i--)
+ abstr_new(n, il->u[indx++].fld);
+ break;
+
+ case IL_If1:
+ abstr_new(n, il->u[1].fld);
+ break;
+
+ case IL_If2:
+ abstr_new(n, il->u[1].fld);
+ abstr_new(n, il->u[2].fld);
+ break;
+
+ case IL_Tcase1:
+ num_cases = il->u[1].n;
+ indx = 2;
+ for (i = 0; i < num_cases; ++i) {
+ indx += 2; /* skip type info */
+ abstr_new(n, il->u[indx++].fld); /* action */
+ }
+ break;
+
+ case IL_Tcase2:
+ num_cases = il->u[1].n;
+ indx = 2;
+ for (i = 0; i < num_cases; ++i) {
+ indx += 2; /* skip type info */
+ abstr_new(n, il->u[indx++].fld); /* action */
+ }
+ abstr_new(n, il->u[indx].fld); /* default */
+ break;
+
+ case IL_Lcase:
+ num_cases = il->u[0].n;
+ indx = 1;
+ for (i = 0; i < num_cases; ++i) {
+ ++indx; /* skip selection num */
+ abstr_new(n, il->u[indx++].fld); /* action */
+ }
+ abstr_new(n, il->u[indx].fld); /* default */
+ break;
+
+ case IL_Acase:
+ abstr_new(n, il->u[2].fld); /* C_integer action */
+ if (largeints)
+ abstr_new(n, il->u[3].fld); /* integer action */
+ abstr_new(n, il->u[4].fld); /* C_double action */
+ break;
+
+ case IL_Abstr:
+ case IL_Inter:
+ case IL_Lst:
+ case IL_TpAsgn:
+ case IL_Union:
+ abstr_new(n, il->u[0].fld);
+ abstr_new(n, il->u[1].fld);
+ break;
+
+ case IL_Compnt:
+ case IL_Store:
+ case IL_VarTyp:
+ abstr_new(n, il->u[0].fld);
+ break;
+
+ case IL_Block:
+ case IL_Call:
+ case IL_Const: /* should have been replaced by literal node */
+ case IL_Err1:
+ case IL_Err2:
+ case IL_IcnTyp:
+ case IL_Subscr:
+ case IL_Var:
+ break;
+
+ default:
+ fprintf(stderr, "compiler error: unknown info in data base\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+/*
+ * alloc_stor - allocate a store with empty types.
+ */
+static struct store *alloc_stor(stor_sz, n_types)
+int stor_sz;
+int n_types;
+ {
+ struct store *stor;
+ int i;
+
+ /*
+ * If type inferencing is disabled, we don't actually make use of
+ * any stores, but the initialization code asks for them anyway.
+ */
+ if (!do_typinfer)
+ return NULL;
+
+#ifdef OptimizeType
+ stor = (struct store *)alloc((unsigned int)(sizeof(struct store) +
+ ((stor_sz - 1) * sizeof(struct typinfo *))));
+ stor->next = NULL;
+ stor->perm = 1;
+ for (i = 0; i < stor_sz; ++i) {
+ stor->types[i] = (struct typinfo *)alloc_typ(n_types);
+ }
+#else /* OptimizeType */
+ stor = (struct store *)alloc((unsigned int)(sizeof(struct store) +
+ ((stor_sz - 1) * sizeof(unsigned int *))));
+ stor->next = NULL;
+ stor->perm = 1;
+ for (i = 0; i < stor_sz; ++i) {
+ stor->types[i] = (unsigned int *)alloc_typ(n_types);
+ }
+#endif /* OptimizeType */
+
+ return stor;
+ }
+
+/*
+ * findloops - find both explicit loops and implicit loops caused by
+ * goal-directed evaluation. Allocate stores for them. Determine which
+ * expressions cannot fail (used to eliminate dynamic store allocation
+ * for some bounded expressions). Allocate stores for 'if' and 'case'
+ * expressions that can be resumed. Initialize expression types.
+ * The syntax tree is walked in reverse execution order looking for
+ * failure and for generators.
+ */
+static int findloops(n, resume, rslt_type)
+struct node *n;
+int resume;
+#ifdef OptimizeType
+struct typinfo *rslt_type;
+#else /* OptimizeType */
+unsigned int *rslt_type;
+#endif /* OptimizeType */
+ {
+ struct loop {
+ int resume;
+ int can_fail;
+ int every_cntrl;
+#ifdef OptimizeType
+ struct typinfo *type;
+#else /* OptimizeType */
+ unsigned int *type;
+#endif /* OptimizeType */
+ struct loop *prev;
+ } loop_info;
+ struct loop *loop_sav;
+ static struct loop *cur_loop = NULL;
+ struct node *cases;
+ struct node *clause;
+ int can_fail;
+ int nargs, i;
+
+ n->store = NULL;
+ if (!do_typinfer)
+ rslt_type = any_typ;
+
+ switch (n->n_type) {
+ case N_Activat:
+ if (rslt_type == NULL)
+ rslt_type = alloc_typ(n_intrtyp);
+ n->type = rslt_type;
+ /*
+ * Assume activation can fail.
+ */
+ can_fail = findloops(Tree2(n), 1, NULL);
+ can_fail = findloops(Tree1(n), can_fail, NULL);
+ n->symtyps = symtyps(2);
+ if (optab[Val0(Tree0(n))].tok.t_type == AUGAT)
+ n->symtyps->next = symtyps(2);
+ break;
+
+ case N_Alt:
+ if (rslt_type == NULL)
+ rslt_type = alloc_typ(n_intrtyp);
+ n->type = rslt_type;
+
+#ifdef TypTrc
+ rslt_type = NULL; /* don't share result loc with subexpressions*/
+#endif /* TypTrc */
+
+ if (resume)
+ n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
+ can_fail = findloops(Tree0(n), resume, rslt_type) |
+ findloops(Tree1(n), resume, rslt_type);
+ break;
+
+ case N_Apply:
+ if (rslt_type == NULL)
+ n->type = alloc_typ(n_intrtyp);
+ else
+ n->type = rslt_type;
+ /*
+ * Assume operation can suspend or fail.
+ */
+ n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
+ can_fail = findloops(Tree1(n), 1, NULL);
+ can_fail = findloops(Tree0(n), can_fail, NULL);
+ n->symtyps = symtyps(max_sym);
+ break;
+
+ case N_Augop:
+ if (rslt_type == NULL)
+ rslt_type = alloc_typ(n_intrtyp);
+ n->type = rslt_type;
+
+ can_fail = resume;
+ /*
+ * Impl0(n) is assignment.
+ */
+ if (resume && Impl0(n)->ret_flag & DoesSusp)
+ n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
+ if (MightFail(Impl0(n)->ret_flag))
+ can_fail = 1;
+ /*
+ * Impl1(n) is the augmented operation.
+ */
+ if (can_fail && Impl1(n)->ret_flag & DoesSusp && n->store == NULL)
+ n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
+ if (MightFail(Impl1(n)->ret_flag))
+ can_fail = 1;
+ can_fail = findloops(Tree3(n), can_fail, NULL); /* operand 2 */
+ can_fail = findloops(Tree2(n), can_fail, NULL); /* operand 1 */
+ n->type = Tree2(n)->type;
+ Typ4(n) = alloc_typ(n_intrtyp);
+ n->symtyps = symtyps(n_arg_sym(Impl1(n)));
+ n->symtyps->next = symtyps(n_arg_sym(Impl0(n)));
+ break;
+
+ case N_Bar:
+ can_fail = findloops(Tree0(n), resume, rslt_type);
+ n->type = Tree0(n)->type;
+ n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
+ break;
+
+ case N_Break:
+ if (cur_loop == NULL) {
+ nfatal(n, "invalid context for break", NULL);
+ return 0;
+ }
+ if (rslt_type == NULL)
+ n->type = alloc_typ(n_intrtyp);
+ else
+ n->type = rslt_type;
+ loop_sav = cur_loop;
+ cur_loop = cur_loop->prev;
+ loop_sav->can_fail |= findloops(Tree0(n), loop_sav->resume,
+ loop_sav->type);
+ cur_loop = loop_sav;
+ can_fail = 0;
+ break;
+
+ case N_Case:
+ if (rslt_type == NULL)
+ rslt_type = alloc_typ(n_intrtyp);
+ n->type = rslt_type;
+
+#ifdef TypTrc
+ rslt_type = NULL; /* don't share result loc with subexpressions*/
+#endif /* TypTrc */
+
+ if (resume)
+ n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
+
+ /*
+ * control clause is bounded
+ */
+ can_fail = findloops(Tree0(n), 0, NULL);
+
+ cases = Tree1(n);
+ while (cases != NULL) {
+ if (cases->n_type == N_Ccls) {
+ clause = cases;
+ cases = NULL;
+ }
+ else {
+ clause = Tree1(cases);
+ cases = Tree0(cases);
+ }
+
+ /*
+ * The expression being compared can be resumed.
+ */
+ findloops(Tree0(clause), 1, NULL);
+
+ /*
+ * Body.
+ */
+ can_fail |= findloops(Tree1(clause), resume, rslt_type);
+ }
+
+ if (Tree2(n) == NULL)
+ can_fail = 1;
+ else
+ can_fail |= findloops(Tree2(n), resume, rslt_type); /* default */
+ break;
+
+ case N_Create:
+ if (rslt_type == NULL)
+ n->type = alloc_typ(n_intrtyp);
+ else
+ n->type = rslt_type;
+ findloops(Tree0(n), 1, NULL); /* co-expression code */
+ /*
+ * precompute type
+ */
+ i= type_array[coexp_typ].frst_bit;
+ if (do_typinfer)
+ i += n->new_types[0];
+ set_typ(n->type, i);
+ can_fail = resume;
+ break;
+
+ case N_Cset:
+ if (rslt_type == NULL)
+ n->type = alloc_typ(n_intrtyp);
+ else
+ n->type = rslt_type;
+ set_typ(n->type, type_array[cset_typ].frst_bit); /* precompute type */
+ can_fail = resume;
+ break;
+
+ case N_Empty:
+ if (rslt_type == NULL)
+ n->type = alloc_typ(n_intrtyp);
+ else
+ n->type = rslt_type;
+ set_typ(n->type, null_bit); /* precompute type */
+ can_fail = resume;
+ break;
+
+ case N_Id: {
+ struct lentry *var;
+
+ if (rslt_type == NULL)
+ n->type = alloc_typ(n_intrtyp);
+ else
+ n->type = rslt_type;
+ /*
+ * Precompute type
+ */
+ var = LSym0(n);
+ if (var->flag & F_Global)
+ set_typ(n->type, frst_gbl + var->val.global->index);
+ else if (var->flag & F_Static)
+ set_typ(n->type, frst_gbl + var->val.index);
+ else
+ set_typ(n->type, frst_loc + var->val.index);
+ can_fail = resume;
+ }
+ break;
+
+ case N_Field:
+ if (rslt_type == NULL)
+ n->type = alloc_typ(n_intrtyp);
+ else
+ n->type = rslt_type;
+ can_fail = findloops(Tree0(n), resume, NULL);
+ n->symtyps = symtyps(1);
+ break;
+
+ case N_If:
+ if (rslt_type == NULL)
+ rslt_type = alloc_typ(n_intrtyp);
+ n->type = rslt_type;
+
+#ifdef TypTrc
+ rslt_type = NULL; /* don't share result loc with subexpressions*/
+#endif /* TypTrc */
+ /*
+ * control clause is bounded
+ */
+ findloops(Tree0(n), 0, NULL);
+ can_fail = findloops(Tree1(n), resume, rslt_type);
+ if (Tree2(n)->n_type == N_Empty)
+ can_fail = 1;
+ else {
+ if (resume)
+ n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
+ can_fail |= findloops(Tree2(n), resume, rslt_type);
+ }
+ break;
+
+ case N_Int:
+ if (rslt_type == NULL)
+ n->type = alloc_typ(n_intrtyp);
+ else
+ n->type = rslt_type;
+ set_typ(n->type, int_bit); /* precompute type */
+ can_fail = resume;
+ break;
+
+ case N_Invok:
+ if (rslt_type == NULL)
+ n->type = alloc_typ(n_intrtyp);
+ else
+ n->type = rslt_type;
+ nargs = Val0(n); /* number of arguments */
+ /*
+ * Assume operation can suspend and fail.
+ */
+ if (resume)
+ n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
+ can_fail = 1;
+ for (i = nargs; i >= 0; --i)
+ can_fail = findloops(n->n_field[i+1].n_ptr, can_fail, NULL);
+ n->symtyps = symtyps(max_sym);
+ break;
+
+ case N_InvOp:
+ if (rslt_type == NULL)
+ n->type = alloc_typ(n_intrtyp);
+ else
+ n->type = rslt_type;
+ nargs = Val0(n); /* number of arguments */
+ if (resume && Impl1(n)->ret_flag & DoesSusp)
+ n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
+ if (MightFail(Impl1(n)->ret_flag))
+ can_fail = 1;
+ else
+ can_fail = resume;
+ for (i = nargs; i >= 1; --i)
+ can_fail = findloops(n->n_field[i+1].n_ptr, can_fail, NULL);
+ n->symtyps = symtyps(n_arg_sym(Impl1(n)));
+ break;
+
+ case N_InvProc:
+ if (rslt_type == NULL)
+ n->type = alloc_typ(n_intrtyp);
+ else
+ n->type = rslt_type;
+ nargs = Val0(n); /* number of arguments */
+ if (resume && Proc1(n)->ret_flag & DoesSusp)
+ n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
+ if (Proc1(n)->ret_flag & DoesFail)
+ can_fail = 1;
+ else
+ can_fail = resume;
+ for (i = nargs; i >= 1; --i)
+ can_fail = findloops(n->n_field[i+1].n_ptr, can_fail, NULL);
+ break;
+
+ case N_InvRec:
+ if (rslt_type == NULL)
+ n->type = alloc_typ(n_intrtyp);
+ else
+ n->type = rslt_type;
+ nargs = Val0(n); /* number of args */
+ if (err_conv)
+ can_fail = 1;
+ else
+ can_fail = resume;
+ for (i = nargs; i >= 1; --i)
+ can_fail = findloops(n->n_field[i+1].n_ptr, can_fail, NULL);
+ break;
+
+ case N_Limit:
+ findloops(Tree0(n), resume, rslt_type);
+ can_fail = findloops(Tree1(n), 1, NULL);
+ n->type = Tree0(n)->type;
+ n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
+ n->symtyps = symtyps(1);
+ break;
+
+ case N_Loop: {
+ if (rslt_type == NULL)
+ n->type = alloc_typ(n_intrtyp);
+ else
+ n->type = rslt_type;
+ loop_info.prev = cur_loop;
+ loop_info.resume = resume;
+ loop_info.can_fail = 0;
+ loop_info.every_cntrl = 0;
+ loop_info.type = n->type;
+ cur_loop = &loop_info;
+ switch ((int)Val0(Tree0(n))) {
+ case EVERY:
+ case SUSPEND:
+ /*
+ * The control clause can be resumed. The body is bounded.
+ */
+ loop_info.every_cntrl = 1;
+ can_fail = findloops(Tree1(n), 1, NULL);
+ loop_info.every_cntrl = 0;
+ findloops(Tree2(n), 0, NULL);
+ break;
+
+ case REPEAT:
+ /*
+ * The loop needs a saved store. The body is bounded.
+ */
+ findloops(Tree1(n), 0, NULL);
+ can_fail = 0;
+ break;
+
+ case WHILE:
+ /*
+ * The loop needs a saved store. The control
+ * clause and the body are each bounded.
+ */
+ can_fail = findloops(Tree1(n), 0, NULL);
+ findloops(Tree2(n), 0, NULL);
+ break;
+
+ case UNTIL:
+ /*
+ * The loop needs a saved store. The control
+ * clause and the body are each bounded.
+ */
+ findloops(Tree1(n), 0, NULL);
+ findloops(Tree2(n), 0, NULL);
+ can_fail = 1;
+ break;
+ }
+ n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
+ if (do_typinfer && resume)
+ n->store->next = alloc_stor(n_gbl + n_loc, n_icntyp);
+ can_fail |= cur_loop->can_fail;
+ cur_loop = cur_loop->prev;
+ }
+ break;
+
+ case N_Next:
+ if (cur_loop == NULL) {
+ nfatal(n, "invalid context for next", NULL);
+ return 1;
+ }
+ if (rslt_type == NULL)
+ n->type = alloc_typ(n_intrtyp);
+ else
+ n->type = rslt_type;
+ can_fail = cur_loop->every_cntrl;
+ break;
+
+ case N_Not:
+ if (rslt_type == NULL)
+ n->type = alloc_typ(n_intrtyp);
+ else
+ n->type = rslt_type;
+ set_typ(n->type, null_bit); /* precompute type */
+ /*
+ * The expression is bounded.
+ */
+ findloops(Tree0(n), 0, NULL);
+ can_fail = 1;
+ break;
+
+ case N_Real:
+ if (rslt_type == NULL)
+ n->type = alloc_typ(n_intrtyp);
+ else
+ n->type = rslt_type;
+ set_typ(n->type, real_bit); /* precompute type */
+ can_fail = resume;
+ break;
+
+ case N_Ret:
+ if (rslt_type == NULL)
+ n->type = alloc_typ(n_intrtyp);
+ else
+ n->type = rslt_type;
+ if (Val0(Tree0(n)) == RETURN) {
+ /*
+ * The expression is bounded.
+ */
+ findloops(Tree1(n), 0, NULL);
+ }
+ can_fail = 0;
+ break;
+
+ case N_Scan: {
+ struct implement *asgn_impl;
+
+ if (rslt_type == NULL)
+ n->type = alloc_typ(n_intrtyp);
+ else
+ n->type = rslt_type;
+ n->symtyps = symtyps(1);
+ can_fail = resume;
+ if (optab[Val0(Tree0(n))].tok.t_type == AUGQMARK) {
+ asgn_impl = optab[asgn_loc].binary;
+ if (resume && asgn_impl->ret_flag & DoesSusp)
+ n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
+ if (MightFail(asgn_impl->ret_flag))
+ can_fail = 1;
+ n->symtyps->next = symtyps(n_arg_sym(asgn_impl));
+ }
+ can_fail = findloops(Tree2(n), can_fail, NULL); /* body */
+ can_fail = findloops(Tree1(n), can_fail, NULL); /* subject */
+ }
+ break;
+
+ case N_Sect:
+ if (rslt_type == NULL)
+ n->type = alloc_typ(n_intrtyp);
+ else
+ n->type = rslt_type;
+ can_fail = resume;
+ /*
+ * Impl0(n) is sectioning.
+ */
+ if (resume && Impl0(n)->ret_flag & DoesSusp)
+ n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
+ if (MightFail(Impl0(n)->ret_flag))
+ can_fail = 1;
+ n->symtyps = symtyps(n_arg_sym(Impl0(n)));
+ if (Impl1(n) != NULL) {
+ /*
+ * Impl1(n) is plus or minus
+ */
+ if (can_fail && Impl1(n)->ret_flag & DoesSusp && n->store == NULL)
+ n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
+ if (MightFail(Impl1(n)->ret_flag))
+ can_fail = 1;
+ n->symtyps->next = symtyps(n_arg_sym(Impl1(n)));
+ }
+ can_fail = findloops(Tree4(n), can_fail, NULL); /* operand 3 */
+ can_fail = findloops(Tree3(n), can_fail, NULL); /* operand 2 */
+ can_fail = findloops(Tree2(n), can_fail, NULL); /* operand 1 */
+ break;
+
+ case N_Slist:
+ /*
+ * 1st expression is bounded.
+ */
+ findloops(Tree0(n), 0, NULL);
+ can_fail = findloops(Tree1(n), resume, rslt_type);
+ n->type = Tree1(n)->type;
+ break;
+
+ case N_SmplAsgn:
+ can_fail = findloops(Tree3(n), resume, NULL); /* 2nd operand */
+ findloops(Tree2(n), can_fail, rslt_type); /* variable */
+ n->type = Tree2(n)->type;
+ break;
+
+ case N_SmplAug:
+ can_fail = resume;
+ /*
+ * Impl1(n) is the augmented operation.
+ */
+ if (resume && Impl1(n)->ret_flag & DoesSusp)
+ n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
+ if (MightFail(Impl1(n)->ret_flag))
+ can_fail = 1;
+ can_fail = findloops(Tree3(n), can_fail, NULL); /* 2nd operand */
+ findloops(Tree2(n), can_fail, rslt_type); /* variable */
+ n->symtyps = symtyps(n_arg_sym(Impl1(n)));
+ n->type = Tree2(n)->type;
+ Typ4(n) = alloc_typ(n_intrtyp);
+ break;
+
+ case N_Str:
+ if (rslt_type == NULL)
+ n->type = alloc_typ(n_intrtyp);
+ else
+ n->type = rslt_type;
+ set_typ(n->type, str_bit); /* precompute type */
+ can_fail = resume;
+ break;
+
+ default:
+ fprintf(stderr, "compiler error: node type %d unknown\n", n->n_type);
+ exit(EXIT_FAILURE);
+ }
+ if (can_fail)
+ n->flag = CanFail;
+ else
+ n->flag = 0;
+ return can_fail;
+ }
+
+/*
+ * symtyps - determine the number of entries needed for a symbol table
+ * that maps argument indexes to types for an operation in the
+ * data base. Allocate the symbol table.
+ */
+static struct symtyps *symtyps(nsyms)
+int nsyms;
+ {
+ struct symtyps *tab;
+
+ if (nsyms == 0)
+ return NULL;
+
+#ifdef OptimizeType
+ tab = (struct symtyps *)alloc((unsigned int)(sizeof(struct symtyps) +
+ (nsyms - 1) * sizeof(struct typinfo *)));
+#else /* OptimizeType */
+ tab = (struct symtyps *)alloc((unsigned int)(sizeof(struct symtyps) +
+ (nsyms - 1) * sizeof(int *)));
+#endif /* OptimizeType */
+ tab->nsyms = nsyms;
+ tab->next = NULL;
+ while (nsyms)
+ tab->types[--nsyms] = alloc_typ(n_intrtyp);
+ return tab;
+ }
+
+/*
+ * infer_proc - perform type inference on a call to an Icon procedure.
+ */
+static void infer_prc(proc, n)
+struct pentry *proc;
+nodeptr n;
+ {
+ struct store *s_store;
+ struct store *f_store;
+ struct store *store;
+ struct pentry *sv_proc;
+ struct t_coexpr *sv_coexp;
+ struct lentry *lptr;
+ nodeptr n1;
+ int i;
+ int nparams;
+ int coexp_bit;
+
+ /*
+ * Determine what co-expressions the procedure might be called from.
+ */
+ if (cur_coexp == NULL)
+ ChkMrgTyp(n_icntyp, cur_proc->coexprs, proc->coexprs)
+ else {
+ coexp_bit = type_array[coexp_typ].frst_bit + cur_coexp->typ_indx;
+ if (!bitset(proc->coexprs, coexp_bit)) {
+ ++changed;
+ set_typ(proc->coexprs, coexp_bit);
+ }
+ }
+
+ proc->reachable = 1; /* this procedure can be called */
+
+ /*
+ * If this procedure can suspend, there may be backtracking paths
+ * to this invocation. If so, propagate types of globals from the
+ * backtracking paths to the suspends of the procedure and propagate
+ * types of locals to the success store of the call.
+ */
+ if (proc->ret_flag & DoesSusp && n->store != NULL) {
+ for (i = 0; i < n_gbl; ++i)
+ ChkMrgTyp(n_icntyp, n->store->types[i], proc->susp_store->types[i])
+ for (i = 0; i < n_loc; ++i)
+ MrgTyp(n_icntyp, n->store->types[n_gbl + i], succ_store->types[n_gbl +
+ i])
+ }
+
+ /*
+ * Merge the types of global variables into the "in store" of the
+ * procedure. Because the body of the procedure may already have
+ * been processed for this pass, the "changed" flag must be set if
+ * there is a change of type in the store. This will insure that
+ * there will be another iteration in which to propagate the change
+ * into the body.
+ */
+ store = proc->in_store;
+ for (i = 0; i < n_gbl; ++i)
+ ChkMrgTyp(n_icntyp, succ_store->types[i], store->types[i])
+
+#ifdef TypTrc
+ /*
+ * Trace the call.
+ */
+ if (trcfile != NULL)
+ fprintf(trcfile, "%s (%d,%d) %s%s(", n->n_file, n->n_line, n->n_col,
+ trc_indent, proc->name);
+#endif /* TypTrc */
+
+ /*
+ * Get the types of the arguments, starting with the non-varargs part.
+ */
+ nparams = proc->nargs; /* number of parameters */
+ if (nparams < 0)
+ nparams = -nparams - 1;
+ for (i = 0; i < num_args && i < nparams; ++i) {
+ typ_deref(arg_typs->types[i], store->types[n_gbl + i], 1);
+
+#ifdef TypTrc
+ if (trcfile != NULL) {
+ /*
+ * Trace the argument type to the call.
+ */
+ if (i > 0)
+ fprintf(trcfile, ", ");
+ prt_d_typ(trcfile, arg_typs->types[i]);
+ }
+#endif /* TypTrc */
+
+ }
+
+ /*
+ * Get the type of the varargs part of the argument list.
+ */
+ if (proc->nargs < 0)
+ while (i < num_args) {
+ typ_deref(arg_typs->types[i],
+ compnt_array[lst_elem].store->types[proc->arg_lst], 1);
+
+#ifdef TypTrc
+ if (trcfile != NULL) {
+ /*
+ * Trace the argument type to the call.
+ */
+ if (i > 0)
+ fprintf(trcfile, ", ");
+ prt_d_typ(trcfile, arg_typs->types[i]);
+ }
+#endif /* TypTrc */
+
+ ++i;
+ }
+
+ /*
+ * Missing arguments have the null type.
+ */
+ while (i < nparams) {
+ set_typ(store->types[n_gbl + i], null_bit);
+ ++i;
+ }
+
+#ifdef TypTrc
+ if (trcfile != NULL)
+ fprintf(trcfile, ")\n");
+ {
+ char *trc_ind_sav = trc_indent;
+ trc_indent = ""; /* staring a new procedure, don't indent tracing */
+#endif /* TypTrc */
+
+ /*
+ * only perform type inference on the body of a procedure
+ * once per iteration
+ */
+ if (proc->iteration < iteration) {
+ proc->iteration = iteration;
+ s_store = succ_store;
+ f_store = fail_store;
+ sv_proc = cur_proc;
+ succ_store = cpy_store(proc->in_store);
+ cur_proc = proc;
+ sv_coexp = cur_coexp;
+ cur_coexp = NULL; /* we are not in a create expression */
+ /*
+ * Perform type inference on the initial clause. Static variables
+ * are initialized to null on this path.
+ */
+ for (lptr = proc->statics; lptr != NULL; lptr = lptr->next)
+ set_typ(succ_store->types[lptr->val.index], null_bit);
+ n1 = Tree1(proc->tree);
+ if (n1->flag & CanFail) {
+ /*
+ * The initial clause can fail. Because it is bounded, we need
+ * a new failure store that we can merge into the success store
+ * at the end of the clause.
+ */
+ store = get_store(1);
+ fail_store = store;
+ infer_nd(n1);
+ mrg_store(store, succ_store);
+ free_store(store);
+ }
+ else
+ infer_nd(n1);
+ /*
+ * Perform type inference on the body of procedure. Execution may
+ * pass directly to it without executing initial clause.
+ */
+ mrg_store(proc->in_store, succ_store);
+ n1 = Tree2(proc->tree);
+ if (n1->flag & CanFail) {
+ /*
+ * The body can fail. Because it is bounded, we need a new failure
+ * store that we can merge into the success store at the end of
+ * the procedure.
+ */
+ store = get_store(1);
+ fail_store = store;
+ infer_nd(n1);
+ mrg_store(store, succ_store);
+ free_store(store);
+ }
+ else
+ infer_nd(n1);
+ set_ret(NULL); /* implicit fail */
+ free_store(succ_store);
+ succ_store = s_store;
+ fail_store = f_store;
+ cur_proc = sv_proc;
+ cur_coexp = sv_coexp;
+ }
+
+#ifdef TypTrc
+ trc_indent = trc_ind_sav;
+ }
+#endif /* TypTrc */
+
+ /*
+ * Get updated types for global variables at the end of the call.
+ */
+ store = proc->out_store;
+ for (i = 0; i < n_gbl; ++i)
+ CpyTyp(n_icntyp, store->types[i], succ_store->types[i]);
+
+ /*
+ * If the procedure can fail, merge variable types into the failure
+ * store.
+ */
+ if (proc->ret_flag & DoesFail)
+ mrg_store(succ_store, fail_store);
+
+ /*
+ * The return type of the procedure is the result type of the call.
+ */
+ MrgTyp(n_intrtyp, proc->ret_typ, n->type);
+ }
+
+/*
+ * cpy_store - make a copy of a store.
+ */
+static struct store *cpy_store(source)
+struct store *source;
+ {
+ struct store *dest;
+ int stor_sz;
+ int i;
+
+ if (source == NULL)
+ dest = get_store(1);
+ else {
+ stor_sz = n_gbl + n_loc;
+ dest = get_store(0);
+ for (i = 0; i < stor_sz; ++i)
+ CpyTyp(n_icntyp, source->types[i], dest->types[i])
+ }
+ return dest;
+ }
+
+/*
+ * mrg_store - merge the source store into the destination store.
+ */
+static void mrg_store(source, dest)
+struct store *source;
+struct store *dest;
+ {
+ int i;
+
+ if (source == NULL)
+ return;
+
+ /*
+ * Is this store included in the state that must be checked for a fixed
+ * point?
+ */
+ if (dest->perm) {
+ for (i = 0; i < n_gbl + n_loc; ++i)
+ ChkMrgTyp(n_icntyp, source->types[i], dest->types[i])
+ }
+ else {
+ for (i = 0; i < n_gbl + n_loc; ++i)
+ MrgTyp(n_icntyp, source->types[i], dest->types[i])
+ }
+ }
+
+/*
+ * set_ret - Save return type and the store for global variables.
+ */
+static void set_ret(typ)
+#ifdef OptimizeType
+struct typinfo *typ;
+#else /* OptimizeType */
+unsigned int *typ;
+#endif /* OptimizeType */
+ {
+ int i;
+
+ /*
+ * Merge the return type into the type of the procedure, dereferencing
+ * locals in the process.
+ */
+ if (typ != NULL)
+ deref_lcl(typ, cur_proc->ret_typ);
+
+ /*
+ * Update the types that variables may have upon exit of the procedure.
+ */
+ for (i = 0; i < n_gbl; ++i)
+ MrgTyp(n_icntyp, succ_store->types[i], cur_proc->out_store->types[i]);
+ }
+
+/*
+ * deref_lcl - dereference local variable sub-types.
+ */
+static void deref_lcl(src, dest)
+#ifdef OptimizeType
+struct typinfo *src;
+struct typinfo *dest;
+#else /* OptimizeType */
+unsigned int *src;
+unsigned int *dest;
+#endif /* OptimizeType */
+ {
+ int i, j;
+ int ref_gbl;
+ int frst_stv;
+ int num_stv;
+ struct store *stv_stor;
+ struct type *wktyp;
+
+ /*
+ * Make a copy of the type to be dereferenced.
+ */
+ wktyp = get_wktyp();
+ CpyTyp(n_intrtyp, src, wktyp->bits);
+
+ /*
+ * Determine which variable types must be dereferenced. Merge the
+ * dereferenced type into the return type and delete the variable
+ * type. Start with simple local variables.
+ */
+ for (i = 0; i < n_loc; ++i)
+ if (bitset(wktyp->bits, frst_loc + i)) {
+ MrgTyp(n_icntyp, succ_store->types[n_gbl + i], wktyp->bits)
+ clr_typ(wktyp->bits, frst_loc + i);
+ }
+
+ /*
+ * Check for substring trapped variables. If a sub-string trapped
+ * variable references a local, add "string" to the return type.
+ * If a sub-string trapped variable references a global, leave the
+ * trapped variable in the return type.
+ * It is theoretically possible for a sub-string trapped variable type to
+ * reference both a local and a global. When the trapped variable type
+ * is returned to the calling procedure, the local is re-interpreted
+ * as a local of that procedure. This is a "valid" overestimate of
+ * of the semantics of the return. Because this is unlikely to occur
+ * in real programs, the overestimate is of no practical consequence.
+ */
+ num_stv = type_array[stv_typ].num_bits;
+ frst_stv = type_array[stv_typ].frst_bit;
+ stv_stor = compnt_array[str_var].store;
+ for (i = 0; i < num_stv; ++i) {
+ if (bitset(wktyp->bits, frst_stv + i)) {
+ /*
+ * We have found substring trapped variable i, see whether it
+ * references locals or globals. Globals include structure
+ * element references.
+ */
+ for (j = 0; j < n_loc; ++j)
+ if (bitset(stv_stor->types[i], frst_loc + j)) {
+ set_typ(wktyp->bits, str_bit);
+ break;
+ }
+ ref_gbl = 0;
+ for (j = n_icntyp; j < frst_loc; ++j)
+ if (bitset(stv_stor->types[i], j)) {
+ ref_gbl = 1;
+ break;
+ }
+ /*
+ * Keep the trapped variable only if it references globals.
+ */
+ if (!ref_gbl)
+ clr_typ(wktyp->bits, frst_stv + i);
+ }
+ }
+
+ /*
+ * Merge the types into the destination.
+ */
+ MrgTyp(n_intrtyp, wktyp->bits, dest);
+
+#ifdef TypTrc
+ if (trcfile != NULL) {
+ prt_typ(trcfile, wktyp->bits);
+ fprintf(trcfile, "\n");
+ }
+#endif /* TypTrc */
+
+ free_wktyp(wktyp);
+ }
+
+/*
+ * get_store - get a store large enough to hold globals and locals.
+ */
+static struct store *get_store(clear)
+int clear;
+ {
+ struct store *store;
+ int store_sz;
+ int i;
+
+ /*
+ * Warning, stores for all procedures must be the same size. In some
+ * situations involving sub-string trapped variables (for example
+ * when using the "default" trapped variable) a referenced local variable
+ * type may be interpreted in a procedure to which it does not belong.
+ * This represents an impossible execution and type inference may
+ * "legally" produce any results for this part of the abstract
+ * interpretation. As long as the store is large enough to include any
+ * such "impossible" variables, type inference will do something legal.
+ * Note that n_loc is the maximum number of locals in any procedure,
+ * so store_sz is large enough.
+ */
+ store_sz = n_gbl + n_loc;
+ if ((store = store_pool) == NULL) {
+ store = alloc_stor(store_sz, n_icntyp);
+ store->perm = 0;
+ }
+ else {
+ store_pool = store_pool->next;
+ /*
+ * See if the variables in the store should be initialized to the
+ * empty type.
+ */
+ if (clear)
+ for (i = 0; i < store_sz; ++i)
+ ClrTyp(n_icntyp, store->types[i]);
+ }
+ return store;
+ }
+
+static void free_store(store)
+struct store *store;
+ {
+ store->next = store_pool;
+ store_pool = store;
+ }
+
+/*
+ * infer_nd - perform type inference on a subtree of the syntax tree.
+ */
+static void infer_nd(n)
+nodeptr n;
+ {
+ struct node *cases;
+ struct node *clause;
+ struct store *s_store;
+ struct store *f_store;
+ struct store *store;
+ struct loop {
+ struct store *succ_store;
+ struct store *fail_store;
+ struct store *next_store;
+ struct store *susp_store;
+ struct loop *prev;
+ } loop_info;
+ struct loop *loop_sav;
+ static struct loop *cur_loop;
+ struct argtyps *sav_argtyp;
+ int sav_nargs;
+ struct type *wktyp;
+ int i;
+
+ switch (n->n_type) {
+ case N_Activat:
+ infer_act(n);
+ break;
+
+ case N_Alt:
+ f_store = fail_store;
+ store = get_store(1);
+ fail_store = store;
+ infer_nd(Tree0(n)); /* 1st alternative */
+
+ /*
+ * "Correct" type inferencing of alternation has a performance
+ * problem. Propagating stores through nested alternation
+ * requires as many iterations as the depth of the nesting.
+ * This is solved by adding two edges to the flow graph. These
+ * represent impossible execution paths but this does not
+ * affect the soundness of type inferencing and, in "real"
+ * programs, does not affect the preciseness of its inference.
+ * One edge is directly from the 1st alternative to the 2nd.
+ * The other is a backtracking edge immediately back into
+ * the alternation from the 1st alternative.
+ */
+ mrg_store(succ_store, store); /* imaginary edge to 2nd alternative */
+
+ if (n->store != NULL) {
+ mrg_store(succ_store, n->store); /* imaginary backtracking edge */
+ mrg_store(n->store, fail_store);
+ }
+ s_store = succ_store;
+ succ_store = store;
+ fail_store = f_store;
+ infer_nd(Tree1(n)); /* 2nd alternative */
+ mrg_store(s_store, succ_store);
+ free_store(s_store);
+ if (n->store != NULL)
+ mrg_store(n->store, fail_store);
+ fail_store = n->store;
+#ifdef TypTrc
+ MrgTyp(n_intrtyp, Tree0(n)->type, n->type);
+ MrgTyp(n_intrtyp, Tree1(n)->type, n->type);
+#else /* TypTrc */
+ /*
+ * Type is computed by sub-expressions directly into n->type.
+ */
+#endif /* TypTrc */
+ break;
+
+ case N_Apply: {
+ struct type *lst_types;
+ int frst_lst;
+ int num_lst;
+ struct store *lstel_stor;
+
+ infer_nd(Tree0(n)); /* thing being invoked */
+ infer_nd(Tree1(n)); /* list */
+
+ frst_lst = type_array[list_typ].frst_bit;
+ num_lst = type_array[list_typ].num_bits;
+ lstel_stor = compnt_array[lst_elem].store;
+
+ /*
+ * All that is available is a "summary" of the types of the
+ * elements of the list. Each argument to the invocation
+ * could be any type in the summary. Set up a maximum length
+ * argument list.
+ */
+ lst_types = get_wktyp();
+ typ_deref(Tree1(n)->type, lst_types->bits, 0);
+ wktyp = get_wktyp();
+ for (i = 0; i < num_lst; ++i)
+ if (bitset(lst_types->bits, frst_lst + i))
+ MrgTyp(n_icntyp, lstel_stor->types[i], wktyp->bits);
+ bitset(wktyp->bits, null_bit); /* arg list extension might be done */
+
+ sav_nargs = num_args;
+ sav_argtyp = arg_typs;
+ num_args = max_prm;
+ arg_typs = get_argtyp();
+ for (i = 0; i < max_prm; ++i)
+ arg_typs->types[i] = wktyp->bits;
+ gen_inv(Tree0(n)->type, n); /* inference on general invocation */
+
+ free_wktyp(wktyp);
+ free_wktyp(lst_types);
+ free_argtyp(arg_typs);
+ arg_typs = sav_argtyp;
+ num_args = sav_nargs;
+ }
+ break;
+
+ case N_Augop:
+ infer_nd(Tree2(n)); /* 1st operand */
+ infer_nd(Tree3(n)); /* 2nd operand */
+ /*
+ * Perform type inference on the operation.
+ */
+ sav_argtyp = arg_typs;
+ sav_nargs = num_args;
+ arg_typs = get_argtyp();
+ num_args = 2;
+ arg_typs->types[0] = Tree2(n)->type;
+ arg_typs->types[1] = Tree3(n)->type;
+ infer_impl(Impl1(n), n, n->symtyps, Typ4(n));
+ chk_succ(Impl1(n)->ret_flag, n->store);
+ /*
+ * Perform type inference on the assignment.
+ */
+ arg_typs->types[1] = Typ4(n);
+ infer_impl(Impl0(n), n, n->symtyps->next, n->type);
+ chk_succ(Impl0(n)->ret_flag, n->store);
+
+ free_argtyp(arg_typs);
+ arg_typs = sav_argtyp;
+ num_args = sav_nargs;
+ break;
+
+ case N_Bar:
+ /*
+ * This operation intercepts failure and has an associated
+ * resumption store. If backtracking reaches this operation
+ * execution may either continue backward or proceed forward
+ * again.
+ */
+ mrg_store(n->store, fail_store);
+ mrg_store(n->store, succ_store);
+ fail_store = n->store;
+ infer_nd(Tree0(n));
+ /*
+ * Type is computed by operand.
+ */
+ break;
+
+ case N_Break:
+ /*
+ * The success and failure stores for the operand of break are
+ * those associated with the enclosing loop.
+ */
+ fail_store = cur_loop->fail_store;
+ loop_sav = cur_loop;
+ cur_loop = cur_loop->prev;
+ infer_nd(Tree0(n));
+ cur_loop = loop_sav;
+ mrg_store(succ_store, cur_loop->succ_store);
+ if (cur_loop->susp_store != NULL)
+ mrg_store(cur_loop->susp_store, fail_store);
+ free_store(succ_store);
+ succ_store = get_store(1); /* empty store says: can't get past here */
+ fail_store = dummy_stor; /* shouldn't be used */
+ /*
+ * Result of break is empty type. Result type of expression
+ * is computed directly into result type of loop.
+ */
+ break;
+
+ case N_Case:
+ f_store = fail_store;
+ s_store = get_store(1);
+ infer_nd(Tree0(n)); /* control clause */
+ cases = Tree1(n);
+ while (cases != NULL) {
+ if (cases->n_type == N_Ccls) {
+ clause = cases;
+ cases = NULL;
+ }
+ else {
+ clause = Tree1(cases);
+ cases = Tree0(cases);
+ }
+
+ /*
+ * Set up a failure store to capture the effects of failure
+ * of the selection clause.
+ */
+ store = get_store(1);
+ fail_store = store;
+ infer_nd(Tree0(clause)); /* value of clause */
+
+ /*
+ * Create the effect of the possible failure of the comparison
+ * of the selection value to the control value.
+ */
+ mrg_store(succ_store, fail_store);
+
+ /*
+ * The success and failure stores and the result of the body
+ * of the clause are those of the whole case expression.
+ */
+ fail_store = f_store;
+ infer_nd(Tree1(clause)); /* body of clause */
+ mrg_store(succ_store, s_store);
+ free_store(succ_store);
+ succ_store = store;
+ if (n->store != NULL)
+ mrg_store(n->store, fail_store); /* 'case' can be resumed */
+#ifdef TypTrc
+ MrgTyp(n_intrtyp, Tree1(clause)->type, n->type);
+#else /* TypTrc */
+ /*
+ * Type is computed by case clause directly into n->type.
+ */
+#endif /* TypTrc */
+ }
+
+ /*
+ * Check for default clause.
+ */
+ if (Tree2(n) == NULL)
+ mrg_store(succ_store, f_store);
+ else {
+ fail_store = f_store;
+ infer_nd(Tree2(n)); /* default */
+ mrg_store(succ_store, s_store);
+ if (n->store != NULL)
+ mrg_store(n->store, fail_store); /* 'case' can be resumed */
+#ifdef TypTrc
+ MrgTyp(n_intrtyp, Tree2(n)->type, n->type);
+#else /* TypTrc */
+ /*
+ * Type is computed by default clause directly into n->type.
+ */
+#endif /* TypTrc */
+ }
+ free_store(succ_store);
+ succ_store = s_store;
+ if (n->store != NULL)
+ fail_store = n->store;
+ break;
+
+ case N_Create:
+ /*
+ * Record initial values of local variables for coexpression.
+ */
+ store = coexp_map[n->new_types[0]]->in_store;
+ for (i = 0; i < n_loc; ++i)
+ ChkMrgTyp(n_icntyp, succ_store->types[n_gbl + i],
+ store->types[n_gbl + i])
+ /*
+ * Type is precomputed.
+ */
+ break;
+
+ case N_Cset:
+ case N_Empty:
+ case N_Id:
+ case N_Int:
+ case N_Real:
+ case N_Str:
+ /*
+ * Type is precomputed.
+ */
+ break;
+
+ case N_Field: {
+ struct fentry *fp;
+ struct par_rec *rp;
+ int frst_rec;
+
+ if ((fp = flookup(Str0(Tree1(n)))) == NULL) {
+ break; /* error message printed elsewhere */
+ }
+
+ /*
+ * Determine the record types.
+ */
+ infer_nd(Tree0(n));
+ typ_deref(Tree0(n)->type, n->symtyps->types[0], 0);
+
+ /*
+ * For each record containing this field, get the tupe of
+ * the field in that record.
+ */
+ frst_rec = type_array[rec_typ].frst_bit;
+ for (rp = fp->rlist; rp != NULL; rp = rp->next) {
+ if (bitset(n->symtyps->types[0], frst_rec + rp->rec->rec_num))
+ set_typ(n->type, frst_fld + rp->rec->frst_fld + rp->offset);
+ }
+ }
+ break;
+
+ case N_If:
+ f_store = fail_store;
+ if (Tree2(n)->n_type != N_Empty) {
+ /*
+ * If there is an else clause, we must set up a failure store
+ * to capture the effects of failure of the control clause.
+ */
+ store = get_store(1);
+ fail_store = store;
+ }
+
+ infer_nd(Tree0(n)); /* control clause */
+
+ /*
+ * If the control clause succeeds, execution passes into the
+ * then clause with the failure store for the entire if expression.
+ */
+ fail_store = f_store;
+ infer_nd(Tree1(n)); /* then clause */
+
+ if (Tree2(n)->n_type != N_Empty) {
+ if (n->store != NULL)
+ mrg_store(n->store, fail_store); /* 'if' expr can be resumed */
+ s_store = succ_store;
+
+ /*
+ * The entering success store of the else clause is the failure
+ * store of the control clause. The failure store is that of
+ * the entire if expression.
+ */
+ succ_store = store;
+ fail_store = f_store;
+ infer_nd(Tree2(n)); /* else clause */
+
+ if (n->store != NULL) {
+ mrg_store(n->store, fail_store); /* 'if' expr can be resumed */
+ fail_store = n->store;
+ }
+
+ /*
+ * Join the exiting success stores of the then and else clauses.
+ */
+ mrg_store(s_store, succ_store);
+ free_store(s_store);
+ }
+
+#ifdef TypTrc
+ MrgTyp(n_intrtyp, Tree1(n)->type, n->type);
+ if (Tree2(n)->n_type != N_Empty)
+ MrgTyp(n_intrtyp, Tree2(n)->type, n->type);
+#else /* TypTrc */
+ /*
+ * Type computed by 'then' and 'else' clauses directly into n->type.
+ */
+#endif /* TypTrc */
+ break;
+
+ case N_Invok:
+ /*
+ * General invocation.
+ */
+ infer_nd(Tree1(n)); /* thing being invoked */
+
+ /*
+ * Perform type inference on all the arguments and copy the
+ * results into the argument type array.
+ */
+ sav_argtyp = arg_typs;
+ sav_nargs = num_args;
+ arg_typs = get_argtyp();
+ num_args = Val0(n); /* number of arguments */
+ for (i = 0; i < num_args; ++i) {
+ infer_nd(n->n_field[i+2].n_ptr); /* arg i */
+ arg_typs->types[i] = n->n_field[i+2].n_ptr->type;
+ }
+
+ /*
+ * If this is mutual evaluation, get the type of the last argument,
+ * otherwise do inference on general invocation.
+ */
+ if (Tree1(n)->n_type == N_Empty) {
+ MrgTyp(n_intrtyp, arg_typs->types[num_args - 1], n->type);
+ }
+ else
+ gen_inv(Tree1(n)->type, n);
+
+ free_argtyp(arg_typs);
+ arg_typs = sav_argtyp;
+ num_args = sav_nargs;
+ break;
+
+ case N_InvOp:
+ /*
+ * Invocation of a run-time operation. Perform inference on all
+ * the arguments, copying the results into the argument type
+ * array.
+ */
+ sav_argtyp = arg_typs;
+ sav_nargs = num_args;
+ arg_typs = get_argtyp();
+ num_args = Val0(n); /* number of arguments */
+ for (i = 0; i < num_args; ++i) {
+ infer_nd(n->n_field[i+2].n_ptr); /* arg i */
+ arg_typs->types[i] = n->n_field[i+2].n_ptr->type;
+ }
+
+ /*
+ * Perform inference on operation invocation.
+ */
+ infer_impl(Impl1(n), n, n->symtyps, n->type);
+ chk_succ(Impl1(n)->ret_flag, n->store);
+
+ free_argtyp(arg_typs);
+ arg_typs = sav_argtyp;
+ num_args = sav_nargs;
+ break;
+
+ case N_InvProc:
+ /*
+ * Invocation of a procedure. Perform inference on all
+ * the arguments, copying the results into the argument type
+ * array.
+ */
+ sav_argtyp = arg_typs;
+ sav_nargs = num_args;
+ arg_typs = get_argtyp();
+ num_args = Val0(n); /* number of arguments */
+ for (i = 0; i < num_args; ++i) {
+ infer_nd(n->n_field[i+2].n_ptr); /* arg i */
+ arg_typs->types[i] = n->n_field[i+2].n_ptr->type;
+ }
+
+ /*
+ * Perform inference on the procedure invocation.
+ */
+ infer_prc(Proc1(n), n);
+ chk_succ(Proc1(n)->ret_flag, n->store);
+
+ free_argtyp(arg_typs);
+ arg_typs = sav_argtyp;
+ num_args = sav_nargs;
+ break;
+
+ case N_InvRec:
+ /*
+ * Invocation of a record constructor. Perform inference on all
+ * the arguments, copying the results into the argument type
+ * array.
+ */
+ sav_argtyp = arg_typs;
+ sav_nargs = num_args;
+ arg_typs = get_argtyp();
+ num_args = Val0(n); /* number of arguments */
+ for (i = 0; i < num_args; ++i) {
+ infer_nd(n->n_field[i+2].n_ptr); /* arg i */
+ arg_typs->types[i] = n->n_field[i+2].n_ptr->type;
+ }
+
+ infer_con(Rec1(n), n); /* inference on constructor invocation */
+
+ free_argtyp(arg_typs);
+ arg_typs = sav_argtyp;
+ num_args = sav_nargs;
+ break;
+
+ case N_Limit:
+ infer_nd(Tree1(n)); /* limit */
+ typ_deref(Tree1(n)->type, n->symtyps->types[0], 0);
+ mrg_store(succ_store, fail_store); /* limit might be 0 */
+ mrg_store(n->store, fail_store); /* resumption may bypass expr */
+ infer_nd(Tree0(n)); /* expression */
+ if (fail_store != NULL)
+ mrg_store(n->store, fail_store); /* expression may be resumed */
+ fail_store = n->store;
+ /*
+ * Type is computed by expression being limited.
+ */
+ break;
+
+ case N_Loop: {
+ /*
+ * Establish stores used by break and next.
+ */
+ loop_info.prev = cur_loop;
+ loop_info.succ_store = get_store(1);
+ loop_info.fail_store = fail_store;
+ loop_info.next_store = NULL;
+ loop_info.susp_store = n->store->next;
+ cur_loop = &loop_info;
+
+ switch ((int)Val0(Tree0(n))) {
+ case EVERY:
+ infer_nd(Tree1(n)); /* control clause */
+ f_store = fail_store;
+
+ /*
+ * Next in the do clause resumes the control clause as
+ * does success of the do clause.
+ */
+ loop_info.next_store = fail_store;
+ infer_nd(Tree2(n)); /* do clause */
+ mrg_store(succ_store, f_store);
+ break;
+
+ case REPEAT:
+ /*
+ * The body of the loop can be entered by entering the
+ * loop, by executing a next in the body, or by having
+ * the loop succeed or fail. n->store captures all but
+ * the first case, which is covered by the initial success
+ * store.
+ */
+ fail_store = n->store;
+ mrg_store(n->store, succ_store);
+ loop_info.next_store = n->store;
+ infer_nd(Tree1(n));
+ mrg_store(succ_store, n->store);
+ break;
+
+ case SUSPEND:
+ infer_nd(Tree1(n)); /* value */
+#ifdef TypTrc
+ if (trcfile != NULL)
+ fprintf(trcfile, "%s (%d,%d) suspend ", n->n_file, n->n_line,
+ n->n_col);
+#endif /* TypTrc */
+
+ set_ret(Tree1(n)->type); /* set return type of procedure */
+
+ /*
+ * Get changes to types of global variables from
+ * resumption.
+ */
+ store = cur_proc->susp_store;
+ for (i = 0; i < n_gbl; ++i)
+ CpyTyp(n_icntyp, store->types[i], succ_store->types[i]);
+
+ /*
+ * Next in the do clause resumes the control clause as
+ * does success of the do clause.
+ */
+ f_store = fail_store;
+ loop_info.next_store = fail_store;
+ infer_nd(Tree2(n)); /* do clause */
+ mrg_store(succ_store, f_store);
+ break;
+
+ case WHILE:
+ /*
+ * The control clause can be entered by entering the loop,
+ * executing a next expression, or by having the do clause
+ * succeed or fail. n->store captures all but the first case,
+ * which is covered by the initial success store.
+ */
+ mrg_store(n->store, succ_store);
+ loop_info.next_store = n->store;
+ infer_nd(Tree1(n)); /* control clause */
+ fail_store = n->store;
+ infer_nd(Tree2(n)); /* do clause */
+ mrg_store(succ_store, n->store);
+ break;
+
+ case UNTIL:
+ /*
+ * The control clause can be entered by entering the loop,
+ * executing a next expression, or by having the do clause
+ * succeed or fail. n->store captures all but the first case,
+ * which is covered by the initial success store.
+ */
+ mrg_store(n->store, succ_store);
+ loop_info.next_store = n->store;
+ f_store = fail_store;
+ /*
+ * Set up a failure store to capture the effects of failure
+ * of the control clause.
+ */
+ store = get_store(1);
+ fail_store = store;
+ infer_nd(Tree1(n)); /* control clause */
+ mrg_store(succ_store, f_store);
+ free_store(succ_store);
+ succ_store = store;
+ fail_store = n->store;
+ infer_nd(Tree2(n)); /* do clause */
+ mrg_store(succ_store, n->store);
+ break;
+ }
+ free_store(succ_store);
+ succ_store = loop_info.succ_store;
+ if (n->store->next != NULL)
+ fail_store = n->store->next;
+ cur_loop = cur_loop->prev;
+ /*
+ * Type is computed by break expressions.
+ */
+ }
+ break;
+
+ case N_Next:
+ if (cur_loop->next_store == NULL)
+ mrg_store(succ_store, fail_store); /* control clause of every */
+ else
+ mrg_store(succ_store, cur_loop->next_store);
+ free_store(succ_store);
+ succ_store = get_store(1); /* empty store says: can't get past here */
+ fail_store = dummy_stor; /* shouldn't be used */
+ /*
+ * Result is empty type.
+ */
+ break;
+
+ case N_Not:
+ /*
+ * Set up a failure store to capture the effects of failure
+ * of the negated expression, it becomes the success store
+ * of the entire expression.
+ */
+ f_store = fail_store;
+ store = get_store(1);
+ fail_store = store;
+ infer_nd(Tree0(n));
+ mrg_store(succ_store, f_store); /* if success, then fail */
+ free_store(succ_store);
+ succ_store = store;
+ fail_store = f_store;
+ /*
+ * Type is precomputed.
+ */
+ break;
+
+ case N_Ret:
+ if (Val0(Tree0(n)) == RETURN) {
+ if (Tree1(n)->flag & CanFail) {
+ /*
+ * Set up a failure store to capture the effects of failure
+ * of the returned expression and the corresponding procedure
+ * failure.
+ */
+ store = get_store(1);
+ fail_store = store;
+ infer_nd(Tree1(n)); /* return value */
+ mrg_store(store, succ_store);
+ free_store(store);
+ }
+ else
+ infer_nd(Tree1(n)); /* return value */
+
+#ifdef TypTrc
+ if (trcfile != NULL)
+ fprintf(trcfile, "%s (%d,%d) return ", n->n_file, n->n_line,
+ n->n_col);
+#endif /* TypTrc */
+
+ set_ret(Tree1(n)->type);
+ }
+ else { /* fail */
+ set_ret(NULL);
+
+#ifdef TypTrc
+ if (trcfile != NULL)
+ fprintf(trcfile, "%s (%d,%d) fail\n", n->n_file, n->n_line,
+ n->n_col);
+#endif /* TypTrc */
+
+ }
+ free_store(succ_store);
+ succ_store = get_store(1); /* empty store says: can't get past here */
+ fail_store = dummy_stor; /* shouldn't be used */
+ /*
+ * Empty type.
+ */
+ break;
+
+ case N_Scan: {
+ struct implement *asgn_impl;
+
+ infer_nd(Tree1(n)); /* subject */
+ typ_deref(Tree1(n)->type, n->symtyps->types[0], 0);
+ infer_nd(Tree2(n)); /* body */
+
+ if (optab[Val0(Tree0(n))].tok.t_type == AUGQMARK) {
+ /*
+ * Perform type inference on the assignment.
+ */
+ asgn_impl = optab[asgn_loc].binary;
+ sav_argtyp = arg_typs;
+ sav_nargs = num_args;
+ arg_typs = get_argtyp();
+ num_args = 2;
+ arg_typs->types[0] = Tree1(n)->type;
+ arg_typs->types[1] = Tree2(n)->type;
+ infer_impl(asgn_impl, n, n->symtyps->next, n->type);
+ chk_succ(asgn_impl->ret_flag, n->store);
+ free_argtyp(arg_typs);
+ arg_typs = sav_argtyp;
+ num_args = sav_nargs;
+ }
+ else
+ MrgTyp(n_intrtyp, Tree2(n)->type, n->type);
+ }
+ break;
+
+ case N_Sect:
+ infer_nd(Tree2(n)); /* 1st operand */
+ infer_nd(Tree3(n)); /* 2nd operand */
+ infer_nd(Tree4(n)); /* 3rd operand */
+ sav_argtyp = arg_typs;
+ sav_nargs = num_args;
+ arg_typs = get_argtyp();
+ if (Impl1(n) != NULL) {
+ /*
+ * plus or minus.
+ */
+ num_args = 2;
+ arg_typs->types[0] = Tree3(n)->type;
+ arg_typs->types[1] = Tree4(n)->type;
+ wktyp = get_wktyp();
+ infer_impl(Impl1(n), n, n->symtyps->next, wktyp->bits);
+ chk_succ(Impl1(n)->ret_flag, n->store);
+ arg_typs->types[2] = wktyp->bits;
+ }
+ else
+ arg_typs->types[2] = Tree4(n)->type;
+ num_args = 3;
+ arg_typs->types[0] = Tree2(n)->type;
+ arg_typs->types[1] = Tree3(n)->type;
+ /*
+ * sectioning
+ */
+ infer_impl(Impl0(n), n, n->symtyps, n->type);
+ chk_succ(Impl0(n)->ret_flag, n->store);
+ if (Impl1(n) != NULL)
+ free_wktyp(wktyp);
+ free_argtyp(arg_typs);
+ arg_typs = sav_argtyp;
+ num_args = sav_nargs;
+ break;
+
+ case N_Slist:
+ f_store = fail_store;
+ if (Tree0(n)->flag & CanFail) {
+ /*
+ * Set up a failure store to capture the effects of failure
+ * of the first operand; this is merged into the
+ * incoming success store of the second operand.
+ */
+ store = get_store(1);
+ fail_store = store;
+ infer_nd(Tree0(n));
+ mrg_store(store, succ_store);
+ free_store(store);
+ }
+ else
+ infer_nd(Tree0(n));
+ fail_store = f_store;
+ infer_nd(Tree1(n));
+ /*
+ * Type is computed by second operand.
+ */
+ break;
+
+ case N_SmplAsgn: {
+ /*
+ * Optimized assignment to a named variable.
+ */
+ struct lentry *var;
+ int indx;
+
+ infer_nd(Tree3(n));
+ var = LSym0(Tree2(n));
+ if (var->flag & F_Global)
+ indx = var->val.global->index;
+ else if (var->flag & F_Static)
+ indx = var->val.index;
+ else
+ indx = n_gbl + var->val.index;
+ ClrTyp(n_icntyp, succ_store->types[indx]);
+ typ_deref(Tree3(n)->type, succ_store->types[indx], 0);
+
+#ifdef TypTrc
+ /*
+ * Trace assignment.
+ */
+ if (trcfile != NULL) {
+ fprintf(trcfile, "%s (%d,%d) %s%s := ", n->n_file, n->n_line,
+ n->n_col, trc_indent, var->name);
+ prt_d_typ(trcfile, Tree3(n)->type);
+ fprintf(trcfile, "\n");
+ }
+#endif /* TypTrc */
+ /*
+ * Type is precomputed.
+ */
+ }
+ break;
+
+ case N_SmplAug: {
+ /*
+ * Optimized augmented assignment to a named variable.
+ */
+ struct lentry *var;
+ int indx;
+
+ /*
+ * Perform type inference on the operation.
+ */
+ infer_nd(Tree3(n)); /* 2nd operand */
+
+ /*
+ * Set up type array for arguments of operation.
+ */
+ sav_argtyp = arg_typs;
+ sav_nargs = num_args;
+ arg_typs = get_argtyp();
+ num_args = 2;
+ arg_typs->types[0] = Tree2(n)->type; /* type was precomputed */
+ arg_typs->types[1] = Tree3(n)->type;
+
+ /*
+ * Perform inference on the operation.
+ */
+ infer_impl(Impl1(n), n, n->symtyps, Typ4(n));
+ chk_succ(Impl1(n)->ret_flag, n->store);
+
+ /*
+ * Perform assignment to the variable.
+ */
+ var = LSym0(Tree2(n));
+ if (var->flag & F_Global)
+ indx = var->val.global->index;
+ else if (var->flag & F_Static)
+ indx = var->val.index;
+ else
+ indx = n_gbl + var->val.index;
+ ClrTyp(n_icntyp, succ_store->types[indx]);
+ typ_deref(Typ4(n), succ_store->types[indx], 0);
+
+#ifdef TypTrc
+ /*
+ * Trace assignment.
+ */
+ if (trcfile != NULL) {
+ fprintf(trcfile, "%s (%d,%d) %s%s := ", n->n_file, n->n_line,
+ n->n_col, trc_indent, var->name);
+ prt_d_typ(trcfile, Typ4(n));
+ fprintf(trcfile, "\n");
+ }
+#endif /* TypTrc */
+
+ free_argtyp(arg_typs);
+ arg_typs = sav_argtyp;
+ num_args = sav_nargs;
+
+ /*
+ * Type is precomputed.
+ */
+ }
+ break;
+
+ default:
+ fprintf(stderr, "compiler error: node type %d unknown\n", n->n_type);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+/*
+ * infer_con - perform type inference for the invocation of a record
+ * constructor.
+ */
+static void infer_con(rec, n)
+struct rentry *rec;
+nodeptr n;
+ {
+ int fld_indx;
+ int nfields;
+ int i;
+
+#ifdef TypTrc
+ if (trcfile != NULL)
+ fprintf(trcfile, "%s (%d,%d) %s%s(", n->n_file, n->n_line, n->n_col,
+ trc_indent, rec->name);
+#endif /* TypTrc */
+
+ /*
+ * Dereference argument types into appropriate entries of field store.
+ */
+ fld_indx = rec->frst_fld;
+ nfields = rec->nfields;
+ for (i = 0; i < num_args && i < nfields; ++i) {
+ typ_deref(arg_typs->types[i], fld_stor->types[fld_indx++], 1);
+
+#ifdef TypTrc
+ if (trcfile != NULL) {
+ if (i > 0)
+ fprintf(trcfile, ", ");
+ prt_d_typ(trcfile, arg_typs->types[i]);
+ }
+#endif /* TypTrc */
+
+ }
+
+ /*
+ * If there are too few arguments, add null type to appropriate entries
+ * of field store.
+ */
+ while (i < nfields) {
+ if (!bitset(fld_stor->types[fld_indx], null_bit)) {
+ ++changed;
+ set_typ(fld_stor->types[fld_indx], null_bit);
+ }
+ ++fld_indx;
+ ++i;
+ }
+
+ /*
+ * return record type
+ */
+ set_typ(n->type, type_array[rec_typ].frst_bit + rec->rec_num);
+
+#ifdef TypTrc
+ if (trcfile != NULL) {
+ fprintf(trcfile, ") =>> ");
+ prt_typ(trcfile, n->type);
+ fprintf(trcfile, "\n");
+ }
+#endif /* TypTrc */
+ }
+
+/*
+ * infer_act - perform type inference on coexpression activation.
+ */
+static void infer_act(n)
+nodeptr n;
+ {
+ struct implement *asgn_impl;
+ struct store *s_store;
+ struct store *f_store;
+ struct store *e_store;
+ struct store *store;
+ struct t_coexpr *sv_coexp;
+ struct t_coexpr *coexp;
+ struct type *rslt_typ;
+ struct argtyps *sav_argtyp;
+ int frst_coexp;
+ int num_coexp;
+ int sav_nargs;
+ int i;
+ int j;
+
+#ifdef TypTrc
+ FILE *trc_save;
+#endif /* TypTrc */
+
+ num_coexp = type_array[coexp_typ].num_bits;
+ frst_coexp = type_array[coexp_typ].frst_bit;
+
+ infer_nd(Tree1(n)); /* value to transmit */
+ infer_nd(Tree2(n)); /* coexpression */
+
+ /*
+ * Dereference the two arguments. Note that only locals in the
+ * transmitted value are dereferenced.
+ */
+
+#ifdef TypTrc
+ trc_save = trcfile;
+ trcfile = NULL; /* don't trace value during dereferencing */
+#endif /* TypTrc */
+
+ deref_lcl(Tree1(n)->type, n->symtyps->types[0]);
+
+#ifdef TypTrc
+ trcfile = trc_save;
+#endif /* TypTrc */
+
+ typ_deref(Tree2(n)->type, n->symtyps->types[1], 0);
+
+ rslt_typ = get_wktyp();
+
+ /*
+ * Set up a store for the end of the activation and propagate local
+ * variables across the activation; the activation may succeed or
+ * fail.
+ */
+ e_store = get_store(1);
+ for (i = 0; i < n_loc; ++i)
+ CpyTyp(n_icntyp, succ_store->types[n_gbl + i], e_store->types[n_gbl + i])
+ if (fail_store->perm) {
+ for (i = 0; i < n_loc; ++i)
+ ChkMrgTyp(n_icntyp, succ_store->types[n_gbl + i],
+ fail_store->types[n_gbl + i])
+ }
+ else {
+ for (i = 0; i < n_loc; ++i)
+ MrgTyp(n_icntyp, succ_store->types[n_gbl + i],
+ fail_store->types[n_gbl + i])
+ }
+
+
+ /*
+ * Go through all the co-expressions that might be activated,
+ * perform type inference on them, and transmit stores along
+ * the execution paths induced by the activation.
+ */
+ s_store = succ_store;
+ f_store = fail_store;
+ for (j = 0; j < num_coexp; ++j) {
+ if (bitset(n->symtyps->types[1], frst_coexp + j)) {
+ coexp = coexp_map[j];
+ /*
+ * Merge the types of global variables into the "in store" of the
+ * co-expression. Because the body of the co-expression may already
+ * have been processed for this pass, the "changed" flag must be
+ * set if there is a change of type in the store. This will insure
+ * that there will be another iteration in which to propagate the
+ * change into the body.
+ */
+ store = coexp->in_store;
+ for (i = 0; i < n_gbl; ++i)
+ ChkMrgTyp(n_icntyp, s_store->types[i], store->types[i])
+
+ ChkMrgTyp(n_intrtyp, n->symtyps->types[0], coexp->act_typ)
+
+ /*
+ * Only perform type inference on the body of a co-expression
+ * once per iteration. The main co-expression has no body.
+ */
+ if (coexp->iteration < iteration & coexp->n != NULL) {
+ coexp->iteration = iteration;
+ succ_store = cpy_store(coexp->in_store);
+ fail_store = coexp->out_store;
+ sv_coexp = cur_coexp;
+ cur_coexp = coexp;
+ infer_nd(coexp->n);
+
+ /*
+ * Dereference the locals in the value resulting from
+ * the execution of the co-expression body.
+ */
+
+#ifdef TypTrc
+ if (trcfile != NULL)
+ fprintf(trcfile, "%s (%d,%d) %sC%d =>> ", coexp->n->n_file,
+ coexp->n->n_line, coexp->n->n_col, trc_indent, j);
+#endif /* TypTrc */
+
+ deref_lcl(coexp->n->type, coexp->rslt_typ);
+
+ mrg_store(succ_store, coexp->out_store);
+ free_store(succ_store);
+ cur_coexp = sv_coexp;
+ }
+
+ /*
+ * Get updated types for global variables, assuming the co-expression
+ * fails or returns by completing.
+ */
+ store = coexp->out_store;
+ for (i = 0; i < n_gbl; ++i)
+ MrgTyp(n_icntyp, store->types[i], e_store->types[i]);
+ if (f_store->perm) {
+ for (i = 0; i < n_gbl; ++i)
+ ChkMrgTyp(n_icntyp, store->types[i], f_store->types[i]);
+ }
+ else {
+ for (i = 0; i < n_gbl; ++i)
+ MrgTyp(n_icntyp, store->types[i], f_store->types[i]);
+ }
+ MrgTyp(n_intrtyp, coexp->rslt_typ, rslt_typ->bits)
+ }
+ }
+
+ /*
+ * Control may return from the activation if another co-expression
+ * activates the current one. If we are in a create expression,
+ * cur_coexp is the current co-expression, otherwise the current
+ * procedure may be called within several co-expressions.
+ */
+ if (cur_coexp == NULL) {
+ for (j = 0; j < num_coexp; ++j)
+ if (bitset(cur_proc->coexprs, frst_coexp + j))
+ mrg_act(coexp_map[j], e_store, rslt_typ);
+ }
+ else
+ mrg_act(cur_coexp, e_store, rslt_typ);
+
+ free_store(s_store);
+ succ_store = e_store;
+ fail_store = f_store;
+
+
+#ifdef TypTrc
+ if (trcfile != NULL) {
+ fprintf(trcfile, "%s (%d,%d) %s", n->n_file, n->n_line, n->n_col,
+ trc_indent);
+ prt_typ(trcfile, n->symtyps->types[0]);
+ fprintf(trcfile, " @ ");
+ prt_typ(trcfile, n->symtyps->types[1]);
+ fprintf(trcfile, " =>> ");
+ prt_typ(trcfile, rslt_typ->bits);
+ fprintf(trcfile, "\n");
+ }
+#endif /* TypTrc */
+
+ if (optab[Val0(Tree0(n))].tok.t_type == AUGAT) {
+ /*
+ * Perform type inference on the assignment.
+ */
+ asgn_impl = optab[asgn_loc].binary;
+ sav_argtyp = arg_typs;
+ sav_nargs = num_args;
+ arg_typs = get_argtyp();
+ num_args = 2;
+ arg_typs->types[0] = Tree1(n)->type;
+ arg_typs->types[1] = rslt_typ->bits;
+ infer_impl(asgn_impl, n, n->symtyps->next, n->type);
+ chk_succ(asgn_impl->ret_flag, n->store);
+ free_argtyp(arg_typs);
+ arg_typs = sav_argtyp;
+ num_args = sav_nargs;
+ }
+ else
+ ChkMrgTyp(n_intrtyp, rslt_typ->bits, n->type)
+
+ free_wktyp(rslt_typ);
+ }
+
+/*
+ * mrg_act - merge entry information for the co-expression to the
+ * the ending store and result type for the activation being
+ * analyzed.
+ */
+static void mrg_act(coexp, e_store, rslt_typ)
+struct t_coexpr *coexp;
+struct store *e_store;
+struct type *rslt_typ;
+ {
+ struct store *store;
+ int i;
+
+ store = coexp->in_store;
+ for (i = 0; i < n_gbl; ++i)
+ MrgTyp(n_icntyp, store->types[i], e_store->types[i]);
+
+ MrgTyp(n_intrtyp, coexp->act_typ, rslt_typ->bits)
+ }
+
+/*
+ * typ_deref - perform dereferencing in the abstract type realm.
+ */
+static void typ_deref(src, dest, chk)
+#ifdef OptimizeType
+struct typinfo *src;
+struct typinfo *dest;
+#else /* OptimizeType */
+unsigned int *src;
+unsigned int *dest;
+#endif /* OptimizeType */
+int chk;
+ {
+ struct store *tblel_stor;
+ struct store *tbldf_stor;
+ struct store *ttv_stor;
+ struct store *store;
+ unsigned int old;
+ int num_tbl;
+ int frst_tbl;
+ int num_bits;
+ int frst_bit;
+ int i;
+ int j;
+ int ret;
+/*
+ if (src->bits == NULL) {
+ src->bits = alloc_mem_typ(src->size);
+ xfer_packed_types(src);
+ }
+ if (dest->bits == NULL) {
+ dest->bits = alloc_mem_typ(dest->size);
+ xfer_packed_types(dest);
+ }
+*/
+ /*
+ * copy values to destination
+ */
+#ifdef OptimizeType
+ if ((src->bits != NULL) && (dest->bits != NULL)) {
+ for (i = 0; i < NumInts(n_icntyp) - 1; ++i) {
+ old = dest->bits[i];
+ dest->bits[i] |= src->bits[i];
+ if (chk && (old != dest->bits[i]))
+ ++changed;
+ }
+ old = dest->bits[i];
+ dest->bits[i] |= src->bits[i] & val_mask; /* mask out variables */
+ if (chk && (old != dest->bits[i]))
+ ++changed;
+ }
+ else if ((src->bits != NULL) && (dest->bits == NULL)) {
+ dest->bits = alloc_mem_typ(DecodeSize(dest->packed));
+ xfer_packed_types(dest);
+ for (i = 0; i < NumInts(n_icntyp) - 1; ++i) {
+ old = dest->bits[i];
+ dest->bits[i] |= src->bits[i];
+ if (chk && (old != dest->bits[i]))
+ ++changed;
+ }
+ old = dest->bits[i];
+ dest->bits[i] |= src->bits[i] & val_mask; /* mask out variables */
+ if (chk && (old != dest->bits[i]))
+ ++changed;
+ }
+ else if ((src->bits == NULL) && (dest->bits != NULL)) {
+ ret = xfer_packed_to_bits(src, dest, n_icntyp);
+ if (chk)
+ changed += ret;
+ }
+ else {
+ ret = mrg_packed_to_packed(src, dest, n_icntyp);
+ if (chk)
+ changed += ret;
+ }
+#else /* OptimizeType */
+ for (i = 0; i < NumInts(n_icntyp) - 1; ++i) {
+ old = dest[i];
+ dest[i] |= src[i];
+ if (chk && (old != dest[i]))
+ ++changed;
+ }
+ old = dest[i];
+ dest[i] |= src[i] & val_mask; /* mask out variables */
+ if (chk && (old != dest[i]))
+ ++changed;
+#endif /* OptimizeType */
+
+ /*
+ * predefined variables whose types do not change.
+ */
+ for (i = 0; i < num_typs; ++i) {
+ if (icontypes[i].deref == DrfCnst) {
+ if (bitset(src, type_array[i].frst_bit))
+ if (chk)
+ ChkMrgTyp(n_icntyp, type_array[i].typ, dest)
+ else
+ MrgTyp(n_icntyp, type_array[i].typ, dest)
+ }
+ }
+
+
+ /*
+ * substring trapped variables
+ */
+ num_bits = type_array[stv_typ].num_bits;
+ frst_bit = type_array[stv_typ].frst_bit;
+ for (i = 0; i < num_bits; ++i)
+ if (bitset(src, frst_bit + i))
+ if (!bitset(dest, str_bit)) {
+ if (chk)
+ ++changed;
+ set_typ(dest, str_bit);
+ }
+
+ /*
+ * table element trapped variables
+ */
+ num_bits = type_array[ttv_typ].num_bits;
+ frst_bit = type_array[ttv_typ].frst_bit;
+ num_tbl = type_array[tbl_typ].num_bits;
+ frst_tbl = type_array[tbl_typ].frst_bit;
+ tblel_stor = compnt_array[tbl_val].store;
+ tbldf_stor = compnt_array[tbl_dflt].store;
+ ttv_stor = compnt_array[trpd_tbl].store;
+ for (i = 0; i < num_bits; ++i)
+ if (bitset(src, frst_bit + i))
+ for (j = 0; j < num_tbl; ++j)
+ if (bitset(ttv_stor->types[i], frst_tbl + j)) {
+ if (chk) {
+ ChkMrgTyp(n_icntyp, tblel_stor->types[j], dest)
+ ChkMrgTyp(n_icntyp, tbldf_stor->types[j], dest)
+ }
+ else {
+ MrgTyp(n_icntyp, tblel_stor->types[j], dest)
+ MrgTyp(n_icntyp, tbldf_stor->types[j], dest)
+ }
+ }
+
+ /*
+ * Aggregate compontents that are variables.
+ */
+ for (i = 0; i < num_cmpnts; ++i) {
+ if (typecompnt[i].var) {
+ frst_bit = compnt_array[i].frst_bit;
+ num_bits = compnt_array[i].num_bits;
+ store = compnt_array[i].store;
+ for (j = 0; j < num_bits; ++j) {
+ if (bitset(src, frst_bit + j))
+ if (chk)
+ ChkMrgTyp(n_icntyp, store->types[j], dest)
+ else
+ MrgTyp(n_icntyp, store->types[j], dest)
+ }
+ }
+ }
+
+
+ /*
+ * record fields
+ */
+ for (i = 0; i < n_fld; ++i)
+ if (bitset(src, frst_fld + i)) {
+ if (chk)
+ ChkMrgTyp(n_icntyp, fld_stor->types[i], dest)
+ else
+ MrgTyp(n_icntyp, fld_stor->types[i], dest)
+ }
+
+ /*
+ * global variables
+ */
+ for (i = 0; i < n_gbl; ++i)
+ if (bitset(src, frst_gbl + i)) {
+ if (chk)
+ ChkMrgTyp(n_icntyp, succ_store->types[i], dest)
+ else
+ MrgTyp(n_icntyp, succ_store->types[i], dest)
+ }
+
+ /*
+ * local variables
+ */
+ for (i = 0; i < n_loc; ++i)
+ if (bitset(src, frst_loc + i)) {
+ if (chk)
+ ChkMrgTyp(n_icntyp, succ_store->types[n_gbl + i], dest)
+ else
+ MrgTyp(n_icntyp, succ_store->types[n_gbl + i], dest)
+ }
+}
+
+/*
+ * infer_impl - perform type inference on a call to built-in operation
+ * using the implementation entry from the data base.
+ */
+static void infer_impl(impl, n, symtyps, rslt_typ)
+struct implement *impl;
+nodeptr n;
+struct symtyps *symtyps;
+#ifdef OptimizeType
+struct typinfo *rslt_typ;
+#else /* OptimizeType */
+unsigned int *rslt_typ;
+#endif /* OptimizeType */
+ {
+#ifdef OptimizeType
+ struct typinfo *typ;
+#else /* OptimizeType */
+ unsigned int *typ;
+#endif /* OptimizeType */
+ int flag;
+ int nparms;
+ int i;
+ int j;
+
+#ifdef TypTrc
+ if (trcfile != NULL) {
+ fprintf(trcfile, "%s (%d,%d) %s", n->n_file, n->n_line, n->n_col,
+ trc_indent);
+ if (impl->oper_typ == 'K')
+ fprintf(trcfile, "&%s", impl->name);
+ else
+ fprintf(trcfile, "%s(", impl->name);
+ }
+#endif /* TypTrc */
+ /*
+ * Set up the "symbol table" of dereferenced and undereferenced
+ * argument types as needed by the operation.
+ */
+ nparms = impl->nargs;
+ j = 0;
+ for (i = 0; i < num_args && i < nparms; ++i) {
+ if (impl->arg_flgs[i] & RtParm) {
+ CpyTyp(n_intrtyp, arg_typs->types[i], symtyps->types[j]);
+
+#ifdef TypTrc
+ if (trcfile != NULL) {
+ if (i > 0)
+ fprintf(trcfile, ", ");
+ prt_typ(trcfile, arg_typs->types[i]);
+ }
+#endif /* TypTrc */
+
+ ++j;
+ }
+ if (impl->arg_flgs[i] & DrfPrm) {
+ typ_deref(arg_typs->types[i], symtyps->types[j], 0);
+
+#ifdef TypTrc
+ if (trcfile != NULL) {
+ if (impl->arg_flgs[i] & RtParm)
+ fprintf(trcfile, "->");
+ else if (i > 0)
+ fprintf(trcfile, ", ");
+ prt_d_typ(trcfile, arg_typs->types[i]);
+ }
+#endif /* TypTrc */
+
+ ++j;
+ }
+ }
+ if (nparms > 0) {
+ /*
+ * Check for varargs. Merge remaining arguments into the
+ * type of the variable part of the parameter list.
+ */
+ flag = impl->arg_flgs[nparms - 1];
+ if (flag & VarPrm) {
+ n_vararg = num_args - nparms + 1;
+ if (n_vararg < 0)
+ n_vararg = 0;
+ typ = symtyps->types[j - 1];
+ while (i < num_args) {
+ if (flag & RtParm) {
+ MrgTyp(n_intrtyp, arg_typs->types[i], typ)
+
+#ifdef TypTrc
+ if (trcfile != NULL) {
+ if (i > 0)
+ fprintf(trcfile, ", ");
+ prt_typ(trcfile, arg_typs->types[i]);
+ }
+#endif /* TypTrc */
+
+ }
+ else {
+ typ_deref(arg_typs->types[i], typ, 0);
+
+#ifdef TypTrc
+ if (trcfile != NULL) {
+ if (i > 0)
+ fprintf(trcfile, ", ");
+ prt_d_typ(trcfile, arg_typs->types[i]);
+ }
+#endif /* TypTrc */
+
+ }
+ ++i;
+ }
+ nparms -= 1; /* Don't extend with nulls into variable part */
+ }
+ }
+ while (i < nparms) {
+ if (impl->arg_flgs[i] & RtParm)
+ set_typ(symtyps->types[j++], null_bit); /* Extend args with nulls */
+ if (impl->arg_flgs[i] & DrfPrm)
+ set_typ(symtyps->types[j++], null_bit); /* Extend args with nulls */
+ ++i;
+ }
+
+ /*
+ * If this operation can suspend, there may be backtracking paths
+ * to this invocation. Merge type information from those paths
+ * into the current store.
+ */
+ if (impl->ret_flag & DoesSusp)
+ mrg_store(n->store, succ_store);
+
+ cur_symtyps = symtyps;
+ cur_rslt.bits = rslt_typ;
+ cur_rslt.size = n_intrtyp;
+ cur_new = n->new_types;
+ infer_il(impl->in_line); /* perform inference on operation */
+
+ if (MightFail(impl->ret_flag))
+ mrg_store(succ_store, fail_store);
+
+#ifdef TypTrc
+ if (trcfile != NULL) {
+ if (impl->oper_typ != 'K')
+ fprintf(trcfile, ")");
+ fprintf(trcfile, " =>> ");
+ prt_typ(trcfile, rslt_typ);
+ fprintf(trcfile, "\n");
+ }
+#endif /* TypTrc */
+ }
+
+/*
+ * chk_succ - check to see if the operation can succeed. In particular,
+ * see if it can suspend. Change the succ_store and failure store
+ * appropriately.
+ */
+static void chk_succ(ret_flag, susp_stor)
+int ret_flag;
+struct store *susp_stor;
+ {
+ if (ret_flag & DoesSusp) {
+ if (susp_stor != NULL && (ret_flag & DoesRet))
+ mrg_store(susp_stor, fail_store); /* "pass along" failure */
+ fail_store = susp_stor;
+ }
+ else if (!(ret_flag & DoesRet)) {
+ free_store(succ_store);
+ succ_store = get_store(1);
+ fail_store = dummy_stor; /* shouldn't be used */
+ }
+ }
+
+/*
+ * infer_il - perform type inference on a piece of code within built-in
+ * operation and determine whether execution can get past it.
+ */
+static int infer_il(il)
+struct il_code *il;
+ {
+ struct il_code *il1;
+ int condition;
+ int case_fnd;
+ int ncases;
+ int may_fallthru;
+ int indx;
+ int i;
+
+ if (il == NULL)
+ return 1;
+
+ switch (il->il_type) {
+ case IL_Const: /* should have been replaced by literal node */
+ return 0;
+
+ case IL_If1:
+ condition = eval_cond(il->u[0].fld);
+ may_fallthru = (condition & MaybeFalse);
+ if (condition & MaybeTrue)
+ may_fallthru |= infer_il(il->u[1].fld);
+ return may_fallthru;
+
+ case IL_If2:
+ condition = eval_cond(il->u[0].fld);
+ may_fallthru = 0;
+ if (condition & MaybeTrue)
+ may_fallthru |= infer_il(il->u[1].fld);
+ if (condition & MaybeFalse)
+ may_fallthru |= infer_il(il->u[2].fld);
+ return may_fallthru;
+
+ case IL_Tcase1:
+ type_case(il, infer_il, NULL);
+ return 1; /* no point in trying very hard here */
+
+ case IL_Tcase2:
+ indx = type_case(il, infer_il, NULL);
+ if (indx != -1)
+ infer_il(il->u[indx].fld); /* default */
+ return 1; /* no point in trying very hard here */
+
+ case IL_Lcase:
+ ncases = il->u[0].n;
+ indx = 1;
+ case_fnd = 0;
+ for (i = 0; i < ncases && !case_fnd; ++i) {
+ if (il->u[indx++].n == n_vararg) { /* selection number */
+ infer_il(il->u[indx].fld); /* action */
+ case_fnd = 1;
+ }
+ ++indx;
+ }
+ if (!case_fnd)
+ infer_il(il->u[indx].fld); /* default */
+ return 1; /* no point in trying very hard here */
+
+ case IL_Acase: {
+ int maybe_int;
+ int maybe_dbl;
+
+ eval_arith((int)il->u[0].fld->u[0].n, (int)il->u[1].fld->u[0].n,
+ &maybe_int, &maybe_dbl);
+ if (maybe_int) {
+ infer_il(il->u[2].fld); /* C_integer action */
+ if (largeints)
+ infer_il(il->u[3].fld); /* integer action */
+ }
+ if (maybe_dbl)
+ infer_il(il->u[4].fld); /* C_double action */
+ return 1; /* no point in trying very hard here */
+ }
+
+ case IL_Err1:
+ case IL_Err2:
+ return 0;
+
+ case IL_Block:
+ return il->u[0].n;
+
+ case IL_Call:
+ return ((il->u[3].n & DoesFThru) != 0);
+
+ case IL_Lst:
+ if (infer_il(il->u[0].fld))
+ return infer_il(il->u[1].fld);
+ else
+ return 0;
+
+ case IL_Abstr:
+ /*
+ * Handle side effects.
+ */
+ il1 = il->u[0].fld;
+ if (il1 != NULL) {
+ while (il1->il_type == IL_Lst) {
+ side_effect(il1->u[1].fld);
+ il1 = il1->u[0].fld;
+ }
+ side_effect(il1);
+ }
+
+ /*
+ * Set return type.
+ */
+ abstr_typ(il->u[1].fld, &cur_rslt);
+ return 1;
+
+ default:
+ fprintf(stderr, "compiler error: unknown info in data base\n");
+ exit(EXIT_FAILURE);
+ /* NOTREACHED */
+ }
+ }
+
+/*
+ * side_effect - perform a side effect from an abstract clause of a
+ * built-in operation.
+ */
+static void side_effect(il)
+struct il_code *il;
+ {
+ struct type *var_typ;
+ struct type *val_typ;
+ struct store *store;
+ int num_bits;
+ int frst_bit;
+ int i, j;
+
+ /*
+ * il is IL_TpAsgn, get the variable type and value type, and perform
+ * the side effect.
+ */
+ var_typ = get_wktyp();
+ val_typ = get_wktyp();
+ abstr_typ(il->u[0].fld, var_typ); /* variable type */
+ abstr_typ(il->u[1].fld, val_typ); /* value type */
+
+ /*
+ * Determine which types that can be assigned to are in the variable
+ * type.
+ *
+ * Aggregate compontents.
+ */
+ for (i = 0; i < num_cmpnts; ++i) {
+ frst_bit = compnt_array[i].frst_bit;
+ num_bits = compnt_array[i].num_bits;
+ store = compnt_array[i].store;
+ for (j = 0; j < num_bits; ++j) {
+ if (bitset(var_typ->bits, frst_bit + j))
+ ChkMrgTyp(n_icntyp, val_typ->bits, store->types[j])
+ }
+ }
+
+ /*
+ * record fields
+ */
+ for (i = 0; i < n_fld; ++i)
+ if (bitset(var_typ->bits, frst_fld + i))
+ ChkMrgTyp(n_icntyp, val_typ->bits, fld_stor->types[i]);
+
+ /*
+ * global variables
+ */
+ for (i = 0; i < n_gbl; ++i)
+ if (bitset(var_typ->bits, frst_gbl + i))
+ MrgTyp(n_icntyp, val_typ->bits, succ_store->types[i]);
+
+ /*
+ * local variables
+ */
+ for (i = 0; i < n_loc; ++i)
+ if (bitset(var_typ->bits, frst_loc + i))
+ MrgTyp(n_icntyp, val_typ->bits, succ_store->types[n_gbl + i]);
+
+
+ free_wktyp(var_typ);
+ free_wktyp(val_typ);
+ }
+
+/*
+ * abstr_typ - compute the type bits corresponding to an abstract type
+ * from an abstract clause of a built-in operation.
+ */
+static void abstr_typ(il, typ)
+struct il_code *il;
+struct type *typ;
+ {
+ struct type *typ1;
+ struct type *typ2;
+ struct rentry *rec;
+ struct store *store;
+ struct compnt_info *compnts;
+ int num_bits;
+ int frst_bit;
+ int frst_cmpnt;
+ int num_comps;
+ int typcd;
+ int new_indx;
+ int i;
+ int j;
+ int indx;
+ int size;
+ int t_indx;
+#ifdef OptimizeType
+ struct typinfo *prmtyp;
+#else /* OptimizeType */
+ unsigned int *prmtyp;
+#endif /* OptimizeType */
+
+ if (il == NULL)
+ return;
+
+ switch (il->il_type) {
+ case IL_VarTyp:
+ /*
+ * type(<parameter>)
+ */
+ indx = il->u[0].fld->u[0].n; /* symbol table index of variable */
+ if (indx >= cur_symtyps->nsyms) {
+ prmtyp = any_typ;
+ size = n_rttyp;
+ }
+ else {
+ prmtyp = cur_symtyps->types[indx];
+ size = n_intrtyp;
+ }
+ if (typ->size < size)
+ size = typ->size;
+ MrgTyp(size, prmtyp, typ->bits);
+ break;
+
+ case IL_Store:
+ /*
+ * store[<type>]
+ */
+ typ1 = get_wktyp();
+ abstr_typ(il->u[0].fld, typ1); /* type to be "dereferenced" */
+
+ /*
+ * Dereference types that are Icon varaibles.
+ */
+ typ_deref(typ1->bits, typ->bits, 0);
+
+ /*
+ * "Dereference" aggregate compontents that are not Icon variables.
+ */
+ for (i = 0; i < num_cmpnts; ++i) {
+ if (!typecompnt[i].var) {
+ if (i == stv_typ) {
+ /*
+ * Substring trapped variable stores contain variable
+ * references, so the types are larger, but we cannot
+ * copy more than the destination holds.
+ */
+ size = n_intrtyp;
+ if (typ->size < size)
+ size = typ->size;
+ }
+ else
+ size = n_icntyp;
+ frst_bit = compnt_array[i].frst_bit;
+ num_bits = compnt_array[i].num_bits;
+ store = compnt_array[i].store;
+ for (j = 0; j < num_bits; ++j) {
+ if (bitset(typ1->bits, frst_bit + j))
+ MrgTyp(size, store->types[j], typ->bits);
+ }
+ }
+ }
+
+ free_wktyp(typ1);
+ break;
+
+ case IL_Compnt:
+ /*
+ * <type>.<component>
+ */
+ typ1 = get_wktyp();
+ abstr_typ(il->u[0].fld, typ1); /* type */
+ i = il->u[1].n;
+ if (i == CM_Fields) {
+ /*
+ * The all_fields component must be handled differently
+ * from the others.
+ */
+ frst_bit = type_array[rec_typ].frst_bit;
+ num_bits = type_array[rec_typ].num_bits;
+ for (i = 0; i < num_bits; ++i)
+ if (bitset(typ1->bits, frst_bit + i)) {
+ rec = rec_map[i];
+ for (j = 0; j < rec->nfields; ++j)
+ set_typ(typ->bits, frst_fld + rec->frst_fld + j);
+ }
+ }
+ else {
+ /*
+ * Use component information arrays to transform type bits to
+ * the corresponding component bits.
+ */
+ frst_bit = type_array[typecompnt[i].aggregate].frst_bit;
+ num_bits = type_array[typecompnt[i].aggregate].num_bits;
+ frst_cmpnt = compnt_array[i].frst_bit;
+ if (!typecompnt[i].var && typ->size < n_rttyp)
+ break; /* bad abstract type computation */
+ for (i = 0; i < num_bits; ++i)
+ if (bitset(typ1->bits, frst_bit + i))
+ set_typ(typ->bits, frst_cmpnt + i);
+ free_wktyp(typ1);
+ }
+ break;
+
+ case IL_Union:
+ /*
+ * <type 1> ++ <type 2>
+ */
+ abstr_typ(il->u[0].fld, typ);
+ abstr_typ(il->u[1].fld, typ);
+ break;
+
+ case IL_Inter:
+ /*
+ * <type 1> ** <type 2>
+ */
+ typ1 = get_wktyp();
+ typ2 = get_wktyp();
+ abstr_typ(il->u[0].fld, typ1);
+ abstr_typ(il->u[1].fld, typ2);
+ size = n_rttyp;
+#ifdef OptimizeType
+ and_bits_to_packed(typ2->bits, typ1->bits, size);
+#else /* OptimizeType */
+ for (i = 0; i < NumInts(size); ++i)
+ typ1->bits[i] &= typ2->bits[i];
+#endif /* OptimizeType */
+ if (typ->size < size)
+ size = typ->size;
+ MrgTyp(size, typ1->bits, typ->bits);
+ free_wktyp(typ1);
+ free_wktyp(typ2);
+ break;
+
+ case IL_New:
+ /*
+ * new <type-name>(<type 1> , ...)
+ *
+ * If a type was not allocated for this node, use the default
+ * one.
+ */
+ typ1 = get_wktyp();
+ typcd = il->u[0].n; /* type code */
+ new_indx = type_array[typcd].new_indx;
+ t_indx = 0; /* default is first index of type */
+ if (cur_new != NULL && cur_new[new_indx] > 0)
+ t_indx = cur_new[new_indx];
+
+ /*
+ * This RTL expression evaluates to the "new" sub-type.
+ */
+ set_typ(typ->bits, type_array[typcd].frst_bit + t_indx);
+
+ /*
+ * Update stores for components based on argument types in the
+ * "new" expression.
+ */
+ num_comps = icontypes[typcd].num_comps;
+ j = icontypes[typcd].compnts;
+ compnts = &compnt_array[j];
+ if (typcd == stv_typ) {
+ size = n_intrtyp;
+ }
+ else
+ size = n_icntyp;
+ for (i = 0; i < num_comps; ++i) {
+ ClrTyp(n_rttyp, typ1->bits);
+ abstr_typ(il->u[2 + i].fld, typ1);
+ ChkMrgTyp(size, typ1->bits, compnts[i].store->types[t_indx]);
+ }
+
+ free_wktyp(typ1);
+ break;
+
+ case IL_IcnTyp:
+ typcd_bits((int)il->u[0].n, typ); /* type code */
+ break;
+ }
+ }
+
+/*
+ * eval_cond - evaluate the condition of in 'if' statement from a
+ * built-in operation. The result can be both true and false because
+ * of uncertainty and because more than one execution path may be
+ * involved.
+ */
+static int eval_cond(il)
+struct il_code *il;
+ {
+ int cond1;
+ int cond2;
+
+ switch (il->il_type) {
+ case IL_Bang:
+ cond1 = eval_cond(il->u[0].fld);
+ cond2 = 0;
+ if (cond1 & MaybeTrue)
+ cond2 = MaybeFalse;
+ if (cond1 & MaybeFalse)
+ cond2 |= MaybeTrue;
+ return cond2;
+
+ case IL_And:
+ cond1 = eval_cond(il->u[0].fld);
+ cond2 = eval_cond(il->u[1].fld);
+ return (cond1 & cond2 & MaybeTrue) | ((cond1 | cond2) & MaybeFalse);
+
+ case IL_Cnv1:
+ case IL_Cnv2:
+ return eval_cnv((int)il->u[0].n, (int)il->u[1].fld->u[0].n,
+ 0, NULL);
+
+ case IL_Def1:
+ case IL_Def2:
+ return eval_cnv((int)il->u[0].n, (int)il->u[1].fld->u[0].n,
+ 1, NULL);
+
+ case IL_Is:
+ return eval_is((int)il->u[0].n, il->u[1].fld->u[0].n);
+
+ default:
+ fprintf(stderr, "compiler error: unknown info in data base\n");
+ exit(EXIT_FAILURE);
+ /* NOTREACHED */
+ }
+ }
+
+/*
+ * eval_cnv - evaluate the conversion of a variable to a specific type
+ * to see if it may succeed or fail.
+ */
+int eval_cnv(typcd, indx, def, cnv_flags)
+int typcd; /* type to convert to */
+int indx; /* index into symbol table of variable */
+int def; /* flag: conversion has a default value */
+int *cnv_flags; /* return flag for detailed conversion information */
+ {
+ struct type *may_succeed; /* types where conversion sometimes succeed */
+ struct type *must_succeed; /* types where conversion always succeeds */
+ struct type *must_cnv; /* types where actual conversion is performed */
+ struct type *as_is; /* types where value already has correct type */
+#ifdef OptimizeType
+ struct typinfo *typ; /* possible types of the variable */
+#else /* OptimizeType */
+ unsigned int *typ;
+#endif /* OptimizeType */
+ int cond;
+ int i;
+#ifdef OptimizeType
+ unsigned int val1, val2;
+#endif /* OptimizeType */
+
+ /*
+ * Conversions may succeed for strings, integers, csets, and reals.
+ * Conversions may fail for any other types. In addition,
+ * conversions to integer or real may fail for specific values.
+ */
+ if (indx >= cur_symtyps->nsyms)
+ return MaybeTrue | MaybeFalse;
+ typ = cur_symtyps->types[indx];
+
+ may_succeed = get_wktyp();
+ must_succeed = get_wktyp();
+ must_cnv = get_wktyp();
+ as_is = get_wktyp();
+
+ if (typcd == cset_typ || typcd == TypTCset) {
+ set_typ(as_is->bits, cset_bit);
+
+ set_typ(must_cnv->bits, str_bit);
+ set_typ(must_cnv->bits, int_bit);
+ set_typ(must_cnv->bits, real_bit);
+
+ set_typ(must_succeed->bits, str_bit);
+ set_typ(must_succeed->bits, cset_bit);
+ set_typ(must_succeed->bits, int_bit);
+ set_typ(must_succeed->bits, real_bit);
+ }
+ else if (typcd == str_typ || typcd == TypTStr) {
+ set_typ(as_is->bits, str_bit);
+
+ set_typ(must_cnv->bits, cset_bit);
+ set_typ(must_cnv->bits, int_bit);
+ set_typ(must_cnv->bits, real_bit);
+
+ set_typ(must_succeed->bits, str_bit);
+ set_typ(must_succeed->bits, cset_bit);
+ set_typ(must_succeed->bits, int_bit);
+ set_typ(must_succeed->bits, real_bit);
+ }
+ else if (typcd == TypCStr) {
+ /*
+ * as_is is empty.
+ */
+
+ set_typ(must_cnv->bits, str_bit);
+ set_typ(must_cnv->bits, cset_bit);
+ set_typ(must_cnv->bits, int_bit);
+ set_typ(must_cnv->bits, real_bit);
+
+ set_typ(must_succeed->bits, str_bit);
+ set_typ(must_succeed->bits, cset_bit);
+ set_typ(must_succeed->bits, int_bit);
+ set_typ(must_succeed->bits, real_bit);
+ }
+ else if (typcd == real_typ) {
+ set_typ(as_is->bits, real_bit);
+
+ set_typ(must_cnv->bits, str_bit);
+ set_typ(must_cnv->bits, cset_bit);
+ set_typ(must_cnv->bits, int_bit);
+
+ set_typ(must_succeed->bits, int_bit);
+ set_typ(must_succeed->bits, real_bit);
+ }
+ else if (typcd == TypCDbl) {
+ /*
+ * as_is is empty.
+ */
+
+ set_typ(must_cnv->bits, str_bit);
+ set_typ(must_cnv->bits, cset_bit);
+ set_typ(must_cnv->bits, int_bit);
+ set_typ(must_cnv->bits, real_bit);
+
+ set_typ(must_succeed->bits, int_bit);
+ set_typ(must_succeed->bits, real_bit);
+ }
+ else if (typcd == int_typ) {
+ set_typ(as_is->bits, int_bit);
+
+ set_typ(must_cnv->bits, str_bit);
+ set_typ(must_cnv->bits, cset_bit);
+ set_typ(must_cnv->bits, real_bit);
+
+ set_typ(must_succeed->bits, int_bit);
+ }
+ else if (typcd == TypCInt) {
+ /*
+ * Note that conversion from an integer to a C integer can be
+ * done by changing the way the descriptor is accessed. It
+ * is not considered a real conversion. Conversion may fail
+ * even for integers if large integers are supported.
+ */
+ set_typ(as_is->bits, int_bit);
+
+ set_typ(must_cnv->bits, str_bit);
+ set_typ(must_cnv->bits, cset_bit);
+ set_typ(must_cnv->bits, real_bit);
+
+ if (!largeints)
+ set_typ(must_succeed->bits, int_bit);
+ }
+ else if (typcd == TypEInt) {
+ set_typ(as_is->bits, int_bit);
+
+ set_typ(must_cnv->bits, str_bit);
+ set_typ(must_cnv->bits, cset_bit);
+
+ set_typ(must_succeed->bits, int_bit);
+ }
+ else if (typcd == TypECInt) {
+ set_typ(as_is->bits, int_bit);
+
+ set_typ(must_cnv->bits, str_bit);
+ set_typ(must_cnv->bits, cset_bit);
+
+ if (!largeints)
+ set_typ(must_succeed->bits, int_bit);
+ }
+
+ MrgTyp(n_icntyp, as_is->bits, may_succeed->bits);
+ MrgTyp(n_icntyp, must_cnv->bits, may_succeed->bits);
+ if (def) {
+ set_typ(may_succeed->bits, null_bit);
+ set_typ(must_succeed->bits, null_bit);
+ }
+
+ /*
+ * Determine if the conversion expression may evaluate to true or false.
+ */
+ cond = 0;
+
+/*
+ if (typ->bits == NULL) {
+ typ->bits = alloc_mem_typ(typ->size);
+ xfer_packed_types(typ);
+ }
+ if (may_succeed->bits->bits == NULL) {
+ may_succeed->bits->bits = alloc_mem_typ(may_succeed->bits->size);
+ xfer_packed_types(may_succeed->bits);
+ }
+ if (must_succeed->bits->bits == NULL) {
+ must_succeed->bits->bits = alloc_mem_typ(must_succeed->bits->size);
+ xfer_packed_types(must_succeed->bits);
+ }
+*/
+ for (i = 0; i < NumInts(n_intrtyp); ++i) {
+#ifdef OptimizeType
+ if ((typ->bits != NULL) && (may_succeed->bits->bits != NULL)) {
+ if (typ->bits[i] & may_succeed->bits->bits[i])
+ cond = MaybeTrue;
+ }
+ else if ((typ->bits == NULL) && (may_succeed->bits->bits != NULL)) {
+ val1 = get_bit_vector(typ, i);
+ if (val1 & may_succeed->bits->bits[i])
+ cond = MaybeTrue;
+ }
+ else if ((typ->bits != NULL) && (may_succeed->bits->bits == NULL)) {
+ val2 = get_bit_vector(may_succeed->bits, i);
+ if (typ->bits[i] & val2)
+ cond = MaybeTrue;
+ }
+ else {
+ val1 = get_bit_vector(typ, i);
+ val2 = get_bit_vector(may_succeed->bits, i);
+ if (val1 & val2)
+ cond = MaybeTrue;
+ }
+ if ((typ->bits != NULL) && (must_succeed->bits->bits != NULL)) {
+ if (typ->bits[i] & ~must_succeed->bits->bits[i])
+ cond |= MaybeFalse;
+ }
+ else if ((typ->bits == NULL) && (must_succeed->bits->bits != NULL)) {
+ val1 = get_bit_vector(typ, i);
+ if (val1 & ~must_succeed->bits->bits[i])
+ cond |= MaybeFalse;
+ }
+ else if ((typ->bits != NULL) && (must_succeed->bits->bits == NULL)) {
+ val2 = get_bit_vector(must_succeed->bits, i);
+ if (typ->bits[i] & ~val2)
+ cond |= MaybeFalse;
+ }
+ else {
+ val1 = get_bit_vector(typ, i);
+ val2 = get_bit_vector(must_succeed->bits, i);
+ if (val1 & ~val2)
+ cond |= MaybeFalse;
+ }
+#else /* OptimizeType */
+ if (typ[i] & may_succeed->bits[i])
+ cond = MaybeTrue;
+ if (typ[i] & ~must_succeed->bits[i])
+ cond |= MaybeFalse;
+#endif /* OptimizeType */
+ }
+
+ /*
+ * See if more detailed information about the conversion is needed.
+ */
+ if (cnv_flags != NULL) {
+ *cnv_flags = 0;
+/*
+ if (as_is->bits == NULL) {
+ as_is->bits->bits = alloc_mem_typ(as_is->bits->size);
+ xfer_packed_types(as_is->bits);
+ }
+ if (must_cnv->bits->bits == NULL) {
+ must_cnv->bits->bits = alloc_mem_typ(must_cnv->bits->size);
+ xfer_packed_types(must_cnv->bits);
+ }
+*/
+ for (i = 0; i < NumInts(n_intrtyp); ++i) {
+#ifdef OptimizeType
+ if ((typ->bits != NULL) && (as_is->bits->bits != NULL)) {
+ if (typ->bits[i] & as_is->bits->bits[i])
+ *cnv_flags |= MayKeep;
+ }
+ else if ((typ->bits == NULL) && (as_is->bits->bits != NULL)) {
+ val1 = get_bit_vector(typ, i);
+ if (val1 & as_is->bits->bits[i])
+ *cnv_flags |= MayKeep;
+ }
+ else if ((typ->bits != NULL) && (as_is->bits->bits == NULL)) {
+ val2 = get_bit_vector(as_is->bits, i);
+ if (typ->bits[i] & val2)
+ *cnv_flags |= MayKeep;
+ }
+ else {
+ val1 = get_bit_vector(typ, i);
+ val2 = get_bit_vector(as_is->bits, i);
+ if (val1 & val2)
+ *cnv_flags |= MayKeep;
+ }
+ if ((typ->bits != NULL) && (must_cnv->bits->bits != NULL)) {
+ if (typ->bits[i] & must_cnv->bits->bits[i])
+ *cnv_flags |= MayConvert;
+ }
+ else if ((typ->bits == NULL) && (must_cnv->bits->bits != NULL)) {
+ val1 = get_bit_vector(typ, i);
+ if (val1 & must_cnv->bits->bits[i])
+ *cnv_flags |= MayConvert;
+ }
+ else if ((typ->bits != NULL) && (must_cnv->bits->bits == NULL)) {
+ val2 = get_bit_vector(must_cnv->bits, i);
+ if (typ->bits[i] & val2)
+ *cnv_flags |= MayConvert;
+ }
+ else {
+ val1 = get_bit_vector(typ, i);
+ val2 = get_bit_vector(must_cnv->bits, i);
+ if (val1 & val2)
+ *cnv_flags |= MayConvert;
+ }
+#else /* OptimizeType */
+ if (typ[i] & as_is->bits[i])
+ *cnv_flags |= MayKeep;
+ if (typ[i] & must_cnv->bits[i])
+ *cnv_flags |= MayConvert;
+#endif /* OptimizeType */
+ }
+ if (def && bitset(typ, null_bit))
+ *cnv_flags |= MayDefault;
+ }
+
+ free_wktyp(may_succeed);
+ free_wktyp(must_succeed);
+ free_wktyp(must_cnv);
+ free_wktyp(as_is);
+
+ return cond;
+ }
+
+/*
+ * eval_is - evaluate the result of an 'is' expression within a built-in
+ * operation.
+ */
+int eval_is(typcd, indx)
+int typcd;
+int indx;
+ {
+ int cond;
+#ifdef OptimizeType
+ struct typinfo *typ;
+#else /* OptimizeType */
+ unsigned int *typ;
+#endif /* OptimizeType */
+
+ if (indx >= cur_symtyps->nsyms)
+ return MaybeTrue | MaybeFalse;
+ typ = cur_symtyps->types[indx];
+ if (has_type(typ, typcd, 0))
+ cond = MaybeTrue;
+ else
+ cond = 0;
+ if (other_type(typ, typcd))
+ cond |= MaybeFalse;
+ return cond;
+ }
+
+/*
+ * eval_arith - determine which cases of an arith_case may be taken based
+ * on the types of its arguments.
+ */
+void eval_arith(indx1, indx2, maybe_int, maybe_dbl)
+int indx1;
+int indx2;
+int *maybe_int;
+int *maybe_dbl;
+ {
+#ifdef OptimizeType
+ struct typinfo *typ1; /* possible types of first variable */
+ struct typinfo *typ2; /* possible types of second variable */
+#else /* OptimizeType */
+ unsigned int *typ1; /* possible types of first variable */
+ unsigned int *typ2; /* possible types of second variable */
+#endif /* OptimizeType */
+ int int1 = 0;
+ int int2 = 0;
+ int dbl1 = 0;
+ int dbl2 = 0;
+
+ typ1 = cur_symtyps->types[indx1];
+ typ2 = cur_symtyps->types[indx2];
+
+ /*
+ * First see what might result if you do a convert to numeric on each
+ * variable.
+ */
+ if (bitset(typ1, int_bit))
+ int1 = 1;
+ if (bitset(typ1, real_bit))
+ dbl1 = 1;
+ if (bitset(typ1, str_bit) || bitset(typ1, cset_bit)) {
+ int1 = 1;
+ dbl1 = 1;
+ }
+ if (bitset(typ2, int_bit))
+ int2 = 1;
+ if (bitset(typ2, real_bit))
+ dbl2 = 1;
+ if (bitset(typ2, str_bit) || bitset(typ2, cset_bit)) {
+ int2 = 1;
+ dbl2 = 1;
+ }
+
+ /*
+ * Use the conversion information to figure out what type of arithmetic
+ * might be done.
+ */
+ if (int1 && int2)
+ *maybe_int = 1;
+ else
+ *maybe_int = 0;
+
+ *maybe_dbl = 0;
+ if (dbl1 && dbl2)
+ *maybe_dbl = 1;
+ else if (dbl1 && int2)
+ *maybe_dbl = 1;
+ else if (int1 && dbl2)
+ *maybe_dbl = 1;
+ }
+
+/*
+ * type_case - Determine which cases are selected in a type_case
+ * statement. This routine is used by both type inference and
+ * the code generator: a different fnc is passed in each case.
+ * In addition, the code generator passes a case_anlz structure.
+ */
+int type_case(il, fnc, case_anlz)
+struct il_code *il;
+int (*fnc)();
+struct case_anlz *case_anlz;
+ {
+ int *typ_vect;
+ int i, j;
+ int num_cases;
+ int num_types;
+ int indx;
+ int sym_indx;
+ int typcd;
+ int use_dflt;
+#ifdef OptimizeType
+ struct typinfo *typ;
+#else /* OptimizeType */
+ unsigned int *typ;
+#endif /* OptimizeType */
+ int select;
+ struct type *wktyp;
+
+ /*
+ * Make a copy of the type of the variable the type case is
+ * working on.
+ */
+ sym_indx = il->u[0].fld->u[0].n; /* symbol table index */
+ if (sym_indx >= cur_symtyps->nsyms)
+ typ = any_typ; /* variable is not a parameter, don't know type */
+ else
+ typ = cur_symtyps->types[sym_indx];
+ wktyp = get_wktyp();
+ CpyTyp(n_intrtyp, typ, wktyp->bits);
+ typ = wktyp->bits;
+
+ /*
+ * Loop through all the case clauses.
+ */
+ num_cases = il->u[1].n;
+ indx = 2;
+ for (i = 0; i < num_cases; ++i) {
+ /*
+ * For each of the types selected by this clause, see if the variable's
+ * type bit vector contains that type and delete the type from the
+ * bit vector (so we know if we need the default when we are done).
+ */
+ num_types = il->u[indx++].n;
+ typ_vect = il->u[indx++].vect;
+ select = 0;
+ for (j = 0; j < num_types; ++j)
+ if (has_type(typ, typ_vect[j], 1)) {
+ typcd = typ_vect[j];
+ select += 1;
+ }
+
+ if (select > 0) {
+ fnc(il->u[indx].fld); /* action */
+
+ /*
+ * If this routine was called by the code generator, we need to
+ * return extra information.
+ */
+ if (case_anlz != NULL) {
+ ++case_anlz->n_cases;
+ if (select == 1) {
+ if (case_anlz->il_then == NULL) {
+ case_anlz->typcd = typcd;
+ case_anlz->il_then = il->u[indx].fld;
+ }
+ else if (case_anlz->il_else == NULL)
+ case_anlz->il_else = il->u[indx].fld;
+ }
+ else {
+ /*
+ * There is more than one possible type that will cause
+ * us to select this case. It can only be used in the "else".
+ */
+ if (case_anlz->il_else == NULL)
+ case_anlz->il_else = il->u[indx].fld;
+ else
+ case_anlz->n_cases = 3; /* force no inlining. */
+ }
+ }
+ }
+ ++indx;
+ }
+
+ /*
+ * If there are types that have not been handled, indicate this by
+ * returning the index of the default clause.
+ */
+ use_dflt = 0;
+ for (i = 0; i < n_intrtyp; ++i)
+ if (bitset(typ, i)) {
+ use_dflt = 1;
+ break;
+ }
+ free_wktyp(wktyp);
+ if (use_dflt)
+ return indx;
+ else
+ return -1;
+ }
+
+/*
+ * gen_inv - general invocation. The argument list is set up, perform
+ * abstract interpretation on each possible things being invoked.
+ */
+static void gen_inv(typ, n)
+#ifdef OptimizeType
+struct typinfo *typ;
+#else /* OptimizeType */
+unsigned int *typ;
+#endif /* OptimizeType */
+nodeptr n;
+ {
+ int ret_flag = 0;
+ struct store *s_store;
+ struct store *store;
+ struct gentry *gptr;
+ struct implement *ip;
+ struct type *prc_typ;
+ int frst_prc;
+ int num_prcs;
+ int i;
+
+#ifdef TypTrc
+ if (trcfile != NULL) {
+ fprintf(trcfile, "%s (%d,%d) {\n", n->n_file, n->n_line, n->n_col);
+ trc_indent = " ";
+ }
+#endif /* TypTrc */
+
+ frst_prc = type_array[proc_typ].frst_bit;
+ num_prcs = type_array[proc_typ].num_bits;
+
+ /*
+ * Dereference the type of the thing being invoked.
+ */
+ prc_typ = get_wktyp();
+ typ_deref(typ, prc_typ->bits, 0);
+
+ s_store = succ_store;
+ store = get_store(1);
+
+ if (bitset(prc_typ->bits, str_bit) ||
+ bitset(prc_typ->bits, cset_bit) ||
+ bitset(prc_typ->bits, int_bit) ||
+ bitset(prc_typ->bits, real_bit)) {
+ /*
+ * Assume integer invocation; any argument may be the result type.
+ */
+
+#ifdef TypTrc
+ if (trcfile != NULL) {
+ fprintf(trcfile, "%s (%d,%d) %s{i}(", n->n_file, n->n_line, n->n_col,
+ trc_indent);
+ }
+#endif /* TypTrc */
+
+ for (i = 0; i < num_args; ++i) {
+ MrgTyp(n_intrtyp, arg_typs->types[i], n->type);
+
+#ifdef TypTrc
+ if (trcfile != NULL) {
+ if (i > 0)
+ fprintf(trcfile, ", ");
+ prt_typ(trcfile, arg_typs->types[i]);
+ }
+#endif /* TypTrc */
+
+ }
+
+ /*
+ * Integer invocation may succeed or fail.
+ */
+ ret_flag |= DoesRet | DoesFail;
+ mrg_store(s_store, store);
+ mrg_store(s_store, fail_store);
+
+#ifdef TypTrc
+ if (trcfile != NULL) {
+ fprintf(trcfile, ") =>> ");
+ prt_typ(trcfile, n->type);
+ fprintf(trcfile, "\n");
+ }
+#endif /* TypTrc */
+ }
+
+ if (bitset(prc_typ->bits, str_bit) ||
+ bitset(prc_typ->bits, cset_bit)) {
+ /*
+ * Assume string invocation; add all procedure types to the thing
+ * being invoked.
+ */
+ for (i = 0; i < num_prcs; ++i)
+ set_typ(prc_typ->bits, frst_prc + i);
+ }
+
+ if (bitset(prc_typ->bits, frst_prc)) {
+ /*
+ * First procedure type represents all operators that are
+ * available via string invocation. Scan the operator table
+ * looking for those that are in the string invocation table.
+ * Note, this is not particularly efficient or precise.
+ */
+ for (i = 0; i < IHSize; ++i)
+ for (ip = ohash[i]; ip != NULL; ip = ip->blink)
+ if (ip->iconc_flgs & InStrTbl) {
+ succ_store = cpy_store(s_store);
+ infer_impl(ip, n, n->symtyps, n->type);
+ ret_flag |= ip->ret_flag;
+ mrg_store(succ_store, store);
+ free_store(succ_store);
+ }
+ }
+
+ /*
+ * Check for procedure, built-in, and record constructor types
+ * and perform type inference on invocations of them.
+ */
+ for (i = 1; i < num_prcs; ++i)
+ if (bitset(prc_typ->bits, frst_prc + i)) {
+ succ_store = cpy_store(s_store);
+ gptr = proc_map[i];
+ switch (gptr->flag & (F_Proc | F_Builtin | F_Record)) {
+ case F_Proc:
+ infer_prc(gptr->val.proc, n);
+ ret_flag |= gptr->val.proc->ret_flag;
+ break;
+ case F_Builtin:
+ infer_impl(gptr->val.builtin, n, n->symtyps, n->type);
+ ret_flag |= gptr->val.builtin->ret_flag;
+ break;
+ case F_Record:
+ infer_con(gptr->val.rec, n);
+ ret_flag |= DoesRet | (err_conv ? DoesFail : 0);
+ break;
+ }
+ mrg_store(succ_store, store);
+ free_store(succ_store);
+ }
+
+ /*
+ * If error conversion is supported and a non-procedure value
+ * might be invoked, assume the invocation can fail.
+ */
+ if (err_conv && other_type(prc_typ->bits, proc_typ))
+ mrg_store(s_store, fail_store);
+
+ free_store(s_store);
+ succ_store = store;
+ chk_succ(ret_flag, n->store);
+
+ free_wktyp(prc_typ);
+
+#ifdef TypTrc
+ if (trcfile != NULL) {
+ fprintf(trcfile, "%s (%d,%d) }\n", n->n_file, n->n_line, n->n_col);
+ trc_indent = "";
+ }
+#endif /* TypTrc */
+ }
+
+/*
+ * get_wktyp - get a dynamically allocated bit vector to use as a
+ * work area for doing type computations.
+ */
+static struct type *get_wktyp()
+ {
+ struct type *typ;
+
+ if ((typ = type_pool) == NULL) {
+ typ = NewStruct(type);
+ typ->size = n_rttyp;
+ typ->bits = alloc_typ(n_rttyp);
+ }
+ else {
+ type_pool = type_pool->next;
+ ClrTyp(n_rttyp, typ->bits);
+ }
+ return typ;
+ }
+
+/*
+ * free_wktyp - free a dynamically allocated type bit vector.
+ */
+static void free_wktyp(typ)
+struct type *typ;
+ {
+ typ->next = type_pool;
+ type_pool = typ;
+ }
+
+#ifdef TypTrc
+
+/*
+ * ChkSep - supply a separating space if this is not the first item.
+ */
+#define ChkSep(n) (++n > 1 ? " " : "")
+
+/*
+ * prt_typ - print a type that can include variable references.
+ */
+static void prt_typ(file, typ)
+FILE *file;
+#ifdef OptimizeType
+struct typinfo *typ;
+#else /* OptimizeType */
+unsigned int *typ;
+#endif /* OptimizeType */
+ {
+ struct gentry *gptr;
+ struct lentry *lptr;
+ char *name;
+ int i, j, k;
+ int n;
+ int frst_bit;
+ int num_bits;
+ char *abrv;
+
+ fprintf(trcfile, "{");
+ n = 0;
+ /*
+ * Go through the types and see any sub-types are present.
+ */
+ for (k = 0; k < num_typs; ++k) {
+ frst_bit = type_array[k].frst_bit;
+ num_bits = type_array[k].num_bits;
+ abrv = icontypes[k].abrv;
+ if (k == proc_typ) {
+ /*
+ * procedures, record constructors, and built-in functions.
+ */
+ for (i = 0; i < num_bits; ++i)
+ if (bitset(typ, frst_bit + i)) {
+ if (i == 0)
+ fprintf(file, "%sops", ChkSep(n));
+ else {
+ gptr = proc_map[i];
+ switch (gptr->flag & (F_Proc | F_Builtin | F_Record)) {
+ case F_Proc:
+ fprintf(file, "%s%s:%s", ChkSep(n), abrv, gptr->name);
+ break;
+ case F_Builtin:
+ fprintf(file, "%sfnc:%s", ChkSep(n), gptr->name);
+ break;
+ case F_Record:
+ fprintf(file, "%sconstr:%s", ChkSep(n), gptr->name);
+ break;
+ }
+ }
+ }
+ }
+ else if (k == rec_typ) {
+ /*
+ * records - include record name.
+ */
+ for (i = 0; i < num_bits; ++i)
+ if (bitset(typ, frst_bit + i))
+ fprintf(file, "%s%s:%s", ChkSep(n), abrv, rec_map[i]->name);
+ }
+ else if (icontypes[k].support_new | k == coexp_typ) {
+ /*
+ * A type with sub-types.
+ */
+ for (i = 0; i < num_bits; ++i)
+ if (bitset(typ, frst_bit + i))
+ fprintf(file, "%s%s%d", ChkSep(n), abrv, i);
+ }
+ else {
+ /*
+ * A type with no subtypes.
+ */
+ if (bitset(typ, frst_bit))
+ fprintf(file, "%s%s", ChkSep(n), abrv);
+ }
+ }
+
+ for (k = 0; k < num_cmpnts; ++k) {
+ if (typecompnt[k].var) {
+ /*
+ * Structure component that is a variable.
+ */
+ frst_bit = compnt_array[k].frst_bit;
+ num_bits = compnt_array[k].num_bits;
+ abrv = typecompnt[k].abrv;
+ for (i = 0; i < num_bits; ++i)
+ if (bitset(typ, frst_bit + i))
+ fprintf(file, "%s%s%d", ChkSep(n), abrv, i);
+ }
+ }
+
+
+ /*
+ * record fields
+ */
+ for (i = 0; i < n_fld; ++i)
+ if (bitset(typ, frst_fld + i))
+ fprintf(file, "%sfld%d", ChkSep(n), i);
+
+ /*
+ * global variables
+ */
+ for (i = 0; i < n_nmgbl; ++i)
+ if (bitset(typ, frst_gbl + i)) {
+ name = NULL;
+ for (j = 0; j < GHSize && name == NULL; j++)
+ for (gptr = ghash[j]; gptr != NULL && name == NULL;
+ gptr = gptr->blink)
+ if (gptr->index == i)
+ name = gptr->name;
+ for (lptr = cur_proc->statics; lptr != NULL && name == NULL;
+ lptr = lptr->next)
+ if (lptr->val.index == i)
+ name = lptr->name;
+ /*
+ * Static variables may be returned and dereferenced in a procedure
+ * they don't belong to.
+ */
+ if (name == NULL)
+ name = "?static?";
+ fprintf(file, "%svar:%s", ChkSep(n), name);
+ }
+
+ /*
+ * local variables
+ */
+ for (i = 0; i < n_loc; ++i)
+ if (bitset(typ, frst_loc + i)) {
+ name = NULL;
+ for (lptr = cur_proc->args; lptr != NULL && name == NULL;
+ lptr = lptr->next)
+ if (lptr->val.index == i)
+ name = lptr->name;
+ for (lptr = cur_proc->dynams; lptr != NULL && name == NULL;
+ lptr = lptr->next)
+ if (lptr->val.index == i)
+ name = lptr->name;
+ /*
+ * Local variables types may appear in the wrong procedure due to
+ * substring trapped variables and the inference of impossible
+ * execution paths. Make sure we don't end up with a NULL name.
+ */
+ if (name == NULL)
+ name = "?";
+ fprintf(file, "%svar:%s", ChkSep(n), name);
+ }
+
+ fprintf(trcfile, "}");
+ }
+
+/*
+ * prt_d_typ - dereference a type and print it.
+ */
+static void prt_d_typ(file, typ)
+FILE *file;
+#ifdef OptimizeType
+struct typinfo *typ;
+#else /* OptimizeType */
+unsigned int *typ;
+#endif /* OptimizeType */
+{
+ struct type *wktyp;
+
+ wktyp = get_wktyp();
+ typ_deref(typ, wktyp->bits, 0);
+ prt_typ(file, wktyp->bits);
+ free_wktyp(wktyp);
+}
+#endif /* TypTrc */
+
+/*
+ * get_argtyp - get an array of pointers to type bit vectors for use
+ * in constructing an argument list. The array is large enough for the
+ * largest argument list.
+ */
+static struct argtyps *get_argtyp()
+ {
+ struct argtyps *argtyps;
+
+ if ((argtyps = argtyp_pool) == NULL)
+#ifdef OptimizeType
+ argtyps = (struct argtyps *)alloc((unsigned int)(sizeof(struct argtyps) +
+ ((max_prm - 1) * sizeof(struct typinfo *))));
+#else /* OptimizeType */
+ argtyps = (struct argtyps *)alloc((unsigned int)(sizeof(struct argtyps) +
+ ((max_prm - 1) * sizeof(unsigned int *))));
+#endif /* OptimizeType */
+ else
+ argtyp_pool = argtyp_pool->next;
+ return argtyps;
+ }
+
+/*
+ * free_argtyp - free array of pointers to type bitvectors.
+ */
+static void free_argtyp(argtyps)
+struct argtyps *argtyps;
+ {
+ argtyps->next = argtyp_pool;
+ argtyp_pool = argtyps;
+ }
+
+/*
+ * varsubtyp - examine a type and determine what kinds of variable
+ * subtypes it has and whether it has any non-variable subtypes.
+ * If the type consists of a single named variable, return its symbol
+ * table entry through the parameter "singl".
+ */
+int varsubtyp(typ, singl)
+#ifdef OptimizeType
+struct typinfo *typ;
+#else /* OptimizeType */
+unsigned int *typ;
+#endif /* OptimizeType */
+struct lentry **singl;
+ {
+ struct store *stv_stor;
+ int subtypes;
+ int n_types;
+ int var_indx;
+ int frst_bit;
+ int num_bits;
+ int i, j;
+
+
+ subtypes = 0;
+ n_types = 0;
+ var_indx = -1;
+
+ /*
+ * check for non-variables.
+ */
+ for (i = 0; i < n_icntyp; ++i)
+ if (bitset(typ, i)) {
+ subtypes |= HasVal;
+ ++n_types;
+ }
+
+ /*
+ * Predefined variable types.
+ */
+ for (i = 0; i < num_typs; ++i) {
+ if (icontypes[i].deref != DrfNone) {
+ frst_bit = type_array[i].frst_bit;
+ num_bits = type_array[i].num_bits;
+ for (j = 0; j < num_bits; ++j) {
+ if (bitset(typ, frst_bit + j)) {
+ if (i == stv_typ) {
+ /*
+ * We have found substring trapped variable j, see whether it
+ * references locals or globals.
+ */
+ if (do_typinfer) {
+ stv_stor = compnt_array[str_var].store;
+ subtypes |= varsubtyp(stv_stor->types[j], NULL);
+ }
+ else
+ subtypes |= HasLcl | HasPrm | HasGlb;
+ }
+ else
+ subtypes |= HasGlb;
+ ++n_types;
+ }
+ }
+ }
+ }
+
+ /*
+ * Aggregate compontents that are variables.
+ */
+ for (i = 0; i < num_cmpnts; ++i) {
+ if (typecompnt[i].var) {
+ frst_bit = compnt_array[i].frst_bit;
+ num_bits = compnt_array[i].num_bits;
+ for (j = 0; j < num_bits; ++j) {
+ if (bitset(typ, frst_bit + j)) {
+ subtypes |= HasGlb;
+ ++n_types;
+ }
+ }
+ }
+ }
+
+ /*
+ * record fields
+ */
+ for (i = 0; i < n_fld; ++i)
+ if (bitset(typ, frst_fld + i)) {
+ subtypes |= HasGlb;
+ ++n_types;
+ }
+
+ /*
+ * global variables, including statics
+ */
+ for (i = 0; i < n_gbl; ++i) {
+ if (bitset(typ, frst_gbl + i)) {
+ subtypes |= HasGlb;
+ var_indx = i;
+ ++n_types;
+ }
+ }
+
+ /*
+ * local variables
+ */
+ for (i = 0; i < n_loc; ++i) {
+ if (bitset(typ, frst_loc + i)) {
+ if (i < Abs(cur_proc->nargs))
+ subtypes |= HasPrm;
+ else
+ subtypes |= HasLcl;
+ var_indx = n_gbl + i;
+ ++n_types;
+ }
+ }
+
+ if (singl != NULL) {
+ /*
+ * See if the type consists of a single named variable.
+ */
+ if (n_types == 1 && var_indx != -1)
+ *singl = cur_proc->vartypmap[var_indx];
+ else
+ *singl = NULL;
+ }
+
+ return subtypes;
+ }
+
+/*
+ * mark_recs - go through the list of parent records for this field
+ * and mark those that are in the type. Also gather information
+ * to help generate better code.
+ */
+void mark_recs(fp, typ, num_offsets, offset, bad_recs)
+struct fentry *fp;
+#ifdef OptimizeType
+struct typinfo *typ;
+#else /* OptimizeType */
+unsigned int *typ;
+#endif /* OptimizeType */
+int *num_offsets;
+int *offset;
+int *bad_recs;
+ {
+ struct par_rec *rp;
+ struct type *wktyp;
+ int frst_rec;
+
+ *num_offsets = 0;
+ *offset = -1;
+ *bad_recs = 0;
+
+ wktyp = get_wktyp();
+ CpyTyp(n_icntyp, typ, wktyp->bits);
+
+ /*
+ * For each record containing this field, see if the record is
+ * in the type.
+ */
+ frst_rec = type_array[rec_typ].frst_bit;
+ for (rp = fp->rlist; rp != NULL; rp = rp->next) {
+ if (bitset(wktyp->bits, frst_rec + rp->rec->rec_num)) {
+ /*
+ * This record is in the type.
+ */
+ rp->mark = 1;
+ clr_typ(wktyp->bits, frst_rec + rp->rec->rec_num);
+ if (*offset != rp->offset) {
+ *offset = rp->offset;
+ *num_offsets += 1;
+ }
+ }
+ }
+
+ /*
+ * Are there any records that do not contain this field?
+ */
+ *bad_recs = has_type(wktyp->bits, rec_typ, 0);
+ free_wktyp(wktyp);
+ }
+
+/*
+ * past_prms - return true if execution might continue past the parameter
+ * evaluation. If a parameter has no type, this will not happen.
+ */
+int past_prms(n)
+nodeptr n;
+ {
+ struct implement *impl;
+ struct symtyps *symtyps;
+ int nparms;
+ int nargs;
+ int flag;
+ int i, j;
+
+ nargs = Val0(n);
+ impl = Impl1(n);
+ symtyps = n->symtyps;
+ nparms = impl->nargs;
+
+ if (symtyps == NULL)
+ return 1;
+
+ j = 0;
+ for (i = 0; i < nparms; ++i) {
+ flag = impl->arg_flgs[i];
+ if (flag & VarPrm && i >= nargs)
+ break; /* no parameters for variable part of arg list */
+ if (flag & RtParm) {
+ if (is_empty(symtyps->types[j]))
+ return 0;
+ ++j;
+ }
+ if (flag & DrfPrm) {
+ if (is_empty(symtyps->types[j]))
+ return 0;
+ ++j;
+ }
+ }
+ return 1;
+ }