summaryrefslogtreecommitdiff
path: root/src/iconc/ccode.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/iconc/ccode.c')
-rw-r--r--src/iconc/ccode.c4954
1 files changed, 0 insertions, 4954 deletions
diff --git a/src/iconc/ccode.c b/src/iconc/ccode.c
deleted file mode 100644
index 108cd15..0000000
--- a/src/iconc/ccode.c
+++ /dev/null
@@ -1,4954 +0,0 @@
-/*
- * 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;
- }
- }