home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / icon / historic / v92.tgz / v92.tar / v92 / src / iconc / ccode.c next >
C/C++ Source or Header  |  1996-03-22  |  135KB  |  4,470 lines

  1. /*
  2.  * ccode.c - routines to produce internal representation of C code.
  3.  */
  4. #include "::h:gsupport.h"
  5. #include "::h:lexdef.h"
  6. #include "ctrans.h"
  7. #include "cglobals.h"
  8. #include "csym.h"
  9. #include "ccode.h"
  10. #include "ctree.h"
  11. #include "ctoken.h"
  12. #include "cproto.h"
  13.  
  14. /*
  15.  * Prototypes for static functions.
  16.  */
  17. hidden struct c_fnc   *alc_fnc   Params((noargs));
  18. hidden struct tmplftm *alc_lftm  Params((int num, union field *args));
  19. hidden int             alc_tmp   Params((int n, struct tmplftm *lifetm_ary));
  20. hidden struct code    *asgn_null Params((struct val_loc *loc1));
  21. hidden struct val_loc *bound     Params((struct node *n, struct val_loc *rslt,
  22.                                    int catch_fail));
  23. hidden struct code    *check_var Params((struct val_loc *d, struct code *lbl));
  24. hidden novalue         deref_cd  Params((struct val_loc *src,
  25.                                    struct val_loc *dest));
  26. hidden novalue         deref_ret Params((struct val_loc *src,
  27.                                    struct val_loc *dest, int subtypes));
  28. hidden novalue         endlife   Params((int kind, int indx, int old,
  29.                                    nodeptr n));
  30. hidden struct val_loc *field_ref Params((struct node *n, struct val_loc *rslt));
  31. hidden struct val_loc *gen_act   Params((nodeptr n, struct val_loc *rslt));
  32. hidden struct val_loc *gen_apply Params((struct node *n, struct val_loc *rslt));
  33. hidden struct val_loc *gen_args  Params((struct node *n, int frst_arg,
  34.                                    int nargs));
  35. hidden struct val_loc *gen_case  Params((struct node *n, struct val_loc *rslt));
  36. hidden struct val_loc *gen_creat Params((struct node *n, struct val_loc *rslt));
  37. hidden struct val_loc *gen_lim   Params((struct node *n, struct val_loc *rslt));
  38. hidden struct val_loc *gen_scan  Params((struct node *n, struct val_loc *rslt));
  39. hidden struct val_loc *gencode   Params((struct node *n, struct val_loc *rslt));
  40. hidden struct val_loc *genretval Params((struct node *n, struct node *expr,
  41.                                    struct val_loc *dest));
  42. hidden struct val_loc *inv_prc   Params((nodeptr n, struct val_loc *rslt));
  43. hidden struct val_loc *inv_op    Params((nodeptr n, struct val_loc *rslt));
  44. hidden nodeptr         max_lftm  Params((nodeptr n1, nodeptr n2));
  45. hidden novalue         mk_callop Params((char *oper_nm, int ret_flag,
  46.                                    struct val_loc *arg1rslt, int nargs,
  47.                                    struct val_loc *rslt, int optim));
  48. hidden struct code    *mk_cpyval Params((struct val_loc *loc1,
  49.                                    struct val_loc *loc2));
  50. hidden struct code    *new_call  Params((noargs));
  51. hidden char           *oper_name Params((struct implement *impl));
  52. hidden novalue         restr_env Params((struct val_loc *sub_sav,
  53.                                     struct val_loc *pos_sav));
  54. hidden novalue         save_env  Params((struct val_loc *sub_sav,
  55.                                    struct val_loc *pos_sav));
  56. hidden novalue         setloc    Params((nodeptr n));
  57. hidden struct val_loc *tmp_loc   Params((int n));
  58. hidden struct val_loc *var_ref   Params((struct lentry *sym));
  59. hidden struct val_loc *vararg_sz Params((int n));
  60.  
  61. #define FrstArg 2
  62.  
  63. /*
  64.  * Information that must be passed between a loop and its next and break
  65.  *   expressions.
  66.  */
  67. struct loop_info {
  68.    struct code *next_lbl;       /* where to branch for a next expression */
  69.    struct code *end_loop;       /* label at end of loop */
  70.    struct code *on_failure;     /* where to go if the loop fails */
  71.    struct scan_info *scan_info; /* scanning environment upon entering loop */
  72.    struct val_loc *rslt;        /* place to put result of loop */
  73.    struct c_fnc *succ_cont;     /* the success continuation for the loop */
  74.    struct loop_info *prev;      /* link to info for outer loop */
  75.    };
  76.  
  77. /*
  78.  * The allocation status of a temporary variable can either be "in use",
  79.  *  "not allocated", or reserved for use at a code position (indicated
  80.  *  by a specific negative number).
  81.  */
  82. #define InUse 1
  83. #define NotAlc 0
  84.  
  85. /*
  86.  * tmplftm is used to precompute lifetime information for use in allocating
  87.  *  temporary variables.
  88.  */
  89. struct tmplftm {
  90.    int cur_status;
  91.    nodeptr lifetime;
  92.    };
  93.  
  94. /*
  95.  * Places where &subject and &pos are saved during string scanning. "outer"
  96.  *  values are saved when the scanning expression is executed. "inner"
  97.  *  values are saved when the scanning expression suspends.
  98.  */
  99. struct scan_info {
  100.    struct val_loc *outer_sub;
  101.    struct val_loc *outer_pos;
  102.    struct val_loc *inner_sub;
  103.    struct val_loc *inner_pos;
  104.    struct scan_info *next;
  105.    };
  106.  
  107. struct scan_info scan_base = {NULL, 0, NULL, 0, NULL};
  108. struct scan_info *nxt_scan = &scan_base;
  109.  
  110. struct val_loc ignore;         /* no values, just something to point at */
  111. static struct val_loc proc_rslt; /* result location for procedure */
  112.  
  113. int *tmp_status = NULL;      /* allocation status of temp descriptor vars */
  114. int *itmp_status = NULL;     /* allocation status of temp C int vars*/
  115. int *dtmp_status = NULL;     /* allocation status of temp C double vars */
  116. int *sbuf_status = NULL;     /* allocation of string buffers */
  117. int *cbuf_status = NULL;     /* allocation of cset buffers */
  118. int num_tmp;                 /* number of temp descriptors actually used */
  119. int num_itmp;                /* number of temp C ints actually used */
  120. int num_dtmp;                /* number of temp C doubles actually used */
  121. int num_sbuf;                /* number of string buffers actually used */
  122. int num_cbuf;                /* number of cset buffers actually used */
  123. int status_sz = 20;          /* current size of tmp_status array */
  124. int istatus_sz = 20;         /* current size of itmp_status array */
  125. int dstatus_sz = 20;         /* current size of dtmp_status array */
  126. int sstatus_sz = 20;         /* current size of sbuf_status array */
  127. int cstatus_sz = 20;         /* current size of cbuf_status array */
  128. struct freetmp *freetmp_pool = NULL;
  129.  
  130. static char frm_prfx[PrfxSz + 1];/* prefix for procedure frame */
  131. static char *lastfiln;         /* last file name set in code */
  132. static int lastline;         /* last line number set in code */
  133.  
  134. static struct c_fnc *fnc_lst;    /* list of C functions implementing proc */
  135. static struct c_fnc **flst_end; /* pointer to null pointer at end of fnc_lst */
  136. struct c_fnc *cur_fnc;       /* C function currently being built */
  137. static int create_lvl = 0;      /* co-expression create level */
  138.  
  139. struct pentry *cur_proc;        /* procedure currently being translated */
  140.  
  141. struct code *on_failure;    /* place to go on failure */
  142.  
  143. static struct code *p_ret_lbl;   /* label for procedure return */
  144. static struct code *p_fail_lbl;  /* label for procedure fail */
  145. struct code *bound_sig;        /* bounding signal for current procedure */
  146.  
  147. /*
  148.  * statically declared "signals".
  149.  */
  150. struct code resume;
  151. struct code contin;
  152. struct code fallthru;
  153. struct code next_fail;
  154.  
  155. int lbl_seq_num = 0;  /* next label sequence number */
  156.  
  157. /*
  158.  * proccode - generate code for a procedure.
  159.  */
  160. novalue proccode(proc)
  161. struct pentry *proc;
  162.    {
  163.    struct c_fnc *fnc;
  164.    struct code *cd;
  165.    struct code *cd1;
  166.    struct code *lbl;
  167.    nodeptr n;
  168.    nodeptr failer;
  169.    int gen;
  170.    int i;
  171.  
  172.    /*
  173.     * Initialize arrays used for allocating temporary variables.
  174.     */
  175.    if (tmp_status == NULL)
  176.       tmp_status = (int *)alloc((unsigned int)(status_sz * sizeof(int)));
  177.    if (itmp_status == NULL)
  178.       itmp_status = (int *)alloc((unsigned int)(istatus_sz * sizeof(int)));
  179.    if (dtmp_status == NULL)
  180.       dtmp_status = (int *)alloc((unsigned int)(dstatus_sz * sizeof(int)));
  181.    if (sbuf_status == NULL)
  182.       sbuf_status = (int *)alloc((unsigned int)(sstatus_sz * sizeof(int)));
  183.    if (cbuf_status == NULL)
  184.       cbuf_status = (int *)alloc((unsigned int)(cstatus_sz * sizeof(int)));
  185.    for (i = 0; i < status_sz; ++i)
  186.       tmp_status[i] = NotAlloc;
  187.    for (i = 0; i < istatus_sz; ++i)
  188.       itmp_status[i] = NotAlloc;
  189.    for (i = 0; i < dstatus_sz; ++i)
  190.       dtmp_status[i] = NotAlloc;
  191.    for (i = 0; i < sstatus_sz; ++i)
  192.       sbuf_status[i] = NotAlloc;
  193.    for (i = 0; i < cstatus_sz; ++i)
  194.       cbuf_status[i] = NotAlloc;
  195.    num_tmp = 0;
  196.    num_itmp = 0;
  197.    num_dtmp = 0;
  198.    num_sbuf = 0;
  199.    num_cbuf = 0;
  200.  
  201.    /*
  202.     * Initialize standard signals.
  203.     */
  204.    resume.cd_id = C_Resume;
  205.    contin.cd_id = C_Continue;
  206.    fallthru.cd_id = C_FallThru;
  207.  
  208.    /*
  209.     * Initialize procedure result and the transcan locations.
  210.     */
  211.    proc_rslt.loc_type = V_PRslt;
  212.    proc_rslt.mod_access = M_None;
  213.    ignore.loc_type = V_Ignore;
  214.    ignore.mod_access = M_None;
  215.  
  216.    cur_proc = proc;  /* current procedure */
  217.    lastfiln = NULL;  /* file name */
  218.    lastline = 0;     /* line number */
  219.  
  220.    /*
  221.     * Procedure frame prefix is the procedure prefix.
  222.     */
  223.    for (i = 0; i < PrfxSz; ++i)
  224.       frm_prfx[i] = cur_proc->prefix[i];
  225.    frm_prfx[PrfxSz] = '\0';
  226.  
  227.    /*
  228.     * Initialize the continuation list and allocate the outer function for
  229.     *  this procedure.
  230.     */
  231.    fnc_lst = NULL;
  232.    flst_end = &fnc_lst;
  233.    cur_fnc = alc_fnc();
  234.  
  235.    /*
  236.     * If the procedure is not used anywhere don't generate code for it.
  237.     *  This can happen when using libraries containing several procedures,
  238.     *  but not all are needed. However, if there is a block for the
  239.     *  procedure, we need at least a dummy function.
  240.     */
  241.    if (!cur_proc->reachable) {
  242.       if (!(glookup(cur_proc->name)->flag & F_SmplInv))
  243.          outerfnc(fnc_lst);
  244.       return;
  245.       }
  246.  
  247.    /*
  248.     * Allocate labels for the code for procedure failure, procedure return,
  249.     *  and allocate the bounding signal for this procedure (at this point
  250.     *  signals and labels are not distinguished).
  251.     */
  252.    p_fail_lbl = alc_lbl("proc fail", 0);
  253.    p_ret_lbl = alc_lbl("proc return", 0);
  254.    bound_sig = alc_lbl("bound", 0);
  255.  
  256.    n = proc->tree;
  257.    setloc(n);
  258.    if (Type(Tree1(n)) != N_Empty) {
  259.       /*
  260.        * initial clause.
  261.        */
  262.       Tree1(n)->lifetime = NULL;
  263.       liveness(Tree1(n), NULL, &failer, &gen);
  264.       if (tfatals > 0)
  265.          return;
  266.       lbl = alc_lbl("end initial", 0);
  267.       cd_add(lbl);
  268.       cur_fnc->cursor = lbl->prev;        /* code goes before label */
  269.       cd = NewCode(2);
  270.       cd->cd_id = C_If;
  271.       cd1 = alc_ary(1);
  272.       cd1->ElemTyp(0) = A_Str;
  273.       cd1->Str(0) = "!first_time";
  274.       cd->Cond = cd1;
  275.       cd->ThenStmt = mk_goto(lbl);
  276.       cd_add(cd);
  277.       cd = alc_ary(1);
  278.       cd->ElemTyp(0) = A_Str;
  279.       cd->Str(0) = "first_time = 0;";
  280.       cd_add(cd);
  281.       bound(Tree1(n), &ignore, 1);
  282.       cur_fnc->cursor = lbl;
  283.       }
  284.    Tree2(n)->lifetime = NULL;
  285.    liveness(Tree2(n), NULL, &failer, &gen);
  286.    if (tfatals > 0)
  287.       return;
  288.    bound(Tree2(n), &ignore, 1);
  289.  
  290.    /*
  291.     * Place code to perform procedure failure and return and the
  292.     *  end of the outer function.
  293.     */
  294.    setloc(Tree3(n));
  295.    cd_add(p_fail_lbl);
  296.    cd = NewCode(0);
  297.    cd->cd_id = C_PFail;
  298.    cd_add(cd);
  299.    cd_add(p_ret_lbl);
  300.    cd = NewCode(0);
  301.    cd->cd_id = C_PRet;
  302.    cd_add(cd);
  303.  
  304.    /*
  305.     * Fix up signal handling code and perform peephole optimizations.
  306.     */
  307.    fix_fncs(fnc_lst);
  308.  
  309.    /*
  310.     * The outer function is the first one on the list. It has the
  311.     *  procedure interface; the others are just continuations.
  312.     */
  313.    outerfnc(fnc_lst);
  314.    for (fnc = fnc_lst->next; fnc != NULL; fnc = fnc->next)
  315.       if (fnc->ref_cnt > 0)
  316.          prt_fnc(fnc);
  317.    }
  318.  
  319. /*
  320.  * gencode - generate code for a syntax tree.
  321.  */
  322. static struct val_loc *gencode(n, rslt)
  323. struct node *n;
  324. struct val_loc *rslt;
  325.    {
  326.    struct code *cd;
  327.    struct code *cd1;
  328.    struct code *fail_sav;
  329.    struct code *lbl1;
  330.    struct code *lbl2;
  331.    struct code *cursor_sav;
  332.    struct c_fnc *fnc_sav;
  333.    struct c_fnc *fnc;
  334.    struct implement *impl;
  335.    struct implement *impl1;
  336.    struct val_loc *r1[3];
  337.    struct val_loc *r2[2];
  338.    struct val_loc *frst_arg;
  339.    struct lentry *single;
  340.    struct freetmp *freetmp;
  341.    struct freetmp *ft;
  342.    struct tmplftm *lifetm_ary;
  343.    char *sbuf;
  344.    int i;
  345.    int tmp_indx;
  346.    int nargs;
  347.    static struct loop_info *loop_info = NULL;
  348.    struct loop_info *li_sav;
  349.  
  350.    switch (n->n_type) {
  351.       case N_Activat:
  352.          rslt = gen_act(n, rslt);
  353.          break;
  354.  
  355.       case N_Alt:
  356.          rslt = chk_alc(rslt, n->lifetime); /* insure a result location */
  357.  
  358.          fail_sav = on_failure;
  359.          fnc_sav = cur_fnc;
  360.  
  361.          /*
  362.           * If the first alternative fails, execution must go to the
  363.           *  "alt" label.
  364.           */
  365.          lbl1 = alc_lbl("alt", 0);
  366.          on_failure = lbl1;
  367.  
  368.          cd_add(lbl1);
  369.          cur_fnc->cursor = lbl1->prev;  /* 1st alternative goes before label */
  370.          gencode(Tree0(n), rslt);
  371.  
  372.          /*
  373.           * Each alternative must call the same success continuation.
  374.           */
  375.          fnc = alc_fnc();
  376.          callc_add(fnc);
  377.  
  378.          cur_fnc = fnc_sav;             /* return to the context of the label */
  379.          cur_fnc->cursor = lbl1;        /* 2nd alternative goes after label */
  380.          on_failure = fail_sav;         /* on failure, alternation fails */
  381.          gencode(Tree1(n), rslt);
  382.          callc_add(fnc);                /* call continuation */
  383.  
  384.          /*
  385.           * Code following the alternation goes in the continuation. If
  386.           *  the code fails, the continuation returns the resume signal.
  387.           */
  388.          cur_fnc = fnc;
  389.          on_failure = &resume;
  390.          break;
  391.  
  392.       case N_Apply:
  393.          rslt = gen_apply(n, rslt);
  394.          break;
  395.  
  396.       case N_Augop:
  397.          impl = Impl0(n);       /* assignment */
  398.          impl1 = Impl1(n);      /* the operation */
  399.          if (impl == NULL || impl1 == NULL) {
  400.             rslt = &ignore;    /* make sure code generation can continue */
  401.             break;
  402.             }
  403.  
  404.          /*
  405.           * allocate an argument list for the operation.
  406.           */
  407.          lifetm_ary = alc_lftm(2, &n->n_field[2]);
  408.          tmp_indx = alc_tmp(2, lifetm_ary);
  409.          r1[0] = tmp_loc(tmp_indx);
  410.          r1[1] = tmp_loc(tmp_indx + 1);
  411.  
  412.          gencode(Tree2(n), r1[0]);  /* first argument */
  413.  
  414.          /*
  415.           * allocate an argument list for the assignment and copy the
  416.           *  value of the first argument into it.
  417.           */
  418.          lifetm_ary[0].cur_status = InUse;
  419.          lifetm_ary[1].cur_status = n->postn;
  420.          lifetm_ary[1].lifetime = n->intrnl_lftm;
  421.          tmp_indx = alc_tmp(2, lifetm_ary);
  422.          r2[0] = tmp_loc(tmp_indx++);
  423.          cd_add(mk_cpyval(r2[0], r1[0]));
  424.          r2[1] = tmp_loc(tmp_indx);
  425.  
  426.          gencode(Tree3(n), r1[1]); /* second argument */
  427.  
  428.          /*
  429.           * Produce code for the operation.
  430.           */
  431.          setloc(n);
  432.          implproto(impl1);
  433.          mk_callop(oper_name(impl1), impl1->ret_flag, r1[0], 2, r2[1], 0);
  434.  
  435.          /*
  436.           * Produce code for the assignment.
  437.           */
  438.          implproto(impl);
  439.          if (impl->ret_flag & (DoesRet | DoesSusp))
  440.             rslt = chk_alc(rslt, n->lifetime);
  441.          mk_callop(oper_name(impl), impl->ret_flag, r2[0], 2, rslt, 0);
  442.  
  443.          free((char *)lifetm_ary);
  444.          break;
  445.  
  446.       case N_Bar: {
  447.          struct val_loc *fail_flg;
  448.  
  449.          /*
  450.           * Allocate an integer variable to keep track of whether the
  451.           *  repeated alternation should fail when execution reaches
  452.           *  the top of its loop, and generate code to initialize the
  453.           *  variable to 0.
  454.           */
  455.          fail_flg = itmp_loc(alc_itmp(n->intrnl_lftm));
  456.          cd = alc_ary(2);
  457.          cd->ElemTyp(0) = A_ValLoc;
  458.          cd->ValLoc(0) =                fail_flg;
  459.          cd->ElemTyp(1) = A_Str;
  460.          cd->Str(1) =                   " = 0;";
  461.          cd_add(cd);
  462.  
  463.          /*
  464.           * Code at the top of the repeated alternation loop checks
  465.           *  the failure flag.
  466.           */
  467.          lbl1 = alc_lbl("rep alt", 0);
  468.          cd_add(lbl1);
  469.          cd = NewCode(2);
  470.          cd->cd_id = C_If;
  471.          cd1 = alc_ary(1);
  472.          cd1->ElemTyp(0) = A_ValLoc;
  473.          cd1->ValLoc(0) = fail_flg;
  474.          cd->Cond = cd1;
  475.          cd->ThenStmt = sig_cd(on_failure, cur_fnc);
  476.          cd_add(cd);
  477.  
  478.          /*
  479.           * If the expression fails without producing a value, the
  480.           *  repeated alternation must fail.
  481.           */
  482.          cd = alc_ary(2);
  483.          cd->ElemTyp(0) = A_ValLoc;
  484.          cd->ValLoc(0) =                fail_flg;
  485.          cd->ElemTyp(1) = A_Str;
  486.          cd->Str(1) =                   " = 1;";
  487.          cd_add(cd);
  488.  
  489.          /*
  490.           * Generate code for the repeated expression. If it produces
  491.           *  a value before before backtracking occurs, the loop is
  492.           *  repeated as indicated by the value of the failure flag.
  493.           */
  494.          on_failure = lbl1;
  495.          rslt = gencode(Tree0(n), rslt);
  496.          cd = alc_ary(2);
  497.          cd->ElemTyp(0) = A_ValLoc;
  498.          cd->ValLoc(0) =                fail_flg;
  499.          cd->ElemTyp(1) = A_Str;
  500.          cd->Str(1) =                   " = 0;";
  501.          cd_add(cd);
  502.          }
  503.         break;
  504.  
  505.       case N_Break:
  506.          if (loop_info == NULL) {
  507.             nfatal(n, "invalid context for a break expression", NULL);
  508.             rslt = &ignore;
  509.             break;
  510.             }
  511.  
  512.          /*
  513.           * If the break is in a different string scanning context from the
  514.           *  loop itself, generate code to restore the scanning environment.
  515.           */
  516.          if (nxt_scan != loop_info->scan_info)
  517.             restr_env(loop_info->scan_info->outer_sub,
  518.                loop_info->scan_info->outer_pos);
  519.  
  520.  
  521.          if (Tree0(n)->n_type == N_Empty && loop_info->rslt == &ignore) {
  522.              /*
  523.               * The break has no associated expression and the loop needs
  524.               *  no value, so just branch out of the loop.
  525.               */
  526.              cd_add(sig_cd(loop_info->end_loop, cur_fnc));
  527.              }
  528.          else {
  529.             /*
  530.              * The code for the expression associated with the break is
  531.              *  actually placed at the end of the loop. Go there and
  532.              *  add a label to branch to.
  533.              */
  534.             cursor_sav = cur_fnc->cursor;
  535.             fnc_sav = cur_fnc;
  536.             fail_sav = on_failure;
  537.             cur_fnc = loop_info->end_loop->Container;
  538.             cur_fnc->cursor = loop_info->end_loop->prev;
  539.             on_failure = loop_info->on_failure;
  540.             lbl1 = alc_lbl("break", 0);
  541.             cd_add(lbl1);
  542.  
  543.             /*
  544.              * Make sure a result location has been allocated for the
  545.              *  loop, restore the loop information for the next outer
  546.              *  loop, generate code for the break expression, then
  547.              *  restore the loop information for this loop.
  548.              */
  549.             loop_info->rslt = chk_alc(loop_info->rslt, Tree0(n)->lifetime);
  550.             li_sav = loop_info;
  551.             loop_info = loop_info->prev;
  552.             gencode(Tree0(n), li_sav->rslt);
  553.             loop_info = li_sav;
  554.  
  555.             /*
  556.              * If this or another break expression suspends so we cannot
  557.              *  just branch to the end of the loop, all breaks must
  558.              *  call a common continuation.
  559.              */
  560.             if (cur_fnc->cursor->next != loop_info->end_loop &&
  561.                 loop_info->succ_cont == NULL)
  562.                loop_info->succ_cont = alc_fnc();
  563.             if (loop_info->succ_cont == NULL)
  564.                cd_add(mk_goto(loop_info->end_loop)); /* go to end of loop */
  565.             else
  566.                callc_add(loop_info->succ_cont);      /* call continuation */
  567.  
  568.             /*
  569.              * Return to the location of the break and generate a branch to
  570.              *  the code for its associated expression.
  571.              */
  572.             cur_fnc = fnc_sav;
  573.             cur_fnc->cursor = cursor_sav;
  574.             on_failure = fail_sav;
  575.             cd_add(sig_cd(lbl1, cur_fnc));
  576.             }
  577.          rslt = &ignore;   /* shouldn't be used but must be something valid */
  578.          break;
  579.  
  580.       case N_Case:
  581.          rslt = gen_case(n, rslt);
  582.          break;
  583.  
  584.       case N_Create:
  585.          rslt = gen_creat(n, rslt);
  586.          break;
  587.  
  588.       case N_Cset:
  589.       case N_Int:
  590.       case N_Real:
  591.       case N_Str:
  592.          cd = NewCode(2);
  593.          cd->cd_id = C_Lit;
  594.          rslt = chk_alc(rslt, n->lifetime);
  595.          cd->Rslt = rslt;
  596.          cd->Literal = CSym0(n);
  597.          cd_add(cd);
  598.          break;
  599.  
  600.       case N_Empty:
  601.          /*
  602.           * Assume null value is needed.
  603.           */
  604.          if (rslt == &ignore)
  605.            break;
  606.          rslt = chk_alc(rslt, n->lifetime);
  607.          cd_add(asgn_null(rslt));
  608.          break;
  609.  
  610.       case N_Field:
  611.          rslt = field_ref(n, rslt);
  612.          break;
  613.  
  614.       case N_Id:
  615.          /*
  616.           * If the variable reference is not going to be used, don't bother
  617.           *  building it.
  618.           */
  619.          if (rslt == &ignore)
  620.            break;
  621.          cd = NewCode(2);
  622.          cd->cd_id = C_NamedVar;
  623.          rslt = chk_alc(rslt, n->lifetime);
  624.          cd->Rslt = rslt;
  625.          cd->NamedVar = LSym0(n);
  626.          cd_add(cd);
  627.          break;
  628.  
  629.       case N_If:
  630.  
  631.          if (Type(Tree2(n)) == N_Empty) {
  632.             /*
  633.              * if-then. Control clause is bounded, but otherwise trivial.
  634.              */ 
  635.             bound(Tree0(n), &ignore, 0);      /* control clause */
  636.             rslt = gencode(Tree1(n), rslt);     /* then clause */
  637.             }
  638.          else {
  639.             /*
  640.              * if-then-else. Establish an "else" label as the failure
  641.              *   label of the bounded control clause.
  642.              */
  643.             fail_sav = on_failure;
  644.             fnc_sav = cur_fnc;
  645.             lbl1 = alc_lbl("else", 0);
  646.             on_failure = lbl1;
  647.  
  648.             bound(Tree0(n), &ignore, 0);  /* control clause */
  649.  
  650.             cd_add(lbl1);
  651.             cur_fnc->cursor = lbl1->prev; /* then clause goes before else lbl */
  652.             on_failure = fail_sav;
  653.             rslt = chk_alc(rslt, n->lifetime);
  654.             gencode(Tree1(n), rslt);      /* then clause */
  655.  
  656.             /*
  657.              * If the then clause is not a generator, execution can
  658.              *  just go to the end of the if-then-else expression. If it
  659.              *  is a generator, the continuation for the expression must be
  660.              *  in a separate function.
  661.              */
  662.             if (cur_fnc->cursor->next == lbl1) {
  663.                fnc = NULL;
  664.                lbl2 = alc_lbl("end if", 0);
  665.                cd_add(mk_goto(lbl2));
  666.                cur_fnc->cursor = lbl1;
  667.                cd_add(lbl2);
  668.                }
  669.             else {
  670.                lbl2 = NULL;
  671.                fnc = alc_fnc();
  672.                callc_add(fnc);
  673.                cur_fnc = fnc_sav;
  674.                }
  675.  
  676.             cur_fnc->cursor = lbl1;    /* else clause goes after label */
  677.             on_failure = fail_sav;
  678.             gencode(Tree2(n), rslt);   /* else clause */
  679.  
  680.             /*
  681.              * If the else clause is not a generator, execution is at
  682.              *  the end of the if-then-else expression, but the if clause
  683.              *  may have forced the continuation to be in a separate function.
  684.              *  If the else clause is a generator, it forces the continuation
  685.              *  to be in a separate function.
  686.              */
  687.             if (fnc == NULL) {
  688.                if (cur_fnc->cursor->next == lbl2)
  689.                   cur_fnc->cursor = lbl2;
  690.                else {
  691.                   fnc = alc_fnc();
  692.                   callc_add(fnc);
  693.                   /*
  694.                    * The then clause is not a generator, so it has branched
  695.                    *  to lbl2. We must add a call to the continuation there.
  696.                    */
  697.                   cur_fnc = fnc_sav;
  698.                   cur_fnc->cursor = lbl2;
  699.                   on_failure = fail_sav;
  700.                   callc_add(fnc);
  701.                   }
  702.                }
  703.             else
  704.                callc_add(fnc);
  705.  
  706.             if (fnc != NULL) {
  707.                /*
  708.                 * We produced a continuation for the if-then-else, so code
  709.                 *  generation must proceed in it.
  710.                 */
  711.                cur_fnc = fnc;
  712.                on_failure = &resume;
  713.                }
  714.             }
  715.          break;
  716.  
  717.       case N_Invok:
  718.          /*
  719.           * General invocation.
  720.           */
  721.          nargs = Val0(n);
  722.          if (Tree1(n)->n_type == N_Empty) {
  723.             /*
  724.              * Mutual evaluation.
  725.              */
  726.             for (i = 2; i <= nargs; ++i)
  727.                gencode(n->n_field[i].n_ptr, &ignore);   /* arg i - 1 */
  728.             rslt = chk_alc(rslt, n->lifetime);
  729.             gencode(n->n_field[nargs + 1].n_ptr, rslt); /* last argument */
  730.             }
  731.          else {
  732.             ++nargs; /* consider the procedure an argument to invoke() */
  733.             frst_arg = gen_args(n, 1, nargs);
  734.             setloc(n);
  735.             /*
  736.              * Assume this operation uses its result location as a work
  737.              *   area. Give it a location that is tended, where the value
  738.              *   is retained as long as the operation can be resumed.
  739.              */
  740.             if (rslt == &ignore)
  741.                rslt = NULL;      /* force allocation of temporary */
  742.             rslt = chk_alc(rslt, max_lftm(n->lifetime, n->intrnl_lftm));
  743.             mk_callop( "invoke", DoesRet | DoesFail | DoesSusp, frst_arg, nargs,
  744.                rslt, 0);
  745.             }
  746.          break;
  747.  
  748.       case N_InvOp:
  749.          rslt = inv_op(n, rslt);
  750.          break;
  751.  
  752.       case N_InvProc:
  753.          rslt = inv_prc(n, rslt);
  754.          break;
  755.  
  756.       case N_InvRec: {
  757.          /*
  758.           * Directly invoke a record constructor.
  759.           */
  760.          struct rentry *rec;
  761.  
  762.          nargs = Val0(n);             /* number of arguments */
  763.          frst_arg = gen_args(n, 2, nargs);
  764.          setloc(n);
  765.          rec = Rec1(n);
  766.  
  767.          rslt = chk_alc(rslt, n->lifetime);
  768.  
  769.          /*
  770.           * If error conversion can occur then the record constructor may
  771.           *  fail and we must check the signal.
  772.           */
  773.          if (err_conv) {
  774.             sbuf = (char *)alloc((unsigned int)(strlen(rec->name) + 
  775.                 strlen("signal = R_") + PrfxSz + 1));
  776.             sprintf(sbuf, "signal = R%s_%s(", rec->prefix, rec->name);
  777.             }
  778.          else {
  779.             sbuf = (char *)alloc((unsigned int)(strlen(rec->name) + PrfxSz +4));
  780.             sprintf(sbuf, "R%s_%s(", rec->prefix, rec->name);
  781.             }
  782.          cd = alc_ary(9);
  783.          cd->ElemTyp(0) = A_Str;        /* constructor name */
  784.          cd->Str(0) = sbuf;
  785.          cd->ElemTyp(1) = A_Intgr;      /* number of arguments */
  786.          cd->Intgr(1) = nargs;
  787.          cd->ElemTyp(2) = A_Str;        /* , */
  788.          cd->Str(2) = ", ";
  789.          if (frst_arg == NULL) {        /* location of first argument */
  790.             cd->ElemTyp(3) = A_Str;
  791.             cd->Str(3) = "NULL";
  792.             cd->ElemTyp(4) = A_Str;
  793.             cd->Str(4) = "";
  794.             }
  795.          else {
  796.             cd->ElemTyp(3) = A_Str;
  797.             cd->Str(3) = "&";
  798.             cd->ElemTyp(4) = A_ValLoc;
  799.             cd->ValLoc(4) = frst_arg;
  800.             }
  801.          cd->ElemTyp(5) = A_Str;        /* , */
  802.          cd->Str(5) = ", ";
  803.          cd->ElemTyp(6) = A_Str;        /* location of result */
  804.          cd->Str(6) = "&";
  805.          cd->ElemTyp(7) = A_ValLoc;
  806.          cd->ValLoc(7) = rslt;
  807.          cd->ElemTyp(8) = A_Str;
  808.          cd->Str(8) =                   ");";
  809.          cd_add(cd);
  810.          if (err_conv) {
  811.             cd = NewCode(2);
  812.             cd->cd_id = C_If;
  813.             cd1 = alc_ary(1);
  814.             cd1->ElemTyp(0) = A_Str;
  815.             cd1->Str(0) =                  "signal == A_Resume";
  816.             cd->Cond = cd1;
  817.             cd->ThenStmt = sig_cd(on_failure, cur_fnc);
  818.             cd_add(cd);
  819.             }
  820.          }
  821.          break;
  822.  
  823.       case N_Limit:
  824.          rslt = gen_lim(n, rslt);
  825.          break;
  826.  
  827.       case N_Loop: {
  828.          struct loop_info li;
  829.  
  830.          /*
  831.           * Set up loop information for use by break and next expressions.
  832.           */
  833.          li.end_loop = alc_lbl("end loop", 0);
  834.          cd_add(li.end_loop);
  835.          cur_fnc->cursor = li.end_loop->prev;      /* loop goes before label */
  836.          li.rslt = rslt;
  837.          li.on_failure = on_failure;
  838.          li.scan_info = nxt_scan;
  839.          li.succ_cont = NULL;
  840.          li.prev = loop_info;
  841.          loop_info = &li;
  842.  
  843.          switch ((int)Val0(Tree0(n))) {
  844.             case EVERY:
  845.                /*
  846.                 * "next" in the control clause just fails.
  847.                 */
  848.                li.next_lbl = &next_fail;
  849.                gencode(Tree1(n), &ignore);          /* control clause */
  850.                /*
  851.                 * "next" in the do clause transfers control to the
  852.                 *   statement at the end of the loop that resumes the
  853.                 *   control clause.
  854.                 */
  855.                li.next_lbl = alc_lbl("next", 0);
  856.                bound(Tree2(n), &ignore, 1);         /* do clause */
  857.                cd_add(li.next_lbl);
  858.                cd_add(sig_cd(on_failure, cur_fnc)); /* resume control clause */
  859.                break;
  860.  
  861.             case REPEAT:
  862.                li.next_lbl = alc_lbl("repeat", 0);
  863.                cd_add(li.next_lbl);
  864.                bound(Tree1(n), &ignore, 1);
  865.                cd_add(mk_goto(li.next_lbl));
  866.                break;
  867.  
  868.             case SUSPEND:            /* suspension expression */
  869.                if (create_lvl > 0) {
  870.                   nfatal(n, "invalid context for suspend", NULL);
  871.                   return &ignore;
  872.                   }
  873.                /*
  874.                 * "next" in the control clause just fails. The result
  875.                 *   of the control clause goes in the procedure return
  876.                 *   location.
  877.                 */
  878.                li.next_lbl = &next_fail;
  879.                genretval(n, Tree1(n), &proc_rslt);
  880.  
  881.                /*
  882.                 * If necessary, swap scanning environments before suspending.
  883.                 *   if there is no success continuation, just return.
  884.                 */
  885.                if (nxt_scan != &scan_base) {
  886.                   save_env(scan_base.inner_sub, scan_base.inner_pos);
  887.                   restr_env(scan_base.outer_sub, scan_base.outer_pos);
  888.                   }
  889.                cd = NewCode(2);
  890.                cd->cd_id = C_If;
  891.                cd1 = alc_ary(2);
  892.                cd1->ElemTyp(0) = A_ProcCont;
  893.                cd1->ElemTyp(1) = A_Str;
  894.                cd1->Str(1) = " == NULL";
  895.                cd->Cond = cd1;
  896.                cd->ThenStmt = sig_cd(p_ret_lbl, cur_fnc);
  897.                cd_add(cd);
  898.                cd = NewCode(0);
  899.                cd->cd_id = C_PSusp;
  900.                cd_add(cd);
  901.                cur_fnc->flag |= CF_ForeignSig;
  902.  
  903.                /*
  904.                 * Force updating file name and line number, and if needed,
  905.                 *  switch scanning environments before resuming.
  906.                 */
  907.                lastfiln = NULL;
  908.                lastline = 0;
  909.                if (nxt_scan != &scan_base) {
  910.                   save_env(scan_base.outer_sub, scan_base.outer_pos);
  911.                   restr_env(scan_base.inner_sub, scan_base.inner_pos);
  912.                   }
  913.  
  914.                /*
  915.                 * "next" in the do clause transfers control to the
  916.                 *   statement at the end of the loop that resumes the
  917.                 *   control clause.
  918.                 */
  919.                li.next_lbl = alc_lbl("next", 0);
  920.                bound(Tree2(n), &ignore, 1);       /* do clause */
  921.                cd_add(li.next_lbl);
  922.                cd_add(sig_cd(on_failure, cur_fnc));
  923.                break;
  924.  
  925.             case WHILE:
  926.                li.next_lbl = alc_lbl("while", 0);
  927.                cd_add(li.next_lbl);
  928.                /*
  929.                 * The control clause and do clause are both bounded expressions,
  930.                 *   but only the do clause establishes a new failure label.
  931.                 */
  932.                bound(Tree1(n), &ignore, 0);      /* control clause */
  933.                bound(Tree2(n), &ignore, 1);      /* do clause */
  934.                cd_add(mk_goto(li.next_lbl));
  935.                break;
  936.  
  937.             case UNTIL:
  938.                fail_sav = on_failure;
  939.                li.next_lbl = alc_lbl("until", 0);
  940.                cd_add(li.next_lbl);
  941.  
  942.                /*
  943.                 * If the control clause fails, execution continues in
  944.                 *  the loop.
  945.                 */
  946.                if (Type(Tree2(n)) == N_Empty)
  947.                   on_failure = li.next_lbl;  
  948.                else {
  949.                   lbl2 = alc_lbl("do", 0);
  950.                   on_failure = lbl2;
  951.                   cd_add(lbl2);
  952.                   cur_fnc->cursor = lbl2->prev;  /* control before label */
  953.                   }
  954.                bound(Tree1(n), &ignore, 0);      /* control clause */
  955.  
  956.                /*
  957.                 * If the control clause succeeds, the loop fails.
  958.                 */
  959.                cd_add(sig_cd(fail_sav, cur_fnc));
  960.  
  961.                if (Type(Tree2(n)) != N_Empty) {
  962.                   /*
  963.                    * Do clause goes after the label and the loop repeats.
  964.                    */
  965.                   cur_fnc->cursor = lbl2;
  966.                   bound(Tree2(n), &ignore, 1);      /* do clause */
  967.                   cd_add(mk_goto(li.next_lbl));
  968.                   }
  969.                break;
  970.             }
  971.  
  972.          /*
  973.           * Go to the end of the loop and see if the loop's success continuation
  974.           *  is in a separate function.
  975.           */
  976.          cur_fnc = li.end_loop->Container;
  977.          cur_fnc->cursor = li.end_loop;
  978.          if (li.succ_cont != NULL) {
  979.             callc_add(li.succ_cont);
  980.             cur_fnc = li.succ_cont;
  981.             on_failure = &resume;
  982.             }
  983.          if (li.rslt == NULL)
  984.             rslt = &ignore; /* shouldn't be used but must be something valid */
  985.          else
  986.             rslt = li.rslt;
  987.          loop_info = li.prev;
  988.          break;
  989.          }
  990.  
  991.       case N_Next:
  992.          /*
  993.           * In some contexts "next" just fails. In other contexts it
  994.           *   transfers control to a label, in which case it may have
  995.           *   to restore a scanning environment.
  996.           */
  997.          if (loop_info == NULL)
  998.             nfatal(n, "invalid context for a next expression", NULL);
  999.          else if (loop_info->next_lbl == &next_fail)
  1000.             cd_add(sig_cd(on_failure, cur_fnc));
  1001.          else {
  1002.             if (nxt_scan != loop_info->scan_info)
  1003.                restr_env(loop_info->scan_info->outer_sub,
  1004.                   loop_info->scan_info->outer_pos);
  1005.             cd_add(sig_cd(loop_info->next_lbl, cur_fnc));
  1006.             }
  1007.          rslt = &ignore; /* shouldn't be used but must be something valid */
  1008.          break;
  1009.  
  1010.       case N_Not:
  1011.          lbl1 = alc_lbl("not", 0);
  1012.          fail_sav = on_failure;
  1013.          on_failure = lbl1;
  1014.          cd_add(lbl1);
  1015.          cur_fnc->cursor = lbl1->prev;        /* code goes before label */
  1016.          bound(Tree0(n), &ignore, 0);
  1017.          on_failure = fail_sav;
  1018.          cd_add(sig_cd(on_failure, cur_fnc)); /* convert success to failure */
  1019.          cur_fnc->cursor = lbl1;          /* convert failure to null */
  1020.          if (rslt != &ignore) {
  1021.             rslt = chk_alc(rslt, n->lifetime);
  1022.             cd_add(asgn_null(rslt));
  1023.             }
  1024.          break;
  1025.  
  1026.       case N_Ret:
  1027.          if (create_lvl > 0) {
  1028.             nfatal(n, "invalid context for return or fail", NULL);
  1029.             return &ignore;
  1030.             }
  1031.          if (Val0(Tree0(n)) == RETURN) {
  1032.             /*
  1033.              * Set up the failure action of the return expression to do a
  1034.              *  procedure fail.
  1035.              */
  1036.             if (nxt_scan != &scan_base) {
  1037.                /*
  1038.                 * we must switch scanning environments if the expression fails.
  1039.                 */
  1040.                lbl1 = alc_lbl("return fail", 0);
  1041.                cd_add(lbl1);
  1042.                restr_env(scan_base.outer_sub, scan_base.outer_pos);
  1043.                cd_add(sig_cd(p_fail_lbl, cur_fnc));
  1044.                cur_fnc->cursor = lbl1->prev;        /* code goes before label */
  1045.                on_failure = lbl1;
  1046.                }
  1047.             else
  1048.                on_failure = p_fail_lbl;
  1049.  
  1050.             /*
  1051.              * Produce code to place return value in procedure result location.
  1052.              */
  1053.             genretval(n, Tree1(n), &proc_rslt);
  1054.  
  1055.             /*
  1056.              * See if a scanning environment must be restored and
  1057.              *  transfer control to the procedure return code.
  1058.              */
  1059.             if (nxt_scan != &scan_base)
  1060.                restr_env(scan_base.outer_sub, scan_base.outer_pos);
  1061.             cd_add(sig_cd(p_ret_lbl, cur_fnc));
  1062.             }
  1063.          else {
  1064.             /*
  1065.              * fail. See if a scanning environment must be restored and
  1066.              *  transfer control to the procedure failure code.
  1067.              */
  1068.             if (nxt_scan != &scan_base)
  1069.                restr_env(scan_base.outer_sub, scan_base.outer_pos);
  1070.             cd_add(sig_cd(p_fail_lbl, cur_fnc));
  1071.             }
  1072.          rslt = &ignore; /* shouldn't be used but must be something valid */
  1073.          break;
  1074.  
  1075.       case N_Scan:
  1076.          rslt = gen_scan(n, rslt);
  1077.          break;
  1078.  
  1079.       case N_Sect:
  1080.          /*
  1081.           * x[i+:j] or x[i-:j] (x[i:j] handled as ordinary operator)
  1082.           */
  1083.          impl1 = Impl0(n);     /* sectioning */
  1084.          if (impl1 == NULL) {
  1085.             rslt = &ignore;    /* make sure code generation can continue */
  1086.             break;
  1087.             }
  1088.          implproto(impl1);
  1089.  
  1090.          impl = Impl1(n);      /* plus or minus */
  1091.          /*
  1092.           * Allocate work area of temporary variables for sectioning.
  1093.           */
  1094.          lifetm_ary = alc_lftm(3, NULL);
  1095.          lifetm_ary[0].cur_status = Tree2(n)->postn;
  1096.          lifetm_ary[0].lifetime = n->intrnl_lftm;
  1097.          lifetm_ary[1].cur_status = Tree3(n)->postn;
  1098.          lifetm_ary[1].lifetime = n->intrnl_lftm;
  1099.          lifetm_ary[2].cur_status = n->postn;
  1100.          lifetm_ary[2].lifetime = n->intrnl_lftm;
  1101.          tmp_indx = alc_tmp(3, lifetm_ary);
  1102.          for (i = 0; i < 3; ++i)
  1103.             r1[i] = tmp_loc(tmp_indx++);
  1104.          gencode(Tree2(n), r1[0]);   /* generate code to compute x */
  1105.          gencode(Tree3(n), r1[1]);   /* generate code compute i */
  1106.  
  1107.          /*
  1108.           * Allocate work area of temporary variables for arithmetic.
  1109.           */
  1110.          lifetm_ary[0].cur_status = InUse;
  1111.          lifetm_ary[0].lifetime = Tree3(n)->lifetime;
  1112.          lifetm_ary[1].cur_status = Tree4(n)->postn;
  1113.          lifetm_ary[1].lifetime = Tree4(n)->lifetime;
  1114.          tmp_indx = alc_tmp(2, lifetm_ary);
  1115.          for (i = 0; i < 2; ++i)
  1116.             r2[i] = tmp_loc(tmp_indx++);
  1117.          cd_add(mk_cpyval(r2[0], r1[1])); /* generate code to copy i */
  1118.          gencode(Tree4(n), r2[1]);        /* generate code to compute j */
  1119.  
  1120.          /*
  1121.           * generate code for i op j.
  1122.           */
  1123.          setloc(n);
  1124.          implproto(impl);
  1125.          mk_callop(oper_name(impl), impl->ret_flag, r2[0], 2, r1[2], 0);
  1126.  
  1127.          /*
  1128.           * generate code for x[i : (i op j)]
  1129.           */
  1130.          rslt = chk_alc(rslt, n->lifetime);
  1131.          mk_callop(oper_name(impl1),impl1->ret_flag,r1[0],3,rslt,0);
  1132.          free((char *)lifetm_ary);
  1133.          break;
  1134.  
  1135.       case N_Slist:
  1136.          bound(Tree0(n), &ignore, 1);
  1137.          rslt = gencode(Tree1(n), rslt);
  1138.          break;
  1139.  
  1140.       case N_SmplAsgn: {
  1141.          struct val_loc *var, *val;
  1142.  
  1143.          /*
  1144.           * Optimized assignment to a named variable. Use information
  1145.           *  from type inferencing to determine if the right-hand-side
  1146.           *  is a variable.
  1147.           */
  1148.          var = var_ref(LSym0(Tree2(n)));
  1149.          if (HasVar(varsubtyp(Tree3(n)->type, &single)))
  1150.             Val0(n) = AsgnDeref;
  1151.          if (single != NULL) {
  1152.             /*
  1153.              * Right-hand-side results in a named variable. Compute
  1154.              *  the expression but don't bother saving the result, we
  1155.              *  know what it is. Assignment just copies value from
  1156.              *  one variable to the other.
  1157.              */
  1158.             gencode(Tree3(n), &ignore);
  1159.             val = var_ref(single);
  1160.             cd_add(mk_cpyval(var, val));
  1161.             }
  1162.          else switch (Val0(n)) { 
  1163.             case AsgnDirect:
  1164.                /*
  1165.                 * It is safe to compute the result directly into the variable.
  1166.                 */
  1167.                gencode(Tree3(n), var);
  1168.                break;
  1169.             case AsgnCopy:
  1170.                /*
  1171.                 * The result is not a variable reference, but it is not
  1172.                 *  safe to compute it into the variable, we must use a
  1173.                 *  temporary variable.
  1174.                 */
  1175.                val = gencode(Tree3(n), NULL);
  1176.                cd_add(mk_cpyval(var, val));
  1177.                break;
  1178.             case AsgnDeref:
  1179.                /*
  1180.                 * We must dereference the result into the variable.
  1181.                 */
  1182.                val = gencode(Tree3(n), NULL);
  1183.                deref_cd(val, var);
  1184.                break;
  1185.             }
  1186.  
  1187.          /*
  1188.           * If the assignment has to produce a result, construct the
  1189.           *  variable reference.
  1190.           */
  1191.          if (rslt != &ignore)
  1192.             rslt = gencode(Tree2(n), rslt);
  1193.          }
  1194.          break;
  1195.  
  1196.       case N_SmplAug: {
  1197.          /*
  1198.           * Optimized augmented assignment to a named variable.
  1199.           */
  1200.          struct val_loc *var, *val;
  1201.  
  1202.          impl = Impl1(n);      /* the operation */
  1203.          if (impl == NULL) {
  1204.             rslt = &ignore;    /* make sure code generation can continue */
  1205.             break;
  1206.             }
  1207.  
  1208.          implproto(impl); /* insure prototype for operation */
  1209.  
  1210.          /*
  1211.           * Generate code to compute the arguments for the operation.
  1212.           */
  1213.          frst_arg = gen_args(n, 2, 2);
  1214.          setloc(n);
  1215.  
  1216.          /*
  1217.           * Use information from type inferencing to determine if the
  1218.           *  operation produces a variable.
  1219.           */
  1220.          if (HasVar(varsubtyp(Typ4(n), &single)))
  1221.             Val0(n) = AsgnDeref;
  1222.          var = var_ref(LSym0(Tree2(n)));
  1223.          if (single != NULL) {
  1224.             /*
  1225.              * The operation results in a named variable. Call the operation
  1226.              *  but don't bother saving the result, we know what it is.
  1227.              *  Assignment just copies value from one variable to the other.
  1228.              */
  1229.             mk_callop(oper_name(impl), impl->ret_flag, frst_arg, 2,
  1230.                   &ignore, 0);
  1231.             val = var_ref(single);
  1232.             cd_add(mk_cpyval(var, val));
  1233.             }
  1234.          else switch (Val0(n)) { 
  1235.             case AsgnDirect:
  1236.                /*
  1237.                 * It is safe to compute the result directly into the variable.
  1238.                 */
  1239.                mk_callop(oper_name(impl), impl->ret_flag, frst_arg, 2,
  1240.                   var, 0);
  1241.                break;
  1242.             case AsgnCopy:
  1243.                /*
  1244.                 * The result is not a variable reference, but it is not
  1245.                 *  safe to compute it into the variable, we must use a
  1246.                 *  temporary variable.
  1247.                 */
  1248.                val = chk_alc(NULL, n);
  1249.                mk_callop(oper_name(impl), impl->ret_flag, frst_arg, 2, val, 0);
  1250.                cd_add(mk_cpyval(var, val));
  1251.                break;
  1252.             case AsgnDeref:
  1253.                /*
  1254.                 * We must dereference the result into the variable.
  1255.                 */
  1256.                val = chk_alc(NULL, n);
  1257.                mk_callop(oper_name(impl), impl->ret_flag, frst_arg, 2, val, 0);
  1258.                deref_cd(val, var);
  1259.                break;
  1260.             }
  1261.  
  1262.          /*
  1263.           * If the assignment has to produce a result, construct the
  1264.           *  variable reference.
  1265.           */
  1266.          if (rslt != &ignore)
  1267.             rslt = gencode(Tree2(n), rslt);
  1268.          }
  1269.          break;
  1270.  
  1271.       default:
  1272.          fprintf(stderr, "compiler error: node type %d unknown\n", n->n_type);
  1273.          exit(ErrorExit);
  1274.       }
  1275.  
  1276.    /*
  1277.     * Free any temporaries whose lifetime ends at this node.
  1278.     */
  1279.    freetmp = n->freetmp;
  1280.    while (freetmp != NULL) {
  1281.       switch (freetmp->kind) {
  1282.          case DescTmp:
  1283.             tmp_status[freetmp->indx] = freetmp->old;
  1284.             break;
  1285.          case CIntTmp:
  1286.             itmp_status[freetmp->indx] = freetmp->old;
  1287.             break;
  1288.          case CDblTmp:
  1289.             dtmp_status[freetmp->indx] = freetmp->old;
  1290.             break;
  1291.          case SBuf:
  1292.             sbuf_status[freetmp->indx] = freetmp->old;
  1293.             break;
  1294.          case CBuf:
  1295.             cbuf_status[freetmp->indx] = freetmp->old;
  1296.             break;
  1297.          }
  1298.       ft = freetmp->next;
  1299.       freetmp->next = freetmp_pool;
  1300.       freetmp_pool = freetmp;
  1301.       freetmp = ft;
  1302.       }
  1303.    return rslt;
  1304.    }
  1305.  
  1306. /*
  1307.  * chk_alc - make sure a result location has been allocated. If it is
  1308.  *  a temporary variable, indicate that it is now in use.
  1309.  */
  1310. struct val_loc *chk_alc(rslt, lifetime)
  1311. struct val_loc *rslt;
  1312. nodeptr lifetime;
  1313.    {
  1314.    struct tmplftm tmplftm;
  1315.  
  1316.    if (rslt == NULL) {
  1317.       if (lifetime == NULL)
  1318.          rslt = &ignore;
  1319.       else {
  1320.          tmplftm.cur_status = InUse;
  1321.          tmplftm.lifetime = lifetime;
  1322.          rslt = tmp_loc(alc_tmp(1, &tmplftm));
  1323.          }
  1324.       }
  1325.    else if (rslt->loc_type == V_Temp)
  1326.       tmp_status[rslt->u.tmp] = InUse;
  1327.    return rslt;
  1328.    }
  1329.  
  1330. /*
  1331.  * mk_goto - make a code structure for goto label
  1332.  */
  1333. struct code *mk_goto(label)
  1334. struct code *label;
  1335.    {
  1336.    register struct code *cd;
  1337.  
  1338.    cd = NewCode(1);    /* # fields == # fields of C_RetSig & C_Break */
  1339.    cd->cd_id = C_Goto;
  1340.    cd->next = NULL;
  1341.    cd->prev = NULL;
  1342.    cd->Lbl = label;
  1343.    ++label->RefCnt;
  1344.    return cd;
  1345.    }
  1346.  
  1347. /*
  1348.  * mk_cpyval - make code to copy a value from one location to another.
  1349.  */
  1350. static struct code *mk_cpyval(loc1, loc2)
  1351. struct val_loc *loc1;
  1352. struct val_loc *loc2;
  1353.    {
  1354.    struct code *cd;
  1355.  
  1356.    cd = alc_ary(4);
  1357.    cd->ElemTyp(0) = A_ValLoc;
  1358.    cd->ValLoc(0) = loc1;
  1359.    cd->ElemTyp(1) = A_Str;
  1360.    cd->Str(1) = " = ";
  1361.    cd->ElemTyp(2) = A_ValLoc;
  1362.    cd->ValLoc(2) = loc2;
  1363.    cd->ElemTyp(3) = A_Str;
  1364.    cd->Str(3) = ";";
  1365.    return cd;
  1366.    }
  1367.  
  1368. /*
  1369.  * asgn_null - make code to assign the null value to a location.
  1370.  */
  1371. static struct code *asgn_null(loc1)
  1372. struct val_loc *loc1;
  1373.    {
  1374.    struct code *cd;
  1375.  
  1376.    cd = alc_ary(2);
  1377.    cd->ElemTyp(0) = A_ValLoc;
  1378.    cd->ValLoc(0) = loc1;
  1379.    cd->ElemTyp(1) = A_Str;
  1380.    cd->Str(1) = " = nulldesc;";
  1381.    return cd;
  1382.    }
  1383.  
  1384. /*
  1385.  * oper_name - create the name for the most general implementation of an Icon
  1386.  *   operation.
  1387.  */
  1388. static char *oper_name(impl)
  1389. struct implement *impl;
  1390.    {
  1391.    char *sbuf;
  1392.  
  1393.    sbuf = (char *)alloc((unsigned int)(strlen(impl->name) + 5));
  1394.    sprintf(sbuf, "%c%c%c_%s", impl->oper_typ, impl->prefix[0], impl->prefix[1],
  1395.       impl->name);
  1396.    return sbuf;
  1397.    }
  1398.  
  1399. /*
  1400.  * gen_args - generate code to evaluate an argument list.
  1401.  */
  1402. static struct val_loc *gen_args(n, frst_arg, nargs)
  1403. struct node *n;
  1404. int frst_arg;
  1405. int nargs;
  1406.    {
  1407.    struct tmplftm *lifetm_ary;
  1408.    int i;
  1409.    int tmp_indx;
  1410.  
  1411.    if (nargs == 0)
  1412.       return NULL;
  1413.  
  1414.    lifetm_ary = alc_lftm(nargs, &n->n_field[frst_arg]);
  1415.    tmp_indx = alc_tmp(nargs, lifetm_ary);
  1416.    for (i = 0; i < nargs; ++i)
  1417.       gencode(n->n_field[frst_arg + i].n_ptr, tmp_loc(tmp_indx + i));
  1418.    free((char *)lifetm_ary);
  1419.    return tmp_loc(tmp_indx);
  1420.    }
  1421.  
  1422. /*
  1423.  * gen_case - generate code for a case expression.
  1424.  */
  1425. static struct val_loc *gen_case(n, rslt)
  1426. struct node *n;
  1427. struct val_loc *rslt;
  1428.    {
  1429.    struct node *control;
  1430.    struct node *cases;
  1431.    struct node *deflt;
  1432.    struct node *clause;
  1433.    struct val_loc *r1;
  1434.    struct val_loc *r2;
  1435.    struct val_loc *r3;
  1436.    struct code *cd;
  1437.    struct code *cd1;
  1438.    struct code *fail_sav;
  1439.    struct code *skp_lbl;
  1440.    struct code *cd_lbl;
  1441.    struct code *end_lbl;
  1442.    struct c_fnc *fnc_sav;
  1443.    struct c_fnc *succ_cont = NULL;
  1444.  
  1445.    control = Tree0(n);
  1446.    cases = Tree1(n);
  1447.    deflt = Tree2(n);
  1448.  
  1449.    /*
  1450.     * The control clause is bounded.
  1451.     */
  1452.    r1 = chk_alc(NULL, n); 
  1453.    bound(control, r1, 0);
  1454.  
  1455.    /*
  1456.     * Remember the context in which the case expression occurs and
  1457.     *  establish a label at the end of the expression.
  1458.     */
  1459.    fail_sav = on_failure;
  1460.    fnc_sav = cur_fnc;
  1461.    end_lbl = alc_lbl("end case", 0);
  1462.    cd_add(end_lbl);
  1463.    cur_fnc->cursor = end_lbl->prev; /* generate code before the end label */
  1464.  
  1465.    /*
  1466.     * All cases share the result location of the case expression.
  1467.     */
  1468.    rslt = chk_alc(rslt, n->lifetime);
  1469.    r2 = chk_alc(NULL, n);      /* for result of selection clause */
  1470.    r3 = chk_alc(NULL, n);      /* for dereferenced result of control clause */
  1471.  
  1472.    while (cases != NULL) {
  1473.       /*
  1474.        * See if we are at the end of the case clause list.
  1475.        */
  1476.       if (cases->n_type == N_Ccls) {
  1477.          clause = cases;
  1478.          cases = NULL;
  1479.          }
  1480.       else {
  1481.          clause = Tree1(cases);
  1482.          cases = Tree0(cases);
  1483.          }
  1484.  
  1485.       /*
  1486.        * If the evaluation of the selection code or the comparison of
  1487.        *  its value to the control clause fail, execution will proceed
  1488.        *  to the "skip clause" label and on to the next case.
  1489.        */
  1490.       skp_lbl = alc_lbl("skip clause", 0);
  1491.       on_failure = skp_lbl;
  1492.       cd_add(skp_lbl);
  1493.       cur_fnc->cursor = skp_lbl->prev;  /* generate code before end label */
  1494.  
  1495.       /*
  1496.        * Bound the selection code for this clause.
  1497.        */
  1498.       cd_lbl = alc_lbl("selected code", Bounding);
  1499.       cd_add(cd_lbl);
  1500.       cur_fnc->cursor = cd_lbl->prev; 
  1501.       gencode(Tree0(clause), r2);
  1502.  
  1503.       /*
  1504.        * Dereference the results of the control clause and the selection
  1505.        *  clause and compare them.
  1506.        */
  1507.       setloc(clause);
  1508.       deref_cd(r1, r3);
  1509.       deref_cd(r2, r2);
  1510.       cd = NewCode(2);
  1511.       cd->cd_id = C_If;
  1512.       cd1 = alc_ary(5);
  1513.       cd1->ElemTyp(0) = A_Str;
  1514.       cd1->Str(0) =                 "!equiv(&";
  1515.       cd1->ElemTyp(1) = A_ValLoc;
  1516.       cd1->ValLoc(1) =              r3;
  1517.       cd->Cond = cd1;
  1518.       cd1->ElemTyp(2) = A_Str;
  1519.       cd1->Str(2) =                 ", &";
  1520.       cd1->ElemTyp(3) = A_ValLoc;
  1521.       cd1->ValLoc(3) =              r2;
  1522.       cd1->ElemTyp(4) = A_Str;
  1523.       cd1->Str(4) =                 ")";
  1524.       cd->ThenStmt = sig_cd(on_failure, cur_fnc); 
  1525.       cd_add(cd);
  1526.       cd_add(sig_cd(cd_lbl, cur_fnc));  /* transfer control to bounding label */
  1527.  
  1528.       /*
  1529.        * Generate code for the body of this clause after the bounding label.
  1530.        */
  1531.       cur_fnc = fnc_sav;
  1532.       cur_fnc->cursor = cd_lbl;
  1533.       on_failure = fail_sav;
  1534.       gencode(Tree1(clause), rslt);
  1535.  
  1536.       /*
  1537.        * If this clause is a generator, call the success continuation
  1538.        *  for the case expression, otherwise branch to the end of the
  1539.        *  expression.
  1540.        */
  1541.       if (cur_fnc->cursor->next != skp_lbl) {
  1542.          if (succ_cont == NULL)
  1543.             succ_cont = alc_fnc(); /* allocate a continuation function */
  1544.          callc_add(succ_cont);
  1545.          cur_fnc = fnc_sav;
  1546.          }
  1547.       else
  1548.          cd_add(mk_goto(end_lbl));
  1549.  
  1550.       /*
  1551.        * The code for the next clause goes after the  "skip" label of
  1552.        *   this clause.
  1553.        */
  1554.       cur_fnc->cursor = skp_lbl;
  1555.       }
  1556.  
  1557.    if (deflt == NULL)
  1558.       cd_add(sig_cd(fail_sav, cur_fnc));     /* default action is failure */
  1559.    else {
  1560.       /*
  1561.        * There is an explicit default action.
  1562.        */
  1563.       on_failure = fail_sav;
  1564.       gencode(deflt, rslt);
  1565.       if (cur_fnc->cursor->next != end_lbl) {
  1566.          if (succ_cont == NULL)
  1567.             succ_cont = alc_fnc();
  1568.          callc_add(succ_cont);
  1569.          cur_fnc = fnc_sav;
  1570.          }
  1571.       }
  1572.    cur_fnc->cursor = end_lbl;
  1573.  
  1574.    /*
  1575.     * If some clauses are generators but others have transferred control
  1576.     *  to here, we must call the success continuation of the case
  1577.     *  expression and generate subsequent code there.
  1578.     */
  1579.    if (succ_cont != NULL) {
  1580.       on_failure = fail_sav;
  1581.       callc_add(succ_cont);
  1582.       cur_fnc = succ_cont;
  1583.       on_failure = &resume;
  1584.       }
  1585.    return rslt;
  1586.    }
  1587.  
  1588. /*
  1589.  * gen_creat - generate code to create a co-expression.
  1590.  */
  1591. static struct val_loc *gen_creat(n, rslt)
  1592. struct node *n;
  1593. struct val_loc *rslt;
  1594.    {
  1595.    struct code *cd;
  1596.    struct code *fail_sav;
  1597.    struct code *fail_lbl;
  1598.    struct c_fnc *fnc_sav;
  1599.    struct c_fnc *fnc;
  1600.    struct val_loc *co_rslt;
  1601.    struct freetmp *ft;
  1602.    char sav_prfx[PrfxSz];
  1603.    int *tmp_sv;
  1604.    int *itmp_sv;
  1605.    int *dtmp_sv;
  1606.    int *sbuf_sv;
  1607.    int *cbuf_sv;
  1608.    int ntmp_sv;
  1609.    int nitmp_sv;
  1610.    int ndtmp_sv;
  1611.    int nsbuf_sv;
  1612.    int ncbuf_sv;
  1613.    int stat_sz_sv;
  1614.    int istat_sz_sv;
  1615.    int dstat_sz_sv;
  1616.    int sstat_sz_sv;
  1617.    int cstat_sz_sv;
  1618.    int i;
  1619.  
  1620.  
  1621.    rslt = chk_alc(rslt, n->lifetime);
  1622.  
  1623.    fail_sav = on_failure;
  1624.    fnc_sav = cur_fnc;
  1625.    for (i = 0; i < PrfxSz; ++i)
  1626.       sav_prfx[i] = frm_prfx[i];
  1627.  
  1628.    /*
  1629.     * Temporary variables are allocated independently for the co-expression.
  1630.     */
  1631.    tmp_sv = tmp_status;
  1632.    itmp_sv = itmp_status;
  1633.    dtmp_sv = dtmp_status;
  1634.    sbuf_sv = sbuf_status;
  1635.    cbuf_sv = cbuf_status;
  1636.    stat_sz_sv = status_sz;
  1637.    istat_sz_sv = istatus_sz;
  1638.    dstat_sz_sv = dstatus_sz;
  1639.    sstat_sz_sv = sstatus_sz;
  1640.    cstat_sz_sv = cstatus_sz;
  1641.    ntmp_sv = num_tmp;
  1642.    nitmp_sv = num_itmp;
  1643.    ndtmp_sv = num_dtmp;
  1644.    nsbuf_sv = num_sbuf;
  1645.    ncbuf_sv = num_cbuf;
  1646.    tmp_status = (int *)alloc((unsigned int)(status_sz * sizeof(int)));
  1647.    itmp_status = (int *)alloc((unsigned int)(istatus_sz * sizeof(int)));
  1648.    dtmp_status = (int *)alloc((unsigned int)(dstatus_sz * sizeof(int)));
  1649.    sbuf_status = (int *)alloc((unsigned int)(sstatus_sz * sizeof(int)));
  1650.    cbuf_status = (int *)alloc((unsigned int)(cstatus_sz * sizeof(int)));
  1651.    for (i = 0; i < status_sz; ++i)
  1652.       tmp_status[i] = NotAlloc;
  1653.    for (i = 0; i < istatus_sz; ++i)
  1654.       itmp_status[i] = NotAlloc;
  1655.    for (i = 0; i < dstatus_sz; ++i)
  1656.       dtmp_status[i] = NotAlloc;
  1657.    for (i = 0; i < sstatus_sz; ++i)
  1658.       sbuf_status[i] = NotAlloc;
  1659.    for (i = 0; i < cstatus_sz; ++i)
  1660.       cbuf_status[i] = NotAlloc;
  1661.    num_tmp = 0;
  1662.    num_itmp = 0;
  1663.    num_dtmp = 0;
  1664.    num_sbuf = 0;
  1665.    num_cbuf = 0;
  1666.  
  1667.    /*
  1668.     * Put code for co-expression in separate function. We will need a new
  1669.     *  type of procedure frame which contains copies of local variables,
  1670.     *  copies of arguments, and temporaries for use by the co-expression.
  1671.     */
  1672.    fnc = alc_fnc();
  1673.    fnc->ref_cnt = 1;
  1674.    fnc->flag |= CF_Coexpr;
  1675.    ChkPrefix(fnc->prefix);
  1676.    for (i = 0; i < PrfxSz; ++i)
  1677.       frm_prfx[i] = fnc->frm_prfx[i] = fnc->prefix[i];
  1678.    cur_fnc = fnc;
  1679.  
  1680.    /*
  1681.     * Set up a co-expression failure label followed by a context switch
  1682.     *  and a branch back to the failure label.
  1683.     */
  1684.    fail_lbl = alc_lbl("co_fail", 0);
  1685.    cd_add(fail_lbl);
  1686.    lastline = 0;  /* force setting line number so tracing matches interp */
  1687.    setloc(n);
  1688.    cd = alc_ary(2);
  1689.    cd->ElemTyp(0) = A_Str;
  1690.    cd->ElemTyp(1) = A_Str;
  1691.    cd->Str(0) = "co_chng(popact((struct b_coexpr *)BlkLoc(k_current)),";
  1692.    cd->Str(1) =    "NULL, NULL, A_Cofail, 1);";
  1693.    cd_add(cd);
  1694.    cd_add(mk_goto(fail_lbl));
  1695.    cur_fnc->cursor = fail_lbl->prev;  /* code goes before failure label */
  1696.    on_failure = fail_lbl;
  1697.  
  1698.    /*
  1699.     * Generate code for the co-expression body, using the same
  1700.     *  dereferencing rules as for procedure return.
  1701.     */
  1702.    lastfiln = "";  /* force setting of file name and line number */
  1703.    lastline = 0;
  1704.    setloc(n);
  1705.    ++create_lvl;
  1706.    co_rslt = genretval(n, Tree0(n), NULL);
  1707.    --create_lvl;
  1708.  
  1709.    /*
  1710.     * If the co-expression might produce a result, generate a co-expression
  1711.     *  context switch.
  1712.     */
  1713.    if (co_rslt != NULL) {
  1714.       cd = alc_ary(1);
  1715.       cd->ElemTyp(0) = A_Str;
  1716.       cd->Str(0) = "++BlkLoc(k_current)->coexpr.size;";
  1717.       cd_add(cd);
  1718.       cd = alc_ary(3);
  1719.       cd->ElemTyp(0) = A_Str;
  1720.       cd->Str(0) = "co_chng(popact((struct b_coexpr *)BlkLoc(k_current)), &";
  1721.       cd->ElemTyp(1) = A_ValLoc;
  1722.       cd->ValLoc(1) = co_rslt;
  1723.       cd->ElemTyp(2) = A_Str;
  1724.       cd->Str(2) = ", NULL, A_Coret, 1);";
  1725.       cd_add(cd);
  1726.       cd_add(sig_cd(on_failure, cur_fnc)); /* if reactivated, resume expr */
  1727.       }
  1728.  
  1729.    /*
  1730.     * Output the new frame definition.
  1731.     */
  1732.    prt_frame(frm_prfx, cur_proc->tnd_loc + num_tmp + Abs(cur_proc->nargs),
  1733.       num_itmp, num_dtmp, num_sbuf, num_cbuf);
  1734.  
  1735.    /*
  1736.     * Now return to original function and produce code to create the
  1737.     *  co-expression.
  1738.     */
  1739.    cur_fnc = fnc_sav;
  1740.    for (i = 0; i < PrfxSz; ++i)
  1741.       frm_prfx[i] = sav_prfx[i];
  1742.    on_failure = fail_sav;
  1743.  
  1744.    lastfiln = "";  /* force setting of file name and line number */
  1745.    lastline = 0;
  1746.    setloc(n);
  1747.    cd = NewCode(5);
  1748.    cd->cd_id =  C_Create;
  1749.    cd->Rslt = rslt;
  1750.    cd->Cont = fnc;
  1751.    cd->NTemps = num_tmp;
  1752.    cd->WrkSize = num_itmp;
  1753.    cd->NextCreat = cur_fnc->creatlst;
  1754.    cur_fnc->creatlst = cd;
  1755.    cd_add(cd);
  1756.  
  1757.    /*
  1758.     * Restore arrays for temporary variable allocation.
  1759.     */
  1760.    free((char *)tmp_status);
  1761.    free((char *)itmp_status);
  1762.    free((char *)dtmp_status);
  1763.    free((char *)sbuf_status);
  1764.    free((char *)cbuf_status);
  1765.    tmp_status = tmp_sv;
  1766.    itmp_status = itmp_sv;
  1767.    dtmp_status = dtmp_sv;
  1768.    sbuf_status = sbuf_sv;
  1769.    cbuf_status = cbuf_sv;
  1770.    status_sz = stat_sz_sv;
  1771.    istatus_sz = istat_sz_sv;
  1772.    dstatus_sz = dstat_sz_sv;
  1773.    sstatus_sz = sstat_sz_sv;
  1774.    cstatus_sz = cstat_sz_sv;
  1775.    num_tmp = ntmp_sv;
  1776.    num_itmp = nitmp_sv;
  1777.    num_dtmp = ndtmp_sv;
  1778.    num_sbuf = nsbuf_sv;
  1779.    num_cbuf = ncbuf_sv;
  1780.  
  1781.    /*
  1782.     * Temporary variables that exist to the end of the co-expression
  1783.     *   have no meaning in the surrounding code and must not be
  1784.     *   deallocated there.
  1785.     */
  1786.    while (n->freetmp != NULL) {
  1787.       ft = n->freetmp->next;
  1788.       n->freetmp->next = freetmp_pool;
  1789.       freetmp_pool = n->freetmp;
  1790.       n->freetmp = ft;
  1791.       }
  1792.  
  1793.    return rslt;
  1794.    }
  1795.  
  1796. /*
  1797.  * gen_lim - generate code for limitation.
  1798.  */
  1799. static struct val_loc *gen_lim(n, rslt)
  1800. struct node *n;
  1801. struct val_loc *rslt;
  1802.    {
  1803.    struct node *expr;
  1804.    struct node *limit;
  1805.    struct val_loc *lim_desc;
  1806.    struct code *cd;
  1807.    struct code *cd1;
  1808.    struct code *lbl;
  1809.    struct code *fail_sav;
  1810.    struct c_fnc *fnc_sav;
  1811.    struct c_fnc *succ_cont;
  1812.    struct val_loc *lim_int;
  1813.    struct lentry *single;
  1814.    int deref;
  1815.  
  1816.    expr = Tree0(n);
  1817.    limit = Tree1(n);
  1818.  
  1819.    /*
  1820.     * Generate code to compute the limitation value and dereference it.
  1821.     */
  1822.    deref = HasVar(varsubtyp(limit->type, &single));
  1823.    if (single != NULL) {
  1824.       /*
  1825.        * Limitation is in a named variable. Use value directly from
  1826.        *  the variable rather than saving the result of the expression.
  1827.        */
  1828.       gencode(limit, &ignore);
  1829.       lim_desc = var_ref(single);
  1830.       }
  1831.    else {
  1832.       lim_desc = gencode(limit, NULL);
  1833.       if (deref)
  1834.          deref_cd(lim_desc, lim_desc);
  1835.       }
  1836.  
  1837.    setloc(n);
  1838.    fail_sav = on_failure;
  1839.  
  1840.    /*
  1841.     * Try to convert the limitation value into an integer.
  1842.     */
  1843.    lim_int = itmp_loc(alc_itmp(n->intrnl_lftm));
  1844.    cur_symtyps = n->symtyps;
  1845.    if (largeints || (eval_is(int_typ, 0) & MaybeFalse)) {
  1846.       /*
  1847.        * Must call the conversion routine.
  1848.        */
  1849.       lbl = alc_lbl("limit is int", 0);
  1850.       cd_add(lbl);
  1851.       cur_fnc->cursor = lbl->prev;        /* conversion goes before label */
  1852.       cd = NewCode(2);
  1853.       cd->cd_id = C_If;
  1854.       cd1 = alc_ary(5);
  1855.       cd1->ElemTyp(0) = A_Str;
  1856.       cd1->Str(0) =                  "cnv_c_int(&";
  1857.       cd1->ElemTyp(1) = A_ValLoc;
  1858.       cd1->ValLoc(1) =               lim_desc;
  1859.       cd1->ElemTyp(2) = A_Str;
  1860.       cd1->Str(2) =                  ", &";
  1861.       cd1->ElemTyp(3) = A_ValLoc;
  1862.       cd1->ValLoc(3) =                lim_int;
  1863.       cd1->ElemTyp(4) = A_Str;
  1864.       cd1->Str(4) =                  ")";
  1865.       cd->Cond = cd1;
  1866.       cd->ThenStmt = mk_goto(lbl);
  1867.       cd_add(cd);
  1868.       cd = alc_ary(3);
  1869.       cd->ElemTyp(0) = A_Str;
  1870.       cd->Str(0) =                  "err_msg(101, &";
  1871.       cd->ElemTyp(1) = A_ValLoc;
  1872.       cd->ValLoc(1) =               lim_desc;
  1873.       cd->ElemTyp(2) = A_Str;
  1874.       cd->Str(2) =                  ");";
  1875.       cd_add(cd);
  1876.       if (err_conv)
  1877.          cd_add(sig_cd(on_failure, cur_fnc));
  1878.       cur_fnc->cursor = lbl;
  1879.       }
  1880.    else {
  1881.       /*
  1882.        * The C integer is in the vword.
  1883.        */
  1884.       cd = alc_ary(4);
  1885.       cd->ElemTyp(0) = A_ValLoc;
  1886.       cd->ValLoc(0) =                lim_int;
  1887.       cd->ElemTyp(1) = A_Str;
  1888.       cd->Str(1) =                   " = IntVal(";
  1889.       cd->ElemTyp(2) = A_ValLoc;
  1890.       cd->ValLoc(2) =                lim_desc;
  1891.       cd->ElemTyp(3) = A_Str;
  1892.       cd->Str(3) =                   ");";
  1893.       cd_add(cd);
  1894.       }
  1895.  
  1896.    /*
  1897.     * Make sure the limitation value is positive.
  1898.     */
  1899.    lbl = alc_lbl("limit positive", 0);
  1900.    cd_add(lbl);
  1901.    cur_fnc->cursor = lbl->prev;        /* code goes before label */
  1902.    cd = NewCode(2);
  1903.    cd->cd_id = C_If;
  1904.    cd1 = alc_ary(2);
  1905.    cd1->ElemTyp(0) = A_ValLoc;
  1906.    cd1->ValLoc(0) =                lim_int;
  1907.    cd1->ElemTyp(1) = A_Str;
  1908.    cd1->Str(1) =                  " >= 0";
  1909.    cd->Cond = cd1;
  1910.    cd->ThenStmt = mk_goto(lbl);
  1911.    cd_add(cd);
  1912.    cd = alc_ary(3);
  1913.    cd->ElemTyp(0) = A_Str;
  1914.    cd->Str(0) =                  "err_msg(205, &";
  1915.    cd->ElemTyp(1) = A_ValLoc;
  1916.    cd->ValLoc(1) =               lim_desc;
  1917.    cd->ElemTyp(2) = A_Str;
  1918.    cd->Str(2) =                  ");";
  1919.    cd_add(cd);
  1920.    if (err_conv)
  1921.       cd_add(sig_cd(on_failure, cur_fnc));
  1922.    cur_fnc->cursor = lbl;
  1923.  
  1924.    /*
  1925.     * If the limitation value is 0, fail immediately.
  1926.     */
  1927.    cd = NewCode(2);
  1928.    cd->cd_id = C_If;
  1929.    cd1 = alc_ary(2);
  1930.    cd1->ElemTyp(0) = A_ValLoc;
  1931.    cd1->ValLoc(0) =              lim_int;
  1932.    cd1->ElemTyp(1) = A_Str;
  1933.    cd1->Str(1) =                  " == 0";
  1934.    cd->Cond = cd1;
  1935.    cd->ThenStmt = sig_cd(on_failure, cur_fnc);
  1936.    cd_add(cd);
  1937.  
  1938.    /*
  1939.     * Establish where to go when limit has been reached.
  1940.     */
  1941.    fnc_sav = cur_fnc;
  1942.    lbl = alc_lbl("limit", 0);
  1943.    cd_add(lbl);
  1944.    cur_fnc->cursor = lbl->prev;  /* limited expression goes before label */
  1945.  
  1946.    /*
  1947.     * Generate code for limited expression and to check the limit value.
  1948.     */
  1949.    rslt = gencode(expr, rslt);
  1950.    cd = NewCode(2);
  1951.    cd->cd_id = C_If;
  1952.    cd1 = alc_ary(3);
  1953.    cd1->ElemTyp(0) = A_Str;
  1954.    cd1->Str(0) =                  "--";
  1955.    cd1->ElemTyp(1) = A_ValLoc;
  1956.    cd1->ValLoc(1) =               lim_int;
  1957.    cd1->ElemTyp(2) = A_Str;
  1958.    cd1->Str(2) =                  " == 0";
  1959.    cd->Cond = cd1;
  1960.    cd->ThenStmt = sig_cd(lbl, cur_fnc);
  1961.    cd_add(cd);
  1962.  
  1963.    /*
  1964.     * Call the success continuation both here and after the limitation
  1965.     *  label.
  1966.     */
  1967.    succ_cont = alc_fnc();
  1968.    callc_add(succ_cont);
  1969.    cur_fnc = fnc_sav;
  1970.    cur_fnc->cursor = lbl;
  1971.    on_failure = fail_sav;
  1972.    callc_add(succ_cont);
  1973.    cur_fnc = succ_cont;
  1974.    on_failure = &resume;
  1975.  
  1976.    return rslt;
  1977.    }
  1978.  
  1979. /*
  1980.  * gen_apply - generate code for the apply operator, !.
  1981.  */
  1982. static struct val_loc *gen_apply(n, rslt)
  1983. struct node *n;
  1984. struct val_loc *rslt;
  1985.    {
  1986.    struct val_loc *callee;
  1987.    struct val_loc *lst;
  1988.    struct code *arg_lst;
  1989.    struct code *on_ret;
  1990.    struct c_fnc *fnc;
  1991.  
  1992.    /*
  1993.     * Generate code to compute the two operands.
  1994.     */
  1995.    callee = gencode(Tree0(n), NULL);
  1996.    lst = gencode(Tree1(n), NULL);
  1997.    rslt = chk_alc(rslt, n->lifetime);
  1998.    setloc(n);
  1999.  
  2000.    /*
  2001.     * Construct argument list for apply().
  2002.     */
  2003.    arg_lst = alc_ary(6);
  2004.    arg_lst->ElemTyp(0) = A_Str;
  2005.    arg_lst->Str(0) =                   "&";
  2006.    arg_lst->ElemTyp(1) = A_ValLoc;
  2007.    arg_lst->ValLoc(1) =                callee;
  2008.    arg_lst->ElemTyp(2) = A_Str;
  2009.    arg_lst->Str(2) =                   ", &";
  2010.    arg_lst->ElemTyp(3) = A_ValLoc;
  2011.    arg_lst->ValLoc(3) =                lst;
  2012.    arg_lst->ElemTyp(4) = A_Str;
  2013.    arg_lst->Str(4) =                   ", &";
  2014.    arg_lst->ElemTyp(5) = A_ValLoc;
  2015.    arg_lst->ValLoc(5) =                rslt;
  2016.  
  2017.    /*
  2018.     * Generate code to call apply(). Assume the operation can suspend and
  2019.     *   allocate a continuation. If it returns a "continue" signal,
  2020.     *   just break out of the signal handling code and fall into a call
  2021.     *   to the continuation.
  2022.     */
  2023.    on_ret = NewCode(1);      /* #fields for C_Break == #fields for C_Goto */
  2024.    on_ret->cd_id = C_Break;
  2025.    on_ret->next = NULL;
  2026.    on_ret->prev = NULL;
  2027.    fnc = alc_fnc();          /* success continuation */
  2028.    callo_add("apply", DoesFail | DoesRet | DoesSusp, fnc, 1, arg_lst, on_ret);
  2029.    callc_add(fnc);
  2030.    cur_fnc = fnc;            /* subsequent code goes in the continuation */
  2031.    on_failure = &resume;
  2032.  
  2033.    return rslt;
  2034.    }
  2035.  
  2036.  
  2037. /*
  2038.  * gen_scan - generate code for string scanning.
  2039.  */
  2040. static struct val_loc *gen_scan(n, rslt)
  2041. nodeptr n;
  2042. struct val_loc *rslt;
  2043.    {
  2044.    struct node *op;
  2045.    struct node *subj;
  2046.    struct node *body;
  2047.    struct scan_info *scanp;
  2048.    struct val_loc *asgn_var;
  2049.    struct val_loc *new_subj;
  2050.    struct val_loc *scan_rslt;
  2051.    struct tmplftm *lifetm_ary;
  2052.    struct lentry *subj_single;
  2053.    struct lentry *body_single;
  2054.    struct code *cd;
  2055.    struct code *cd1;
  2056.    struct code *lbl;
  2057.    struct implement *impl;
  2058.    int subj_deref;
  2059.    int body_deref;
  2060.    int op_tok;
  2061.    int tmp_indx;
  2062.  
  2063.    op = Tree0(n);          /* operator node '?' or '?:=' */
  2064.    subj = Tree1(n);        /* subject expression */
  2065.    body = Tree2(n);        /* scanning expression */
  2066.    op_tok = optab[Val0(op)].tok.t_type;
  2067.  
  2068.    /*
  2069.     * The location of the save areas for scanning environments is stored
  2070.     *  in list so they can be accessed by expressions that transfer
  2071.     *  control out of string scanning. Get the next list element and
  2072.     *  allocate the save areas in the procedure frame.
  2073.     */
  2074.    scanp = nxt_scan;
  2075.    if (nxt_scan->next == NULL)
  2076.       nxt_scan->next = NewStruct(scan_info);
  2077.    nxt_scan = nxt_scan->next;
  2078.    scanp->outer_sub = chk_alc(NULL, n->intrnl_lftm);
  2079.    scanp->outer_pos = itmp_loc(alc_itmp(n->intrnl_lftm));
  2080.    scanp->inner_sub = chk_alc(NULL, n->intrnl_lftm); 
  2081.    scanp->inner_pos = itmp_loc(alc_itmp(n->intrnl_lftm));
  2082.  
  2083.    subj_deref = HasVar(varsubtyp(subj->type, &subj_single));
  2084.    if (subj_single != NULL) {
  2085.       /*
  2086.        * The subject value is in a named variable. Use value directly from
  2087.        *  the variable rather than saving the result of the expression.
  2088.        */
  2089.       gencode(subj, &ignore);
  2090.       new_subj = var_ref(subj_single);
  2091.  
  2092.       if (op_tok == AUGQMARK) {
  2093.          body_deref = HasVar(varsubtyp(body->type, &body_single));
  2094.          if (body_single != NULL)
  2095.             scan_rslt = &ignore; /* we know where the value will be */
  2096.          else
  2097.             scan_rslt = chk_alc(NULL, n->intrnl_lftm);
  2098.          }
  2099.       else
  2100.          scan_rslt = rslt; /* result of 2nd operand is result of scanning */
  2101.       }
  2102.    else if (op_tok == AUGQMARK) {
  2103.       /*
  2104.        * Augmented string scanning using general assignment. The operands
  2105.        *  must be in consecutive locations.
  2106.        */
  2107.       lifetm_ary = alc_lftm(2, &n->n_field[1]);
  2108.       tmp_indx = alc_tmp(2, lifetm_ary);
  2109.       asgn_var = tmp_loc(tmp_indx++);
  2110.       scan_rslt = tmp_loc(tmp_indx);
  2111.       free((char *)lifetm_ary);
  2112.  
  2113.       gencode(subj, asgn_var);
  2114.       new_subj = chk_alc(NULL, n->intrnl_lftm);
  2115.       deref_cd(asgn_var, new_subj);
  2116.       }
  2117.    else {
  2118.       new_subj = gencode(subj, NULL);
  2119.       if (subj_deref)
  2120.           deref_cd(new_subj, new_subj);
  2121.       scan_rslt = rslt; /* result of 2nd operand is result of scanning */
  2122.       }
  2123.  
  2124.    /*
  2125.     * Produce code to save the old scanning environment.
  2126.     */
  2127.    setloc(op);
  2128.    save_env(scanp->outer_sub, scanp->outer_pos);
  2129.  
  2130.    /*
  2131.     * Produce code to handle failure of the body of string scanning.
  2132.     */
  2133.    lbl = alc_lbl("scan fail", 0);
  2134.    cd_add(lbl);
  2135.    restr_env(scanp->outer_sub, scanp->outer_pos);
  2136.    cd_add(sig_cd(on_failure, cur_fnc)); /* fail */
  2137.    cur_fnc->cursor = lbl->prev;         /* body goes before label */
  2138.    on_failure = lbl;
  2139.  
  2140.    /*
  2141.     * If necessary, try to convert the subject to a string. Note that if
  2142.     *   error conversion occurs, backtracking will restore old subject.
  2143.     */
  2144.    cur_symtyps = n->symtyps;
  2145.    if (eval_is(str_typ, 0) & MaybeFalse) {
  2146.       lbl = alc_lbl("&subject is string", 0);
  2147.       cd_add(lbl);
  2148.       cur_fnc->cursor = lbl->prev;        /* code goes before label */
  2149.       cd = NewCode(2);
  2150.       cd->cd_id = C_If;
  2151.       cd1 = alc_ary(3);
  2152.       cd1->ElemTyp(0) = A_Str;
  2153.       cd1->Str(0) =                 "cnv_str(&";
  2154.       cd1->ElemTyp(1) = A_ValLoc;
  2155.       cd1->ValLoc(1) =              new_subj;
  2156.       cd1->ElemTyp(2) = A_Str;
  2157.       cd1->Str(2) =                 ", &k_subject)";
  2158.       cd->Cond = cd1;
  2159.       cd->ThenStmt = mk_goto(lbl);
  2160.       cd_add(cd);
  2161.       cd = alc_ary(3);
  2162.       cd->ElemTyp(0) = A_Str;
  2163.       cd->Str(0) =                  "err_msg(103, &";
  2164.       cd->ElemTyp(1) = A_ValLoc;
  2165.       cd->ValLoc(1) =               new_subj;
  2166.       cd->ElemTyp(2) = A_Str;
  2167.       cd->Str(2) =                  ");";
  2168.       cd_add(cd);
  2169.       if (err_conv)
  2170.          cd_add(sig_cd(on_failure, cur_fnc));
  2171.       cur_fnc->cursor = lbl;
  2172.       }
  2173.    else {
  2174.       cd = alc_ary(3);
  2175.       cd->ElemTyp(0) = A_Str;
  2176.       cd->Str(0) =                  "k_subject = ";
  2177.       cd->ElemTyp(1) = A_ValLoc;
  2178.       cd->ValLoc(1) =               new_subj;
  2179.       cd->ElemTyp(2) = A_Str;
  2180.       cd->Str(2) =                  ";";
  2181.       cd_add(cd);
  2182.       }
  2183.    cd = alc_ary(1);
  2184.    cd->ElemTyp(0) = A_Str;
  2185.    cd->Str(0) =                 "k_pos = 1;";
  2186.    cd_add(cd);
  2187.  
  2188.    scan_rslt = gencode(body, scan_rslt);
  2189.  
  2190.    setloc(op);
  2191.    if (op_tok == AUGQMARK) {
  2192.       /*
  2193.        * '?:=' - perform assignment.
  2194.        */
  2195.       if (subj_single != NULL) {
  2196.          /*
  2197.           * Assignment to a named variable.
  2198.           */
  2199.          if (body_single != NULL)
  2200.             cd_add(mk_cpyval(new_subj, var_ref(body_single)));
  2201.          else if (body_deref)
  2202.             deref_cd(scan_rslt, new_subj);
  2203.          else
  2204.              cd_add(mk_cpyval(new_subj, scan_rslt));
  2205.          }
  2206.       else {
  2207.          /*
  2208.           * Use general assignment.
  2209.           */
  2210.          impl = optab[asgn_loc].binary;
  2211.          if (impl == NULL) {
  2212.             nfatal(op, "assignment not implemented", NULL);
  2213.             rslt = &ignore; /* make sure code generation can continue */
  2214.             }
  2215.          else {
  2216.             implproto(impl);
  2217.             rslt = chk_alc(rslt, n->lifetime);
  2218.             mk_callop(oper_name(impl), impl->ret_flag, asgn_var, 2, rslt,0);
  2219.             }
  2220.          }
  2221.       }
  2222.    else {
  2223.       /*
  2224.        * '?'
  2225.        */
  2226.       rslt = scan_rslt;
  2227.       }
  2228.  
  2229.    /*
  2230.     * Produce code restore subject and pos when the body of the
  2231.     *  scanning expression succeeds. The new subject and pos must
  2232.     *  be saved in case of resumption.
  2233.     */
  2234.    save_env(scanp->inner_sub, scanp->inner_pos);
  2235.    restr_env(scanp->outer_sub, scanp->outer_pos);
  2236.  
  2237.    /*
  2238.     * Produce code to handle resumption of string scanning.
  2239.     */
  2240.    lbl = alc_lbl("scan resume", 0);
  2241.    cd_add(lbl);
  2242.    save_env(scanp->outer_sub, scanp->outer_pos);
  2243.    restr_env(scanp->inner_sub, scanp->inner_pos);
  2244.    cd_add(sig_cd(on_failure, cur_fnc)); /* fail */
  2245.    cur_fnc->cursor = lbl->prev;     /* success continuation goes before label */
  2246.    on_failure = lbl;
  2247.  
  2248.    nxt_scan = scanp;
  2249.    return rslt;
  2250.    }
  2251.  
  2252. /*
  2253.  * gen_act - generate code for co-expression activation.
  2254.  */
  2255. static struct val_loc *gen_act(n, rslt)
  2256. nodeptr n;
  2257. struct val_loc *rslt;
  2258.    {
  2259.    struct node *op;
  2260.    struct node *transmit;
  2261.    struct node *coexpr;
  2262.    struct tmplftm *lifetm_ary;
  2263.    struct val_loc *trans_loc;
  2264.    struct val_loc *coexpr_loc;
  2265.    struct val_loc *asgn1;
  2266.    struct val_loc *asgn2;
  2267.    struct val_loc *act_rslt;
  2268.    struct lentry *c_single;
  2269.    struct code *cd;
  2270.    struct code *cd1;
  2271.    struct code *lbl;
  2272.    struct implement *impl;
  2273.    int c_deref;
  2274.    int op_tok;
  2275.    int tmp_indx;
  2276.  
  2277.    op = Tree0(n);        /* operator node for '@' or '@:=' */
  2278.    transmit = Tree1(n);  /* expression for value to transmit */
  2279.    coexpr = Tree2(n);    /* expression for co-expression */
  2280.    op_tok = optab[Val0(op)].tok.t_type;
  2281.  
  2282.    /*
  2283.     * Produce code for the value to be transmitted.
  2284.     */
  2285.    if (op_tok == AUGAT) {
  2286.       /*
  2287.        * Augmented activation. This is seldom used so don't try too
  2288.        *  hard to optimize it. Allocate contiguous temporaries for
  2289.        *  the operands to the assignment.
  2290.        */
  2291.       lifetm_ary = alc_lftm(2, &n->n_field[1]);
  2292.       tmp_indx = alc_tmp(2, lifetm_ary);
  2293.       asgn1 = tmp_loc(tmp_indx++);
  2294.       asgn2 = tmp_loc(tmp_indx);
  2295.       free((char *)lifetm_ary);
  2296.  
  2297.       /*
  2298.        * Generate code to produce the left-hand-side of the assignment.
  2299.        *  This is also the transmitted value. Activation may need a
  2300.        *  dereferenced value, so this must be in a different location.
  2301.        */
  2302.       gencode(transmit, asgn1);
  2303.       trans_loc = chk_alc(NULL, n->intrnl_lftm);
  2304.       setloc(op);
  2305.       deref_ret(asgn1, trans_loc, varsubtyp(transmit->type, NULL));
  2306.       }
  2307.    else
  2308.       trans_loc = genretval(op, transmit, NULL); /* ordinary activation */
  2309.  
  2310.    /*
  2311.     * Determine if the value to be activated needs dereferencing, and
  2312.     *  see if it can only come from a single named variable.
  2313.     */
  2314.    c_deref = HasVar(varsubtyp(coexpr->type, &c_single));
  2315.    if (c_single == NULL) {
  2316.       /*
  2317.        * The value is something other than a single named variable.
  2318.        */
  2319.       coexpr_loc = gencode(coexpr, NULL);
  2320.       if (c_deref)
  2321.          deref_cd(coexpr_loc, coexpr_loc);
  2322.       }
  2323.    else {
  2324.       /*
  2325.        * The value is in a named variable. Use it directly from the
  2326.        *  variable rather than saving the result of the expression.
  2327.        */
  2328.       gencode(coexpr, &ignore);
  2329.       coexpr_loc = var_ref(c_single);
  2330.       }
  2331.  
  2332.    /*
  2333.     * Make sure the value to be activated is a co-expression. Perform
  2334.     *   run-time checking if necessary.
  2335.     */
  2336.    cur_symtyps = n->symtyps;
  2337.    if (eval_is(coexp_typ, 1) & MaybeFalse) {
  2338.       lbl = alc_lbl("is co-expression", 0);
  2339.       cd_add(lbl);
  2340.       cur_fnc->cursor = lbl->prev;        /* code goes before label */
  2341.       cd = NewCode(2);
  2342.       cd->cd_id = C_If;
  2343.       cd1 = alc_ary(3);
  2344.       cd1->ElemTyp(0) = A_Str;
  2345.       cd1->Str(0) =                  "(";
  2346.       cd1->ElemTyp(1) = A_ValLoc;
  2347.       cd1->ValLoc(1) =               coexpr_loc;
  2348.       cd1->ElemTyp(2) = A_Str;
  2349.       cd1->Str(2) =                  ").dword == D_Coexpr";
  2350.       cd->Cond = cd1;
  2351.       cd->ThenStmt = mk_goto(lbl);
  2352.       cd_add(cd);
  2353.       cd = alc_ary(3);
  2354.       cd->ElemTyp(0) = A_Str;
  2355.       cd->Str(0) =                   "err_msg(118, &(";
  2356.       cd->ElemTyp(1) = A_ValLoc;
  2357.       cd->ValLoc(1) =                coexpr_loc;
  2358.       cd->ElemTyp(2) = A_Str;
  2359.       cd->Str(2) =                   "));";
  2360.       cd_add(cd);
  2361.       if (err_conv)
  2362.          cd_add(sig_cd(on_failure, cur_fnc));
  2363.       cur_fnc->cursor = lbl;
  2364.       }
  2365.  
  2366.    /*
  2367.     * Make sure a result location has been allocated. For ordinary
  2368.     *  activation, this is where activate() puts its result. For
  2369.     *  augmented activation, this is where assignment puts its result.
  2370.     */
  2371.    rslt = chk_alc(rslt, n->lifetime);
  2372.    if (op_tok == AUGAT)
  2373.       act_rslt = asgn2;
  2374.    else
  2375.       act_rslt = rslt;
  2376.  
  2377.    /*
  2378.     * Generate code to call activate().
  2379.     */
  2380.    setloc(n);
  2381.    cd = NewCode(2);
  2382.    cd->cd_id = C_If;
  2383.    cd1 = alc_ary(7);
  2384.    cd1->ElemTyp(0) = A_Str;
  2385.    cd1->Str(0) =                  "activate(&";
  2386.    cd1->ElemTyp(1) = A_ValLoc;
  2387.    cd1->ValLoc(1) =                trans_loc;
  2388.    cd1->ElemTyp(2) = A_Str;
  2389.    cd1->Str(2) =                  ", (struct b_coexpr *)BlkLoc(";
  2390.    cd1->ElemTyp(3) = A_ValLoc;
  2391.    cd1->ValLoc(3) =                coexpr_loc;
  2392.    cd1->ElemTyp(4) = A_Str;
  2393.    cd1->Str(4) =                  "), &";
  2394.    cd1->ElemTyp(5) = A_ValLoc;
  2395.    cd1->ValLoc(5) =                act_rslt;
  2396.    cd1->ElemTyp(6) = A_Str;
  2397.    cd1->Str(6) =                  ") == A_Resume";
  2398.    cd->Cond = cd1;
  2399.    cd->ThenStmt = sig_cd(on_failure, cur_fnc);
  2400.    cd_add(cd);
  2401.  
  2402.    /*
  2403.     * For augmented activation, generate code to call assignment.
  2404.     */
  2405.    if (op_tok == AUGAT) {
  2406.       impl = optab[asgn_loc].binary;
  2407.       if (impl == NULL) {
  2408.          nfatal(op, "assignment not implemented", NULL);
  2409.          rslt = &ignore; /* make sure code generation can continue */
  2410.          }
  2411.       else {
  2412.          implproto(impl);
  2413.          mk_callop(oper_name(impl), impl->ret_flag, asgn1, 2, rslt, 0);
  2414.          }
  2415.       }
  2416.  
  2417.    return rslt;
  2418.    }
  2419.  
  2420. /*
  2421.  * save_env - generate code to save scanning environment.
  2422.  */
  2423. static novalue save_env(sub_sav, pos_sav)
  2424. struct val_loc *sub_sav;
  2425. struct val_loc *pos_sav;
  2426.    {
  2427.    struct code *cd;
  2428.  
  2429.    cd = alc_ary(2);
  2430.    cd->ElemTyp(0) = A_ValLoc;
  2431.    cd->ValLoc(0) =              sub_sav;
  2432.    cd->ElemTyp(1) = A_Str;
  2433.    cd->Str(1) =                 " = k_subject;";
  2434.    cd_add(cd);
  2435.    cd = alc_ary(2);
  2436.    cd->ElemTyp(0) = A_ValLoc;
  2437.    cd->ValLoc(0) =              pos_sav;
  2438.    cd->ElemTyp(1) = A_Str;
  2439.    cd->Str(1) =                 " = k_pos;";
  2440.    cd_add(cd);
  2441.    }
  2442.  
  2443. /*
  2444.  * restr_env - generate code to restore scanning environment.
  2445.  */
  2446. static novalue restr_env(sub_sav, pos_sav)
  2447. struct val_loc *sub_sav;
  2448. struct val_loc *pos_sav;
  2449.    {
  2450.    struct code *cd;
  2451.  
  2452.    cd = alc_ary(3);
  2453.    cd->ElemTyp(0) = A_Str;
  2454.    cd->Str(0) =                 "k_subject = ";
  2455.    cd->ElemTyp(1) = A_ValLoc;
  2456.    cd->ValLoc(1) =              sub_sav;
  2457.    cd->ElemTyp(2) = A_Str;
  2458.    cd->Str(2) =                 ";";
  2459.    cd_add(cd);
  2460.    cd = alc_ary(3);
  2461.    cd->ElemTyp(0) = A_Str;
  2462.    cd->Str(0) =                 "k_pos = ";
  2463.    cd->ElemTyp(1) = A_ValLoc;
  2464.    cd->ValLoc(1) =              pos_sav;
  2465.    cd->ElemTyp(2) = A_Str;
  2466.    cd->Str(2) =                 ";";
  2467.    cd_add(cd);
  2468.    }
  2469.  
  2470. /*
  2471.  * mk_callop - produce the code to directly call an operation.
  2472.  */
  2473. static novalue mk_callop(oper_nm, ret_flag, arg1rslt, nargs, rslt, optim)
  2474. char *oper_nm;
  2475. int ret_flag;
  2476. struct val_loc *arg1rslt;
  2477. int nargs;
  2478. struct val_loc *rslt;
  2479. int optim;
  2480.    {
  2481.    struct code *arg_lst;
  2482.    struct code *on_ret;
  2483.    struct c_fnc *fnc;
  2484.    int n;
  2485.    int need_cont;
  2486.  
  2487.    /*
  2488.     * If this operation can return an "continue" signal, we will need
  2489.     *   a break statement in the signal switch to handle it.
  2490.     */
  2491.    if (ret_flag & DoesRet) {
  2492.       on_ret = NewCode(1);      /* #fields == #fields C_Goto */
  2493.       on_ret->cd_id = C_Break;
  2494.       on_ret->next = NULL;
  2495.       on_ret->prev = NULL;
  2496.       }
  2497.    else
  2498.       on_ret = NULL;
  2499.  
  2500.    /*
  2501.     * Construct argument list for the C function implementing the
  2502.     *  operation. First compute the size of the code array for the
  2503.     *  argument list; this varies if we are using an optimized calling
  2504.     *  interface.
  2505.     */
  2506.    if (optim) {
  2507.       n = 0;
  2508.       if (arg1rslt != NULL)
  2509.          n += 2;
  2510.       if (ret_flag & (DoesRet | DoesSusp)) {
  2511.          if (n > 0)
  2512.             ++n;
  2513.          n += 2;
  2514.          }
  2515.       }
  2516.    else
  2517.       n = 7;
  2518.    if (n == 0)
  2519.       arg_lst = NULL;
  2520.    else {
  2521.       arg_lst = alc_ary(n);
  2522.       n = 0;
  2523.       if (!optim) {
  2524.          arg_lst->ElemTyp(n) = A_Intgr;       /* number of arguments */
  2525.          arg_lst->Intgr(n) = nargs;
  2526.          ++n;
  2527.          arg_lst->ElemTyp(n) = A_Str;        /* , */
  2528.          arg_lst->Str(n) = ", ";
  2529.          ++n;
  2530.          }
  2531.       if (arg1rslt == NULL) {             /* location of first argument */
  2532.          if (!optim) {
  2533.             arg_lst->ElemTyp(n) = A_Str;
  2534.             arg_lst->Str(n) = "NULL";
  2535.             ++n;
  2536.             arg_lst->ElemTyp(n) = A_Str;
  2537.             arg_lst->Str(n) = "";         /* nothing, but must fill slot */
  2538.             ++n;
  2539.             }
  2540.          }
  2541.       else {
  2542.          arg_lst->ElemTyp(n) = A_Str;
  2543.          arg_lst->Str(n) = "&";
  2544.          ++n;
  2545.          arg_lst->ElemTyp(n) = A_ValLoc;
  2546.          arg_lst->ValLoc(n) = arg1rslt;
  2547.          ++n;
  2548.          }
  2549.       if (!optim || ret_flag & (DoesRet | DoesSusp)) {
  2550.          if (n > 0) {
  2551.             arg_lst->ElemTyp(n) = A_Str;        /* , */
  2552.             arg_lst->Str(n) = ", ";
  2553.             ++n;
  2554.             }
  2555.          arg_lst->ElemTyp(n) = A_Str;        /* location of result */
  2556.          arg_lst->Str(n) = "&";
  2557.          ++n;
  2558.          arg_lst->ElemTyp(n) = A_ValLoc;
  2559.          arg_lst->ValLoc(n) = rslt;
  2560.          }
  2561.       }
  2562.  
  2563.    /*
  2564.     * Generate code to call the operation and handle returned signals.
  2565.     */
  2566.    if (ret_flag & DoesSusp) {
  2567.       /*
  2568.        * The operation suspends, so call it with a continuation, then
  2569.        *  proceed to generate code in the continuation.
  2570.        */
  2571.       fnc = alc_fnc();
  2572.       callo_add(oper_nm, ret_flag, fnc, 1, arg_lst, on_ret);
  2573.       if (ret_flag & DoesRet)
  2574.          callc_add(fnc);
  2575.       cur_fnc = fnc;
  2576.       on_failure = &resume;
  2577.       }
  2578.    else {
  2579.       /*
  2580.        * No continuation is needed, but if standard calling conventions
  2581.        *  are used, a NULL continuation argument is required.
  2582.        */
  2583.       if (optim)
  2584.          need_cont = 0;
  2585.       else
  2586.          need_cont = 1;
  2587.       callo_add(oper_nm, ret_flag, NULL, need_cont, arg_lst, on_ret);
  2588.       }
  2589.    }
  2590.  
  2591. /*
  2592.  * genretval - generate code for the expression in a return/suspend or
  2593.  *  for the expression for the value to be transmitted in a co-expression
  2594.  *  context switch.
  2595.  */
  2596. static struct val_loc *genretval(n, expr, dest)
  2597. struct node *n;
  2598. struct node *expr;
  2599. struct val_loc *dest;
  2600.    {
  2601.    int subtypes;
  2602.    struct lentry *single;
  2603.    struct val_loc *val;
  2604.  
  2605.    subtypes = varsubtyp(expr->type, &single);
  2606.  
  2607.    /*
  2608.     * If we have a single local or argument, we don't need to construct
  2609.     *  a variable reference; we need the value and we know where it is.
  2610.     */
  2611.    if (single != NULL && (subtypes & (HasLcl | HasPrm))) {
  2612.       gencode(expr, &ignore);
  2613.       val = var_ref(single);
  2614.       if (dest == NULL)
  2615.          dest = val;
  2616.       else
  2617.          cd_add(mk_cpyval(dest, val));
  2618.       }
  2619.    else {
  2620.       dest = gencode(expr, dest);
  2621.       setloc(n);
  2622.       deref_ret(dest, dest, subtypes);
  2623.       }
  2624.  
  2625.    return dest;
  2626.    }
  2627.  
  2628. /*
  2629.  * deref_ret - produced dereferencing code for values returned from
  2630.  *  procedures or transmitted to co-expressions.
  2631.  */
  2632. static novalue deref_ret(src, dest, subtypes)
  2633. struct val_loc *src;
  2634. struct val_loc *dest;
  2635. int subtypes;
  2636.    {
  2637.    struct code *cd;
  2638.    struct code *lbl;
  2639.  
  2640.    if (src == NULL)
  2641.       return;  /* no value to dereference */
  2642.  
  2643.    /*
  2644.     * If there may be values that do not need dereferencing, insure that the
  2645.     *  values are in the destination and make it the source of dereferencing.
  2646.     */
  2647.    if ((subtypes & (HasVal | HasGlb)) && (src != dest)) {
  2648.       cd_add(mk_cpyval(dest, src));
  2649.       src = dest;
  2650.       }
  2651.  
  2652.    if (subtypes & (HasLcl | HasPrm)) {
  2653.       /*
  2654.        * Some values may need to be dereferenced.
  2655.        */
  2656.       lbl = NULL;
  2657.       if (subtypes & HasVal) {
  2658.          /*
  2659.           * We may have a non-variable and must check at run time.
  2660.           */
  2661.          lbl = check_var(dest, NULL);
  2662.          }
  2663.  
  2664.       if (subtypes & HasGlb) {
  2665.          /*
  2666.           * Make sure we don't dereference any globals, use retderef().
  2667.           */
  2668.          if (subtypes & HasLcl) {
  2669.             /*
  2670.              * We must dereference any locals.
  2671.              */
  2672.             cd = alc_ary(3);
  2673.             cd->ElemTyp(0) = A_Str;
  2674.             cd->Str(0) =                "retderef(&";
  2675.             cd->ElemTyp(1) = A_ValLoc;
  2676.             cd->ValLoc(1) =             dest;
  2677.             cd->ElemTyp(2) = A_Str;
  2678.             cd->Str(2) =
  2679.                ", (word *)pfp->tend.d, (word *)(pfp->tend.d + pfp->tend.num));";
  2680.             cd_add(cd);
  2681.             /*
  2682.              * We may now have a value. We must check at run-time and skip
  2683.              *  any attempt to dereference an argument.
  2684.              */
  2685.             lbl = check_var(dest, lbl);
  2686.             }
  2687.    
  2688.          if (subtypes & HasPrm) {
  2689.             /*
  2690.              * We must dereference any arguments.
  2691.              */
  2692.             cd = alc_ary(5);
  2693.             cd->ElemTyp(0) = A_Str;
  2694.             cd->Str(0) =                "retderef(&";
  2695.             cd->ElemTyp(1) = A_ValLoc;
  2696.             cd->ValLoc(1) =             dest;
  2697.             cd->ElemTyp(2) = A_Str;
  2698.             cd->Str(2) =                ", (word *)argp, (word *)(argp + ";
  2699.             cd->ElemTyp(3) = A_Intgr;
  2700.             cd->Intgr(3) =              Abs(cur_proc->nargs);
  2701.             cd->ElemTyp(4) = A_Str;
  2702.             cd->Str(4) =                 "));";
  2703.             cd_add(cd);
  2704.             }
  2705.          }
  2706.       else /* No globals */
  2707.          deref_cd(src, dest);
  2708.  
  2709.       if (lbl != NULL)
  2710.          cur_fnc->cursor = lbl;   /* continue after label */
  2711.       }
  2712.    }
  2713.  
  2714. /*
  2715.  * check_var - generate code to make sure a descriptor contains a variable
  2716.  *  reference. If no label is given to jump to for a non-variable, allocate
  2717.  *  one and generate code before it.
  2718.  */
  2719. static struct code *check_var(d, lbl)
  2720. struct val_loc *d;
  2721. struct code *lbl;
  2722.    {
  2723.    struct code *cd, *cd1;
  2724.  
  2725.    if (lbl == NULL) {
  2726.       lbl = alc_lbl("not variable", 0);
  2727.       cd_add(lbl);
  2728.       cur_fnc->cursor = lbl->prev;        /* code goes before label */
  2729.       }
  2730.  
  2731.    cd = NewCode(2);
  2732.    cd->cd_id = C_If;
  2733.    cd1 = alc_ary(3);
  2734.    cd1->ElemTyp(0) = A_Str;
  2735.    cd1->Str(0) =                  "!Var(";
  2736.    cd1->ElemTyp(1) = A_ValLoc;
  2737.    cd1->ValLoc(1) =               d;
  2738.    cd1->ElemTyp(2) = A_Str;
  2739.    cd1->Str(2) =                  ")";
  2740.    cd->Cond = cd1;
  2741.    cd->ThenStmt = mk_goto(lbl);
  2742.    cd_add(cd);
  2743.  
  2744.    return lbl;
  2745.    }
  2746.  
  2747. /*
  2748.  * field_ref - generate code for a field reference.
  2749.  */
  2750. static struct val_loc *field_ref(n, rslt)
  2751. struct node *n;
  2752. struct val_loc *rslt;
  2753.    {
  2754.    struct node *rec;
  2755.    struct node *fld;
  2756.    struct fentry *fp;
  2757.    struct par_rec *rp;
  2758.    struct val_loc *rec_loc;
  2759.    struct code *cd;
  2760.    struct code *cd1;
  2761.    struct code *lbl;
  2762.    struct lentry *single;
  2763.    int deref;
  2764.    int num_offsets;
  2765.    int offset;
  2766.    int bad_recs;
  2767.  
  2768.    rec = Tree0(n);
  2769.    fld = Tree1(n);
  2770.  
  2771.    /*
  2772.     * Generate code to compute the record value and dereference it.
  2773.     */
  2774.    deref = HasVar(varsubtyp(rec->type, &single));
  2775.    if (single != NULL) {
  2776.       /*
  2777.        * The record is in a named variable. Use value directly from
  2778.        *  the variable rather than saving the result of the expression.
  2779.        */
  2780.       gencode(rec, &ignore);
  2781.       rec_loc = var_ref(single);
  2782.       }
  2783.    else {
  2784.       rec_loc = gencode(rec, NULL);
  2785.       if (deref)
  2786.          deref_cd(rec_loc, rec_loc);
  2787.       }
  2788.  
  2789.    setloc(fld);
  2790.  
  2791.    /*
  2792.     * Make sure the operand is a record.
  2793.     */
  2794.    cur_symtyps = n->symtyps;
  2795.    if (eval_is(rec_typ, 0) & MaybeFalse) {
  2796.       lbl = alc_lbl("is record", 0);
  2797.       cd_add(lbl);
  2798.       cur_fnc->cursor = lbl->prev;        /* code goes before label */
  2799.       cd = NewCode(2);
  2800.       cd->cd_id = C_If;
  2801.       cd1 = alc_ary(3);
  2802.       cd1->ElemTyp(0) = A_Str;
  2803.       cd1->Str(0) =                  "(";
  2804.       cd1->ElemTyp(1) = A_ValLoc;
  2805.       cd1->ValLoc(1) =               rec_loc;
  2806.       cd1->ElemTyp(2) = A_Str;
  2807.       cd1->Str(2) =                  ").dword == D_Record";
  2808.       cd->Cond = cd1;
  2809.       cd->ThenStmt = mk_goto(lbl);
  2810.       cd_add(cd);
  2811.       cd = alc_ary(3);
  2812.       cd->ElemTyp(0) = A_Str;
  2813.       cd->Str(0) =                   "err_msg(107, &";
  2814.       cd->ElemTyp(1) = A_ValLoc;
  2815.       cd->ValLoc(1) =                rec_loc;
  2816.       cd->ElemTyp(2) = A_Str;
  2817.       cd->Str(2) =                   ");";
  2818.       cd_add(cd);
  2819.       if (err_conv)
  2820.          cd_add(sig_cd(on_failure, cur_fnc));
  2821.       cur_fnc->cursor = lbl;
  2822.       }
  2823.  
  2824.    rslt = chk_alc(rslt, n->lifetime);
  2825.  
  2826.    /*
  2827.     * Find the list of records containing this field.
  2828.     */
  2829.    if ((fp = flookup(Str0(fld))) == NULL) {
  2830.       nfatal(n, "invalid field", Str0(fld));
  2831.       return rslt;
  2832.       }
  2833.  
  2834.    /*
  2835.     * Generate code for declarations and to get the record block pointer.
  2836.     */
  2837.    cd = alc_ary(1);
  2838.    cd->ElemTyp(0) = A_Str;
  2839.    cd->Str(0) =             "{";
  2840.    cd_add(cd);
  2841.    cd = alc_ary(3);
  2842.    cd->ElemTyp(0) = A_Str;
  2843.    cd->Str(0) =           "struct b_record *r_rp = (struct b_record *) BlkLoc(";
  2844.    cd->ElemTyp(1) = A_ValLoc;
  2845.    cd->ValLoc(1) =          rec_loc;
  2846.    cd->ElemTyp(2) = A_Str;
  2847.    cd->Str(2) =             ");";
  2848.    cd_add(cd);
  2849.    if (err_conv) {
  2850.       cd = alc_ary(1);
  2851.       cd->ElemTyp(0) = A_Str;
  2852.       cd->Str(0) =             "int r_must_fail = 0;";
  2853.       cd_add(cd);
  2854.       }
  2855.  
  2856.    /*
  2857.     * Determine which records are in the record type.
  2858.     */
  2859.    mark_recs(fp, cur_symtyps->types[0], &num_offsets, &offset, &bad_recs);
  2860.  
  2861.    /*
  2862.     * Generate code to insure that the field belongs to the record
  2863.     *  and to index into the record block.
  2864.     */
  2865.    if (num_offsets == 1 && !bad_recs) {
  2866.       /*
  2867.        * We already know the offset of the field.
  2868.        */
  2869.       cd = alc_ary(4);
  2870.       cd->ElemTyp(0) = A_ValLoc;
  2871.       cd->ValLoc(0) =           rslt;
  2872.       cd->ElemTyp(1) = A_Str;
  2873.       cd->Str(1) =              ".dword = D_Var + ((word *)&r_rp->fields[";
  2874.       cd->ElemTyp(2) = A_Intgr;
  2875.       cd->Intgr(2) =            offset;
  2876.       cd->ElemTyp(3) = A_Str;
  2877.       cd->Str(3) =              "] - (word *)r_rp);";
  2878.       cd_add(cd);
  2879.       cd = alc_ary(3);
  2880.       cd->ElemTyp(0) = A_Str;
  2881.       cd->Str(0) =              "VarLoc(";
  2882.       cd->ElemTyp(1) = A_ValLoc;
  2883.       cd->ValLoc(1) =           rslt;
  2884.       cd->ElemTyp(2) = A_Str;
  2885.       cd->Str(2) =              ") = (dptr)r_rp;";
  2886.       cd_add(cd);
  2887.       for (rp = fp->rlist; rp != NULL; rp = rp->next)
  2888.          rp->mark = 0;
  2889.       }
  2890.    else {
  2891.       /*
  2892.        * The field appears in several records. generate code to determine
  2893.        *  which one it is.
  2894.        */
  2895.  
  2896.       cd = alc_ary(1);
  2897.       cd->ElemTyp(0) = A_Str;
  2898.       cd->Str(0) =              "dptr r_dp;";
  2899.       cd_add(cd);
  2900.       cd = alc_ary(1);
  2901.       cd->ElemTyp(0) = A_Str;
  2902.       cd->Str(0) =              "switch (r_rp->recdesc->proc.recnum) {";
  2903.       cd_add(cd);
  2904.  
  2905.       rp = fp->rlist;
  2906.       while (rp != NULL) {
  2907.          offset = rp->offset;
  2908.          while (rp != NULL && rp->offset == offset) {
  2909.             if (rp->mark) {
  2910.                rp->mark = 0;
  2911.                cd = alc_ary(3);
  2912.                cd->ElemTyp(0) = A_Str;
  2913.                cd->Str(0) =              "   case ";
  2914.                cd->ElemTyp(1) = A_Intgr;
  2915.                cd->Intgr(1) =            rp->rec->rec_num;
  2916.                cd->ElemTyp(2) = A_Str;
  2917.                cd->Str(2) =              ":";
  2918.                cd_add(cd);
  2919.                }
  2920.             rp = rp->next;
  2921.             }
  2922.  
  2923.          cd = alc_ary(3);
  2924.          cd->ElemTyp(0) = A_Str;
  2925.          cd->Str(0) =              "      r_dp = &r_rp->fields[";
  2926.          cd->ElemTyp(1) = A_Intgr;
  2927.          cd->Intgr(1) =                   offset;
  2928.          cd->ElemTyp(2) = A_Str;
  2929.          cd->Str(2) =                     "];";
  2930.          cd_add(cd);
  2931.          cd = alc_ary(1);
  2932.          cd->ElemTyp(0) = A_Str;
  2933.          cd->Str(0) =              "      break;";
  2934.          cd_add(cd);
  2935.          }
  2936.  
  2937.       cd = alc_ary(1);
  2938.       cd->ElemTyp(0) = A_Str;
  2939.       cd->Str(0) =              "   default:";
  2940.       cd_add(cd);
  2941.       cd = alc_ary(3);
  2942.       cd->ElemTyp(0) = A_Str;
  2943.       cd->Str(0) =              "      err_msg(207, &";
  2944.       cd->ElemTyp(1) = A_ValLoc;
  2945.       cd->ValLoc(1) =                   rec_loc;
  2946.       cd->ElemTyp(2) = A_Str;
  2947.       cd->Str(2) =                     ");";
  2948.       cd_add(cd);
  2949.       if (err_conv) {
  2950.          /*
  2951.           * The peephole analyzer doesn't know how to handle a goto or return
  2952.           *  in a switch statement, so just set a flag here.
  2953.           */
  2954.          cd = alc_ary(1);
  2955.          cd->ElemTyp(0) = A_Str;
  2956.          cd->Str(0) =       "      r_must_fail = 1;";
  2957.          cd_add(cd);
  2958.          }
  2959.       cd = alc_ary(1);
  2960.       cd->ElemTyp(0) = A_Str;
  2961.       cd->Str(0) =              "   }";
  2962.       cd_add(cd);
  2963.       if (err_conv) {
  2964.          /*
  2965.           * Now that we are out of the switch statement, see if the flag
  2966.           *   was set to indicate error conversion.
  2967.           */
  2968.          cd = NewCode(2);
  2969.          cd->cd_id = C_If;
  2970.          cd1 = alc_ary(1);
  2971.          cd1->ElemTyp(0) = A_Str;
  2972.          cd1->Str(0) =                  "r_must_fail";
  2973.          cd->Cond = cd1;
  2974.          cd->ThenStmt = sig_cd(on_failure, cur_fnc);
  2975.          cd_add(cd);
  2976.          }
  2977.       cd = alc_ary(2);
  2978.       cd->ElemTyp(0) = A_ValLoc;
  2979.       cd->ValLoc(0) =           rslt;
  2980.       cd->ElemTyp(1) = A_Str;
  2981.       cd->Str(1) =            ".dword = D_Var + ((word *)r_dp - (word *)r_rp);";
  2982.       cd_add(cd);
  2983.       cd = alc_ary(3);
  2984.       cd->ElemTyp(0) = A_Str;
  2985.       cd->Str(0) =              "VarLoc(";
  2986.       cd->ElemTyp(1) = A_ValLoc;
  2987.       cd->ValLoc(1) =           rslt;
  2988.       cd->ElemTyp(2) = A_Str;
  2989.       cd->Str(2) =              ") = (dptr)r_rp;";
  2990.       cd_add(cd);
  2991.       }
  2992.  
  2993.    cd = alc_ary(1);
  2994.    cd->ElemTyp(0) = A_Str;
  2995.    cd->Str(0) =              "}";
  2996.    cd_add(cd);
  2997.    return rslt;
  2998.    }
  2999.  
  3000. /*
  3001.  * bound - bound the code for the given sub-tree. If catch_fail is true,
  3002.  *   direct failure to the bounding label.
  3003.  */
  3004. static struct val_loc *bound(n, rslt, catch_fail)
  3005. struct node *n;
  3006. struct val_loc *rslt;
  3007. int catch_fail;
  3008.    {
  3009.    struct code *lbl1;
  3010.    struct code *fail_sav;
  3011.    struct c_fnc *fnc_sav;
  3012.  
  3013.    fnc_sav = cur_fnc;
  3014.    fail_sav = on_failure;
  3015.  
  3016.    lbl1 = alc_lbl("bound", Bounding);
  3017.    cd_add(lbl1);
  3018.    cur_fnc->cursor = lbl1->prev;     /* code goes before label */
  3019.    if (catch_fail)
  3020.       on_failure = lbl1;
  3021.  
  3022.    rslt = gencode(n, rslt);
  3023.  
  3024.    cd_add(sig_cd(lbl1, cur_fnc));   /* transfer control to bounding label */
  3025.    cur_fnc = fnc_sav;
  3026.    cur_fnc->cursor = lbl1;
  3027.  
  3028.    on_failure = fail_sav;
  3029.    return rslt;
  3030.    }
  3031.  
  3032. /*
  3033.  * cd_add - add a code struct at the cursor in the current function.
  3034.  */
  3035. novalue cd_add(cd)
  3036. struct code *cd;
  3037.    {
  3038.    register struct code *cursor;
  3039.  
  3040.    cursor = cur_fnc->cursor;
  3041.    cd->next = cursor->next;
  3042.    cd->prev = cursor;
  3043.    if (cursor->next != NULL)
  3044.       cursor->next->prev = cd;
  3045.    cursor->next = cd;
  3046.    cur_fnc->cursor = cd;
  3047.    }
  3048.  
  3049. /*
  3050.  * sig_cd - convert a signal/label into a goto or return signal in
  3051.  *   the context of the given function.
  3052.  */
  3053. struct code *sig_cd(sig, fnc)
  3054. struct code *sig;
  3055. struct c_fnc *fnc;
  3056.    {
  3057.    struct code *cd;
  3058.  
  3059.    if (sig->cd_id == C_Label && sig->Container == fnc)
  3060.       return mk_goto(sig);
  3061.    else {
  3062.       cd = NewCode(1);      /* # fields <= # fields of C_Goto */
  3063.       cd->cd_id = C_RetSig;
  3064.       cd->next = NULL;
  3065.       cd->prev = NULL;
  3066.       cd->SigRef = add_sig(sig, fnc);
  3067.       return cd;
  3068.       }
  3069.    }
  3070.  
  3071. /*
  3072.  * add_sig - add signal to list of signals returned by function.
  3073.  */
  3074. struct sig_lst *add_sig(sig, fnc)
  3075. struct code *sig;
  3076. struct c_fnc *fnc;
  3077.    {
  3078.    struct sig_lst *sl;
  3079.  
  3080.    for (sl = fnc->sig_lst; sl != NULL && sl->sig != sig; sl = sl->next)
  3081.       ;
  3082.    if (sl == NULL) {
  3083.       sl = NewStruct(sig_lst);
  3084.       sl->sig = sig;
  3085.       sl->ref_cnt = 1;
  3086.       sl->next = fnc->sig_lst;
  3087.       fnc->sig_lst = sl;
  3088.       }
  3089.    else
  3090.       ++sl->ref_cnt;
  3091.    return sl;
  3092.    }
  3093.  
  3094. /*
  3095.  * callc_add - add code to call a continuation. Note the action to be
  3096.  *  taken if the continuation returns resumption. The actual list
  3097.  *  signals returned and actions to take will be figured out after
  3098.  *  the continuation has been optimized.
  3099.  */
  3100. novalue callc_add(cont)
  3101. struct c_fnc *cont;
  3102.    {
  3103.    struct code *cd;
  3104.  
  3105.    cd = new_call();
  3106.    cd->OperName = NULL;
  3107.    cd->Cont = cont;
  3108.    cd->ArgLst = NULL;
  3109.    cd->ContFail = on_failure;
  3110.    cd->SigActs = NULL;
  3111.    ++cont->ref_cnt;
  3112.    }
  3113.  
  3114. /*
  3115.  * callo_add - add code to call an operation.
  3116.  */
  3117. novalue callo_add(oper_nm, ret_flag, cont, need_cont, arglist, on_ret)
  3118. char *oper_nm;
  3119. int ret_flag;
  3120. struct c_fnc *cont;
  3121. int need_cont;
  3122. struct code *arglist;
  3123. struct code *on_ret;
  3124.    {
  3125.    struct code *cd;
  3126.    struct code *cd1;
  3127.  
  3128.    cd = new_call();
  3129.    cd->OperName = oper_nm;
  3130.    cd->Cont = cont;
  3131.    if (need_cont)
  3132.       cd->Flags = NeedCont;
  3133.    cd->ArgLst = arglist;
  3134.    cd->ContFail = NULL;   /* operation handles failure from the continuation */
  3135.    /*
  3136.     * Decide how to handle the signals produced by the operation. (Those
  3137.     *  produced by the continuation will be examined after the continuation
  3138.     *  is optimized.)
  3139.     */
  3140.    cd->SigActs = NULL;
  3141.    if (MightFail(ret_flag))
  3142.       cd->SigActs = new_sgact(&resume, sig_cd(on_failure,cur_fnc), cd->SigActs);
  3143.    if (ret_flag & DoesRet)
  3144.       cd->SigActs = new_sgact(&contin, on_ret, cd->SigActs);
  3145.    if (ret_flag & DoesFThru) {
  3146.       cd1 = NewCode(1);      /* #fields == #fields C_Goto */
  3147.       cd1->cd_id = C_Break;
  3148.       cd1->next = NULL;
  3149.       cd1->prev = NULL;
  3150.       cd->SigActs = new_sgact(&fallthru, cd1, cd->SigActs);
  3151.       }
  3152.    if (cont != NULL)
  3153.       ++cont->ref_cnt;  /* increment reference count */
  3154.    }
  3155.  
  3156. /* 
  3157.  * Create a call, add it to the code for the current function, and 
  3158.  *  add it to the list of calls from the current function.
  3159.  */
  3160. static struct code *new_call()
  3161.    {
  3162.    struct code *cd;
  3163.  
  3164.    cd = NewCode(7);
  3165.    cd->cd_id = C_CallSig;
  3166.    cd_add(cd);
  3167.    cd->Flags = 0;
  3168.    cd->NextCall = cur_fnc->call_lst;
  3169.    cur_fnc->call_lst = cd;
  3170.    return cd;
  3171.    }
  3172.  
  3173. /*
  3174.  * sig_act - create a new binding of an action to a signal.
  3175.  */
  3176. struct sig_act *new_sgact(sig, cd, next)
  3177. struct code *sig;
  3178. struct code *cd;
  3179. struct sig_act *next;
  3180.    {
  3181.    struct sig_act *sa;
  3182.  
  3183.    sa = NewStruct(sig_act);
  3184.    sa->sig = sig;
  3185.    sa->cd = cd;
  3186.    sa->shar_act = NULL;
  3187.    sa->next = next;
  3188.    return sa;
  3189.    }
  3190.  
  3191. /*
  3192.  * setloc produces code to set the file name and line number to the
  3193.  *  source location of node n.  Code is only produced if the corresponding
  3194.  *  value has changed since the last time setloc was called.
  3195.  */
  3196. static novalue setloc(n)
  3197. nodeptr n;
  3198.    {
  3199.    struct code *cd;
  3200.  
  3201.    if (n == NULL || File(n) == NULL || Line(n) == 0)
  3202.       return;
  3203.  
  3204.    if (File(n) != lastfiln || Line(n) != lastline) {
  3205.       cd = alc_ary(1);
  3206.       cd->ElemTyp(0) = A_Str;
  3207.       cd->Str(0) = "Poll();";
  3208.       cd_add(cd);
  3209.       
  3210.       if (line_info) {
  3211.          cd = NewCode(2);
  3212.          cd->cd_id = C_SrcLoc;
  3213.    
  3214.          if (File(n) == lastfiln)
  3215.             cd->FileName = NULL;
  3216.          else {
  3217.             lastfiln = File(n);
  3218.             cd->FileName = lastfiln;
  3219.             }
  3220.    
  3221.          if (Line(n) == lastline)
  3222.             cd->LineNum = 0;
  3223.          else {
  3224.             lastline = Line(n);
  3225.             cd->LineNum = lastline;
  3226.             }
  3227.    
  3228.          cd_add(cd);
  3229.          }
  3230.       }
  3231.    }
  3232.  
  3233. /*
  3234.  * alc_ary - create an array for a sequence of code fragments.
  3235.  */
  3236. struct code *alc_ary(n)
  3237. int n;
  3238.    {
  3239.    struct code *cd;
  3240.  
  3241.    cd = NewCode(2 * n + 1);
  3242.    cd->cd_id = C_CdAry;
  3243.    cd->next = NULL;
  3244.    cd->prev = NULL;
  3245.    cd->ElemTyp(n) = A_End;
  3246.    return cd;
  3247.    }
  3248.  
  3249.  
  3250. /*
  3251.  * alc_lbl - create a label.
  3252.  */
  3253. struct code *alc_lbl(desc, flag)
  3254. char *desc;
  3255. int flag;
  3256.    {
  3257.    register struct code *cd;
  3258.  
  3259.    cd = NewCode(5);
  3260.    cd->cd_id = C_Label;
  3261.    cd->next = NULL;
  3262.    cd->prev = NULL;
  3263.    cd->Container = cur_fnc; /* function containing label */
  3264.    cd->SeqNum = 0;          /* sequence number is allocated later */
  3265.    cd->Desc = desc;         /* identifying comment */
  3266.    cd->RefCnt = 0;          /* reference count */
  3267.    cd->LabFlg = flag;
  3268.    return cd;
  3269.    }
  3270.  
  3271. /*
  3272.  * alc_fnc - allocate a function structure;
  3273.  */
  3274. static struct c_fnc *alc_fnc()
  3275.    {
  3276.    register struct c_fnc *cf;
  3277.    int i;
  3278.  
  3279.    cf = NewStruct(c_fnc);
  3280.    cf->prefix[0] = '\0';             /* prefix is allocated later */
  3281.    cf->prefix[PrfxSz] = '\0';        /* terminate prefix for printing */
  3282.    cf->flag = 0;
  3283.    for (i = 0; i < PrfxSz; ++i)
  3284.       cf->frm_prfx[i] = frm_prfx[i]; /* note procedure frame prefix */
  3285.    cf->frm_prfx[PrfxSz] = '\0';      /* terminate prefix for printing */
  3286.    cf->cd.cd_id = C_Null;            /* base of code sequence in function */
  3287.    cf->cd.next = NULL;
  3288.    cf->cursor = &cf->cd;             /* current place to insert code */
  3289.    cf->call_lst = NULL;              /* functions called by this function */
  3290.    cf->creatlst = NULL;              /* creates within this function */
  3291.    cf->sig_lst = NULL;               /* signals returned by this function */
  3292.    cf->ref_cnt = 0;
  3293.    cf->next = NULL;
  3294.    *flst_end = cf;                   /* link entry onto global list */
  3295.    flst_end = &(cf->next);
  3296.    return cf;
  3297.    }
  3298.  
  3299. /*
  3300.  * tmp_loc - allocate a value location structure for nth temporary descriptor
  3301.  *  variable in procedure frame.
  3302.  */
  3303. static struct val_loc *tmp_loc(n)
  3304. int n;
  3305.    {
  3306.    register struct val_loc *r;
  3307.  
  3308.    r = NewStruct(val_loc);
  3309.    r->loc_type = V_Temp;
  3310.    r->mod_access = M_None;
  3311.    r->u.tmp = n;
  3312.    return r;
  3313.    }
  3314.  
  3315. /*
  3316.  * itmp_loc - allocate a value location structure for nth temporary integer
  3317.  *  variable in procedure frame.
  3318.  */
  3319. struct val_loc *itmp_loc(n)
  3320. int n;
  3321.    {
  3322.    register struct val_loc *r;
  3323.  
  3324.    r = NewStruct(val_loc);
  3325.    r->loc_type = V_ITemp;
  3326.    r->mod_access = M_None;
  3327.    r->u.tmp = n;
  3328.    return r;
  3329.    }
  3330.  
  3331. /*
  3332.  * dtmp_loc - allocate a value location structure for nth temporary double
  3333.  *  variable in procedure frame.
  3334.  */
  3335. struct val_loc *dtmp_loc(n)
  3336. int n;
  3337.    {
  3338.    register struct val_loc *r;
  3339.  
  3340.    r = NewStruct(val_loc);
  3341.    r->loc_type = V_DTemp;
  3342.    r->mod_access = M_None;
  3343.    r->u.tmp = n;
  3344.    return r;
  3345.    }
  3346.  
  3347. /*
  3348.  * vararg_sz - allocate a value location structure that refers to the size
  3349.  *  of the variable part of an argument list.
  3350.  */
  3351. static struct val_loc *vararg_sz(n)
  3352. int n;
  3353.    {
  3354.    register struct val_loc *r;
  3355.  
  3356.    r = NewStruct(val_loc);
  3357.    r->loc_type = V_Const;
  3358.    r->mod_access = M_None;
  3359.    r->u.int_const = n;
  3360.    return r;
  3361.    }
  3362.  
  3363. /*
  3364.  * cvar_loc - allocate a value location structure for a C variable.
  3365.  */
  3366. struct val_loc *cvar_loc(name)
  3367. char *name;
  3368.    {
  3369.    register struct val_loc *r;
  3370.  
  3371.    r = NewStruct(val_loc);
  3372.    r->loc_type = V_CVar;
  3373.    r->mod_access = M_None;
  3374.    r->u.name = name;
  3375.    return r;
  3376.    }
  3377.  
  3378. /*
  3379.  * var_ref - allocate a value location structure for an Icon named variable.
  3380.  */
  3381. static struct val_loc *var_ref(sym)
  3382. struct lentry *sym;
  3383.    {
  3384.    struct val_loc *loc;
  3385.  
  3386.    loc = NewStruct(val_loc);
  3387.    loc->loc_type = V_NamedVar;
  3388.    loc->mod_access = M_None;
  3389.    loc->u.nvar = sym;
  3390.    return loc;
  3391.    }
  3392.  
  3393. /*
  3394.  * deref_cd - generate code to dereference a descriptor.
  3395.  */
  3396. static novalue deref_cd(src, dest)
  3397. struct val_loc *src;
  3398. struct val_loc *dest;
  3399.    {
  3400.    struct code *cd;
  3401.  
  3402.    cd = alc_ary(5);
  3403.    cd->ElemTyp(0) = A_Str;
  3404.    cd->Str(0) =                  "deref(&";
  3405.    cd->ElemTyp(1) = A_ValLoc;
  3406.    cd->ValLoc(1) =               src;
  3407.    cd->ElemTyp(2) = A_Str;
  3408.    cd->Str(2) =                  ", &";
  3409.    cd->ElemTyp(3) = A_ValLoc;
  3410.    cd->ValLoc(3) =               dest;
  3411.    cd->ElemTyp(4) = A_Str;
  3412.    cd->Str(4) =                  ");";
  3413.    cd_add(cd);
  3414.    }
  3415.  
  3416. /*
  3417.  * inv_op - directly invoke a run-time operation, in-lining it if possible.
  3418.  */
  3419. static struct val_loc *inv_op(n, rslt)
  3420. nodeptr n;
  3421. struct val_loc *rslt;
  3422.    {
  3423.    struct implement *impl;
  3424.    struct code *scont_strt;
  3425.    struct code *scont_fail;
  3426.    struct c_fnc *fnc;
  3427.    struct val_loc *frst_arg;
  3428.    struct val_loc *arg_rslt;
  3429.    struct val_loc *r;
  3430.    struct val_loc **varg_rslt;
  3431.    struct op_symentry *symtab;
  3432.    struct lentry **single;
  3433.    struct tmplftm *lifetm_ary;
  3434.    nodeptr rslt_lftm;
  3435.    char *sbuf;
  3436.    int *maybe_var;
  3437.    int may_mod;
  3438.    int nsyms;
  3439.    int nargs;
  3440.    int nparms;
  3441.    int cont_loc;
  3442.    int flag;
  3443.    int refs;
  3444.    int var_args;
  3445.    int n_varargs;
  3446.    int arg_loc;
  3447.    int dcl_var;
  3448.    int i;
  3449.    int j;
  3450.    int v;
  3451.  
  3452.    nargs = Val0(n);
  3453.    impl = Impl1(n);
  3454.    if (impl == NULL) {
  3455.       /*
  3456.        * We have already printed an error, just make sure we can
  3457.        *  continue.
  3458.        */
  3459.       return &ignore;
  3460.       }
  3461.  
  3462.    /*
  3463.     * If this operation uses its result location as a work area, it must
  3464.     *   be given a tended result location and the value must be retained
  3465.     *   as long as the operation can be resumed.
  3466.     */
  3467.    rslt_lftm = n->lifetime;
  3468.    if (impl->use_rslt) {
  3469.        rslt_lftm = max_lftm(rslt_lftm, n->intrnl_lftm);
  3470.        if (rslt == &ignore)
  3471.           rslt = NULL;      /* force allocation of temporary */
  3472.        }
  3473.  
  3474.    /*
  3475.     * Determine if this operation takes a variable number of arguments
  3476.     *  and determine the size of the variable part of the arg list.
  3477.     */
  3478.    nparms = impl->nargs;
  3479.    if (nparms > 0 && impl->arg_flgs[nparms - 1] & VarPrm) {
  3480.       var_args = 1;
  3481.       n_varargs = nargs - nparms + 1;
  3482.       if (n_varargs < 0)
  3483.          n_varargs = 0;
  3484.       }
  3485.    else {
  3486.       var_args = 0;
  3487.       n_varargs = 0;
  3488.       }
  3489.  
  3490.    /*
  3491.     * Construct a symbol table (implemented as an array) for the operation.
  3492.     *  The symbol table includes parameters, and both the tended and
  3493.     *  ordinary variables from the RTL declare statement.
  3494.     */
  3495.    nsyms = (n->symtyps == NULL ? 0 : n->symtyps->nsyms);
  3496.    if (var_args)
  3497.       ++nsyms;
  3498.    nsyms += impl->ntnds + impl->nvars;
  3499.    if (nsyms > 0)
  3500.       symtab = (struct op_symentry *)alloc((unsigned int)(nsyms *
  3501.          sizeof(struct op_symentry)));
  3502.    else
  3503.       symtab = NULL;
  3504.    for (i = 0; i < nsyms; ++i) {
  3505.       symtab[i].n_refs = 0;     /* number of non-modifying references */
  3506.       symtab[i].n_mods = 0;     /* number of modifying references */
  3507.       symtab[i].n_rets = 0;     /* number of times returned directly */
  3508.       symtab[i].var_safe = 0;   /* Icon variable arg can be passed directly */
  3509.       symtab[i].adjust = 0;     /* adjustments needed to "dereference" */
  3510.       symtab[i].itmp_indx = -1; /* loc after "in-place" convert to C integer */
  3511.       symtab[i].dtmp_indx = -1; /* loc after "in-place" convert to C double */
  3512.       symtab[i].loc = NULL;     /* location as a descriptor */
  3513.       }
  3514.  
  3515.    /*
  3516.     * If in-lining has not been disabled or the operation is a keyword,
  3517.     *  check to see if it can reasonably be in-lined and gather information
  3518.     *  needed to in-line it.
  3519.     */
  3520.    if ((allow_inline || impl->oper_typ == 'K') &&
  3521.       do_inlin(impl, n, &cont_loc, symtab, n_varargs)) {
  3522.       /*
  3523.        * In-line the operation.
  3524.        */
  3525.  
  3526.       if (impl->ret_flag & DoesRet || impl->ret_flag & DoesSusp)
  3527.          rslt = chk_alc(rslt, rslt_lftm);  /* operation produces a result */
  3528.  
  3529.       /*
  3530.        * Allocate arrays to hold information from type inferencing about
  3531.        *  whether arguments are variables. This is used to optimize
  3532.        *  dereferencing.
  3533.        */
  3534.       if (nargs > 0) {
  3535.          maybe_var = (int *)alloc((unsigned int)(nargs * sizeof(int)));
  3536.          single = (struct lentry **)alloc((unsigned int)(nargs *
  3537.             sizeof(struct lentry *)));
  3538.          }
  3539.  
  3540.       if (var_args)
  3541.          --nparms; /* don't deal with varargs parameter yet. */
  3542.  
  3543.       /*
  3544.        * Match arguments with parameters and generate code for the
  3545.        *  arguments. The type of code generated depends on the kinds
  3546.        *  of dereferencing optimizations that are possible, though
  3547.        *  in general, dereferencing must wait until all arguments are
  3548.        *  computed. Because there may be both dereferenced and undereferenced
  3549.        *  parameters for an argument, the symbol table index does not always
  3550.        *  match the argument index.
  3551.        */
  3552.       i = 0;  /* symbol table index */
  3553.       for (j = 0; j < nparms && j < nargs; ++j) {
  3554.          /*
  3555.           * Use information from type inferencing to determine if the
  3556.           *  argument might me a variable and whether it is a single
  3557.           *  known named variable.
  3558.           */
  3559.          maybe_var[j] = HasVar(varsubtyp(n->n_field[FrstArg + j].n_ptr->type,
  3560.              &(single[j])));
  3561.  
  3562.          /*
  3563.           * Determine how many times the argument is referenced. If we
  3564.           *  optimize away return statements because we don't need the
  3565.           *  result, those references don't count. Take into account
  3566.           *  that there may be both dereferenced and undereferenced
  3567.           *  parameters for this argument.
  3568.           */
  3569.          if (rslt == &ignore)
  3570.             symtab[i].n_refs -= symtab[i].n_rets;
  3571.          refs = symtab[i].n_refs + symtab[i].n_mods;
  3572.          flag = impl->arg_flgs[j] & (RtParm | DrfPrm);
  3573.          if (flag == (RtParm | DrfPrm))
  3574.             refs += symtab[i + 1].n_refs + symtab[i + 1].n_mods;
  3575.          if (refs == 0) {
  3576.             /*
  3577.              * Indicate that we don't need the argument value (we must
  3578.              *  still perform the computation in case it has side effects).
  3579.              */
  3580.             arg_rslt = &ignore;
  3581.             symtab[i].adjust = AdjNone;
  3582.             }
  3583.          else {
  3584.             /*
  3585.              * Decide whether the result location for the argument can be
  3586.              *  used directly as the parameter.
  3587.              */
  3588.             if (flag == (RtParm | DrfPrm) && symtab[i].n_refs +
  3589.                symtab[i].n_mods == 0) {
  3590.                   /*
  3591.                    * We have both dereferenced and undereferenced parameters,
  3592.                    *  but don't use the undereferenced one so ignore it.
  3593.                    */
  3594.                   symtab[i].adjust = AdjNone;
  3595.                   ++i;
  3596.                   flag = DrfPrm;
  3597.                   }    
  3598.             if (flag == DrfPrm && single[j] != NULL) {
  3599.                /*
  3600.                 * We need only a dereferenced value, but know what variable
  3601.                 *  it is in. We don't need the computed argument value, we will
  3602.                 *  get it directly from the variable. If it is safe to do
  3603.                 *  so, we will pass a pointer to the variable as the argument
  3604.                 *  to the operation.
  3605.                 */
  3606.                arg_rslt = &ignore;
  3607.                symtab[i].loc = var_ref(single[j]);
  3608.                if (symtab[i].var_safe)
  3609.                   symtab[i].adjust = AdjNone;
  3610.                else
  3611.                   symtab[i].adjust = AdjCpy;
  3612.                }
  3613.             else {
  3614.                /*
  3615.                 * Determine if the argument descriptor is modified by the
  3616.                 *  operation; dereferencing a variable is a modification.
  3617.                 */
  3618.                may_mod = (symtab[i].n_mods != 0);
  3619.                if (flag == DrfPrm)
  3620.                   may_mod |= maybe_var[j];
  3621.                if (n->n_field[FrstArg + j].n_ptr->reuse && may_mod) {
  3622.                   /*
  3623.                    * The parameter may be reused without recomputing
  3624.                    *  the argument and the value may be modified. The
  3625.                    *  argument result location and the parameter location
  3626.                    *  must be separate so the parameter is reloaded upon
  3627.                    *  each invocation.
  3628.                    */
  3629.                   arg_rslt = chk_alc(NULL,
  3630.                      n->n_field[FrstArg + j].n_ptr->lifetime);
  3631.                   if (flag == DrfPrm && maybe_var[j])
  3632.                      symtab[i].adjust = AdjNDrf;  /* var: must dereference */
  3633.                   else
  3634.                      symtab[i].adjust = AdjCpy;   /* value only: just copy */
  3635.                   }
  3636.                else {
  3637.                   /*
  3638.                    * Argument result location will act as parameter location.
  3639.                    *  Its lifetime must be as long as both that of the
  3640.                    *  the argument and the parameter (operation internal
  3641.                    *  lifetime).
  3642.                    */
  3643.                   arg_rslt = chk_alc(NULL, max_lftm(n->intrnl_lftm,
  3644.                      n->n_field[FrstArg + j].n_ptr->lifetime));
  3645.                   if (flag == DrfPrm && maybe_var[j])
  3646.                      symtab[i].adjust = AdjDrf;   /* var: must dereference */
  3647.                   else
  3648.                      symtab[i].adjust = AdjNone;
  3649.                   }
  3650.                symtab[i].loc = arg_rslt;
  3651.                }
  3652.             }
  3653.  
  3654.          /*
  3655.           * Generate the code for the argument.
  3656.           */
  3657.          gencode(n->n_field[FrstArg + j].n_ptr, arg_rslt);
  3658.  
  3659.          if (flag == (RtParm | DrfPrm)) {
  3660.             /*
  3661.              * We have computed the value for the undereferenced parameter,
  3662.              *  decide how to get the dereferenced value.
  3663.              */
  3664.             ++i;
  3665.             if (symtab[i].n_refs + symtab[i].n_mods == 0)
  3666.                symtab[i].adjust = AdjNone;  /* not needed, ignore */
  3667.             else {
  3668.                if (single[j] != NULL) {
  3669.                   /*
  3670.                    * The value is in a specific Icon variable, get it from
  3671.                    *  there. If is is safe to pass the variable directly
  3672.                    *  to the operation, do so.
  3673.                    */
  3674.                   symtab[i].loc = var_ref(single[j]);
  3675.                   if (symtab[i].var_safe)
  3676.                      symtab[i].adjust = AdjNone;
  3677.                   else
  3678.                      symtab[i].adjust = AdjCpy;
  3679.                   }
  3680.                else {
  3681.                   /*
  3682.                    * If there might be a variable reference, note that it
  3683.                    *  must be dereferenced. Otherwise decide whether the
  3684.                    *  argument location can be used for both the dereferenced
  3685.                    *  and undereferenced parameter.
  3686.                    */
  3687.                   symtab[i].loc = arg_rslt;
  3688.                   if (maybe_var[j])
  3689.                      symtab[i].adjust = AdjNDrf;
  3690.                   else if (symtab[i - 1].n_mods + symtab[i].n_mods == 0)
  3691.                      symtab[i].adjust = AdjNone;
  3692.                   else
  3693.                      symtab[i].adjust = AdjCpy;
  3694.                   }
  3695.                }
  3696.             }
  3697.          ++i;
  3698.          }
  3699.  
  3700.       /*
  3701.        * Fill out parameter list with null values.
  3702.        */
  3703.       while (j < nparms) {
  3704.          int k, kn;
  3705.          kn = 0;
  3706.          if (impl->arg_flgs[j] & RtParm)
  3707.             ++kn;
  3708.          if (impl->arg_flgs[j] & DrfPrm)
  3709.             ++kn;
  3710.          for (k = 0; k < kn; ++k) {
  3711.             if (symtab[i].n_refs + symtab[i].n_mods > 0) {
  3712.                arg_rslt = chk_alc(NULL, n->intrnl_lftm);
  3713.                cd_add(asgn_null(arg_rslt));
  3714.                symtab[i].loc = arg_rslt;
  3715.                }
  3716.             symtab[i].adjust = AdjNone;
  3717.             ++i;
  3718.             }
  3719.          ++j;
  3720.          }
  3721.  
  3722.       if (var_args) {
  3723.          /*
  3724.           * Compute variable part of argument list.
  3725.           */
  3726.          ++nparms;   /* add varargs parameter back into parameter list  */
  3727.  
  3728.          /*
  3729.           * The variable part of the parameter list must be in contiguous
  3730.           *  descriptors. Create location and lifetime arrays for use in
  3731.           *  allocating the descriptors.
  3732.           */
  3733.          if (n_varargs > 0) {
  3734.             varg_rslt = (struct val_loc **)alloc((unsigned int)(n_varargs *
  3735.                sizeof(struct val_loc *)));
  3736.             lifetm_ary = alc_lftm(n_varargs, NULL);
  3737.             }
  3738.  
  3739.          flag = impl->arg_flgs[j] & (RtParm | DrfPrm);
  3740.  
  3741.          /*
  3742.           * Compute the lifetime of the elements of the varargs parameter array.
  3743.           */
  3744.          for (v = 0; v < n_varargs; ++v) {
  3745.             /*
  3746.              * Use information from type inferencing to determine if the
  3747.              *  argument might me a variable and whether it is a single
  3748.              *  known named variable.
  3749.              */
  3750.             maybe_var[j + v] = HasVar(varsubtyp(
  3751.                n->n_field[FrstArg+j+v].n_ptr->type, &(single[j + v])));
  3752.  
  3753.             /*
  3754.              * Determine if the elements of the vararg parameter array
  3755.              *  might be modified. If it is a variable, dereferencing
  3756.              *  modifies it.
  3757.              */
  3758.             may_mod = (symtab[j].n_mods != 0);
  3759.             if (flag == DrfPrm)
  3760.                may_mod |= maybe_var[j + v];
  3761.  
  3762.             if ((flag == DrfPrm && single[j + v] != NULL) ||
  3763.                (n->n_field[FrstArg + j + v].n_ptr->reuse && may_mod)) {
  3764.                /*
  3765.                 * The argument value is only placed in the vararg parameter
  3766.                 *  array during "dereferencing". So the lifetime of the array
  3767.                 *  element is the lifetime of the parameter and the element
  3768.                 *  is not used until dereferencing.
  3769.                 */
  3770.                lifetm_ary[v].lifetime = n->intrnl_lftm;
  3771.                lifetm_ary[v].cur_status = n->postn;
  3772.                }
  3773.             else {
  3774.                /*
  3775.                 * The argument is computed into the vararg parameter array.
  3776.                 *  The lifetime of the array element encompasses both
  3777.                 *  the lifetime of the argument and the parameter. The
  3778.                 *  element is used as soon as the argument is computed.
  3779.                 */
  3780.                lifetm_ary[v].lifetime = max_lftm(n->intrnl_lftm,
  3781.                    n->n_field[FrstArg+j+v].n_ptr->lifetime);
  3782.                lifetm_ary[v].cur_status = n->n_field[FrstArg+j+v].n_ptr->postn;
  3783.                }
  3784.             }
  3785.  
  3786.          /*
  3787.           * Allocate (reserve) the array of temporary variables for the
  3788.           *  vararg list.
  3789.           */
  3790.          if (n_varargs > 0) {
  3791.             arg_loc = alc_tmp(n_varargs, lifetm_ary);
  3792.             free((char *)lifetm_ary);
  3793.             }
  3794.  
  3795.          /*
  3796.           * Generate code to compute arguments.
  3797.           */
  3798.          for (v = 0; v < n_varargs; ++v) {
  3799.             may_mod = (symtab[j].n_mods != 0);
  3800.             if (flag == DrfPrm)
  3801.                may_mod |= maybe_var[j + v];
  3802.             if (flag == DrfPrm && single[j + v] != NULL) {
  3803.               /*
  3804.                * We need a dereferenced value and it is in a known place: a
  3805.                *  named variable; don't bother saving the result of the
  3806.                *  argument computation.
  3807.                */
  3808.                r = &ignore;
  3809.                }
  3810.             else if (n->n_field[FrstArg + j + v].n_ptr->reuse && may_mod) {
  3811.                /* 
  3812.                 * The argument can be reused without being recomputed and
  3813.                 *  the parameter may be modified, so we cannot safely
  3814.                 *  compute the argument into the vararg parameter array; we
  3815.                 *  must compute it elsewhere and copy (dereference) it at the
  3816.                 *  beginning of the operation. Let gencode allocate an argument
  3817.                 *  result location.
  3818.                 */
  3819.                r = NULL; 
  3820.                }
  3821.             else {
  3822.                /*
  3823.                 * We can compute the argument directly into the vararg
  3824.                 *  parameter array.
  3825.                 */
  3826.                r = tmp_loc(arg_loc + v);
  3827.                }
  3828.             varg_rslt[v] = gencode(n->n_field[FrstArg + j + v].n_ptr, r);
  3829.             }
  3830.  
  3831.          setloc(n);
  3832.          /*
  3833.           * Dereference or copy argument values that are not already in vararg
  3834.           *  parameter list. Preceding arguments are dereferenced later, but
  3835.           *  it is okay if dereferencing is out-of-order.
  3836.           */
  3837.          for (v = 0; v < n_varargs; ++v) {
  3838.             if (flag == DrfPrm && single[j + v] != NULL) {
  3839.                /*
  3840.                 * Copy the value from the known named variable into the
  3841.                 *  parameter list.
  3842.                 */
  3843.                varg_rslt[v] = var_ref(single[j + v]);
  3844.                cd_add(mk_cpyval(tmp_loc(arg_loc + v), varg_rslt[v]));
  3845.                }
  3846.             else if (flag == DrfPrm && maybe_var[j + v]) {
  3847.                /*
  3848.                 * Dereference the argument into the parameter list.
  3849.                 */
  3850.                deref_cd(varg_rslt[v], tmp_loc(arg_loc + v));
  3851.                }
  3852.             else if (arg_loc + v != varg_rslt[v]->u.tmp) {
  3853.                /*
  3854.                 * The argument is a dereferenced value, but is not yet
  3855.                 *  in the parameter list; copy it there.
  3856.                 */
  3857.                cd_add(mk_cpyval(tmp_loc(arg_loc + v), varg_rslt[v]));
  3858.                }
  3859.             tmp_status[arg_loc + v] = InUse; /* parameter location in use */
  3860.             }
  3861.  
  3862.          /*
  3863.           * The vararg parameter gets the address of the first element
  3864.           *  in the variable part of the argument list and the size
  3865.           *  parameter gets the number of elements in the list.
  3866.           */
  3867.          if (n_varargs > 0) {
  3868.             free((char *)varg_rslt);
  3869.             symtab[i].loc = tmp_loc(arg_loc);
  3870.             }
  3871.          else
  3872.             symtab[i].loc = chk_alc(NULL, n); /* dummy arg location */
  3873.          symtab[i].loc->mod_access = M_Addr;
  3874.          ++i;
  3875.          symtab[i].loc = vararg_sz(n_varargs);
  3876.          ++i;
  3877.          }
  3878.       else {
  3879.          /*
  3880.           * Compute extra arguments, but discard the results.
  3881.           */
  3882.          while (j < nargs) {
  3883.             gencode(n->n_field[FrstArg + j].n_ptr, &ignore);
  3884.             ++j;
  3885.             }
  3886.          }
  3887.  
  3888.       if (nargs > 0) {
  3889.          free((char *)maybe_var);
  3890.          free((char *)single);
  3891.          }
  3892.  
  3893.       /*
  3894.        * If execution does not continue through the parameter evaluation,
  3895.        *  don't try to generate in-line code. A lack of parameter types
  3896.        *  will cause problems with some in-line type conversions.
  3897.        */
  3898.       if (!past_prms(n))
  3899.          return rslt;
  3900.  
  3901.       setloc(n);
  3902.  
  3903.       dcl_var = i;
  3904.  
  3905.       /*
  3906.        * Perform any needed copying or dereferencing.
  3907.        */
  3908.       for (i = 0; i < nsyms; ++i) {
  3909.          switch (symtab[i].adjust) {
  3910.             case AdjNDrf:
  3911.                /*
  3912.                 * Dereference into a new temporary which is used as the
  3913.                 *  parameter.
  3914.                 */
  3915.                arg_rslt = chk_alc(NULL, n->intrnl_lftm);
  3916.                deref_cd(symtab[i].loc, arg_rslt);
  3917.                symtab[i].loc = arg_rslt;
  3918.                break;
  3919.             case AdjDrf:
  3920.                /*
  3921.                 * Dereference in place.
  3922.                 */
  3923.                deref_cd(symtab[i].loc, symtab[i].loc);
  3924.                break;
  3925.            case AdjCpy:
  3926.                /*
  3927.                 * Copy into a new temporary which is used as the
  3928.                 *  parameter.
  3929.                 */
  3930.               arg_rslt = chk_alc(NULL, n->intrnl_lftm);
  3931.               cd_add(mk_cpyval(arg_rslt, symtab[i].loc));
  3932.               symtab[i].loc = arg_rslt;
  3933.               break;
  3934.            case AdjNone:
  3935.               break;     /* nothing need be done */
  3936.             }
  3937.          }
  3938.  
  3939.       switch (cont_loc) {
  3940.          case SepFnc:
  3941.             /*
  3942.              * success continuation must be in a separate function.
  3943.              */
  3944.             fnc = alc_fnc();
  3945.             sbuf = (char *)alloc((unsigned int)(strlen(impl->name) + 5));
  3946.             sprintf(sbuf, "end %s", impl->name);
  3947.             scont_strt = alc_lbl(sbuf, 0);
  3948.             cd_add(scont_strt);
  3949.             cur_fnc->cursor = scont_strt->prev; /* put oper before label */
  3950.             gen_inlin(impl->in_line, rslt, &scont_strt, NULL, fnc, impl,
  3951.                nsyms, symtab, n, dcl_var, n_varargs);
  3952.             cur_fnc->cursor = scont_strt;
  3953.             callc_add(fnc);
  3954.             cur_fnc = fnc;
  3955.             on_failure = &resume;
  3956.             break;
  3957.          case SContIL:
  3958.             /*
  3959.              * one suspend an no return: success continuation is put in-line.
  3960.              */
  3961.             gen_inlin(impl->in_line, rslt, &scont_strt, &scont_fail, NULL, impl,
  3962.                 nsyms, symtab, n, dcl_var, n_varargs);
  3963.             cur_fnc->cursor = scont_strt;
  3964.             on_failure = scont_fail;
  3965.             break;
  3966.          case EndOper:
  3967.             /*
  3968.              * no suspends: success continuation goes at end of operation.
  3969.              */
  3970.  
  3971.             sbuf = (char *)alloc((unsigned int)(strlen(impl->name) + 5));
  3972.             sprintf(sbuf, "end %s", impl->name);
  3973.             scont_strt = alc_lbl(sbuf, 0);
  3974.             cd_add(scont_strt);
  3975.             cur_fnc->cursor = scont_strt->prev; /* put operation before lbl */
  3976.             gen_inlin(impl->in_line, rslt, &scont_strt, NULL, NULL, impl,
  3977.                nsyms, symtab, n, dcl_var, n_varargs);
  3978.             cur_fnc->cursor = scont_strt;
  3979.             break;
  3980.          }
  3981.       }
  3982.    else {
  3983.       /*
  3984.        * Do not in-line operation.
  3985.        */
  3986.       implproto(impl);
  3987.       frst_arg = gen_args(n, 2, nargs);
  3988.       setloc(n);
  3989.       if (impl->ret_flag & (DoesRet | DoesSusp))
  3990.          rslt = chk_alc(rslt, rslt_lftm);
  3991.       mk_callop(oper_name(impl), impl->ret_flag, frst_arg, nargs, rslt,
  3992.          0);
  3993.       }
  3994.    if (symtab != NULL)
  3995.       free((char *)symtab);
  3996.    return rslt;
  3997.    }
  3998.  
  3999. /*
  4000.  * max_lftm - given two lifetimes (in the form of nodes) return the
  4001.  *   maximum one.
  4002.  */
  4003. static nodeptr max_lftm(n1, n2)
  4004. nodeptr n1;
  4005. nodeptr n2;
  4006.    {
  4007.    if (n1 == NULL)
  4008.       return n2;
  4009.    else if (n2 == NULL)
  4010.       return n1;
  4011.    else if (n1->postn > n2->postn)
  4012.       return n1;
  4013.    else
  4014.       return n2;
  4015.    }
  4016.  
  4017. /*
  4018.  * inv_prc - directly invoke a procedure.
  4019.  */
  4020. static struct val_loc *inv_prc(n, rslt)
  4021. nodeptr n;
  4022. struct val_loc *rslt;
  4023.    {
  4024.    struct pentry *proc;
  4025.    struct val_loc *r;
  4026.    struct val_loc *arg1rslt;
  4027.    struct val_loc *var_part;
  4028.    int *must_deref;
  4029.    struct lentry **single;
  4030.    struct val_loc **arg_rslt;
  4031.    struct code *cd;
  4032.    struct tmplftm *lifetm_ary;
  4033.    char *sbuf;
  4034.    int nargs;
  4035.    int nparms;
  4036.    int i, j;
  4037.    int arg_loc;
  4038.    int var_sz;
  4039.    int var_loc;
  4040.  
  4041.    /*
  4042.     * This procedure is implemented without argument list adjustment or 
  4043.     *  dereferencing, so they must be done before the call.
  4044.     */
  4045.    nargs = Val0(n);              /* number of arguments */
  4046.    proc = Proc1(n);
  4047.    nparms = Abs(proc->nargs);
  4048.  
  4049.    if (nparms > 0) {
  4050.       must_deref = (int *)alloc((unsigned int)(nparms * sizeof(int)));
  4051.       single = (struct lentry **)alloc((unsigned int)(nparms *
  4052.          sizeof(struct lentry *)));
  4053.       arg_rslt = (struct val_loc **)alloc((unsigned int)(nparms *
  4054.          sizeof(struct val_loc *)));
  4055.       }
  4056.  
  4057.    /*
  4058.     * Allocate a work area of temporaries to use as argument list. If
  4059.     *  an argument can be reused without being recomputed, it must not
  4060.     *  be computed directly into the work area. It will be copied or
  4061.     *  dereferenced into the work area when execution reaches the
  4062.     *  operation. If an argument is a single named variable, it can
  4063.     *  be dereferenced directly into the argument location. These
  4064.     *  conditions affect when the temporary will receive a value.
  4065.     */
  4066.    if (nparms > 0)
  4067.       lifetm_ary = alc_lftm(nparms, NULL);
  4068.    for (i = 0; i < nparms; ++i)
  4069.       lifetm_ary[i].lifetime = n->intrnl_lftm;
  4070.    for (i = 0; i < nparms && i < nargs; ++i) {
  4071.       must_deref[i] = HasVar(varsubtyp(n->n_field[FrstArg + i].n_ptr->type,
  4072.          &(single[i])));
  4073.       if (single[i] != NULL || n->n_field[FrstArg + i].n_ptr->reuse)
  4074.          lifetm_ary[i].cur_status = n->postn;
  4075.       else
  4076.          lifetm_ary[i].cur_status = n->n_field[FrstArg + i].n_ptr->postn;
  4077.       }
  4078.    while (i < nparms) {
  4079.       lifetm_ary[i].cur_status = n->postn; /* arg list extension */
  4080.       ++i;
  4081.       }
  4082.    if (proc->nargs < 0)
  4083.       lifetm_ary[nparms - 1].cur_status = n->postn;  /* variable part */
  4084.  
  4085.    if (nparms > 0) {
  4086.       arg_loc = alc_tmp(nparms, lifetm_ary);
  4087.       free((char *)lifetm_ary);
  4088.       }
  4089.    if (proc->nargs < 0)
  4090.       --nparms;     /* treat variable part specially */
  4091.    for (i = 0; i < nparms && i < nargs;  ++i) {
  4092.       if (single[i] != NULL)
  4093.          r = &ignore;   /* we know where the dereferenced value is */
  4094.       else if (n->n_field[FrstArg + i].n_ptr->reuse)
  4095.          r = NULL;      /* let gencode allocate a new temporary */
  4096.       else
  4097.          r = tmp_loc(arg_loc + i);
  4098.       arg_rslt[i] = gencode(n->n_field[FrstArg + i].n_ptr, r);
  4099.       }
  4100.  
  4101.    /*
  4102.     * If necessary, fill out argument list with nulls.
  4103.     */
  4104.    while (i < nparms) {
  4105.       cd_add(asgn_null(tmp_loc(arg_loc + i)));
  4106.       tmp_status[arg_loc + i] = InUse;
  4107.       ++i;
  4108.       }
  4109.  
  4110.    if (proc->nargs < 0) {
  4111.       /*
  4112.        * handle variable part of list.
  4113.        */
  4114.       var_sz = nargs - nparms;
  4115.  
  4116.       if (var_sz > 0) {
  4117.          lifetm_ary = alc_lftm(var_sz, &n->n_field[FrstArg + nparms]);
  4118.          var_loc = alc_tmp(var_sz, lifetm_ary);
  4119.          free((char *)lifetm_ary);
  4120.          for (j = 0; j < var_sz; ++j)
  4121.             gencode(n->n_field[FrstArg + nparms + j].n_ptr,
  4122.                tmp_loc(var_loc + j));
  4123.          }
  4124.       }
  4125.    else {
  4126.       /*
  4127.        * If there are extra arguments, compute them, but discard the
  4128.        *  results.
  4129.        */
  4130.       while (i < nargs) {
  4131.          gencode(n->n_field[FrstArg + i].n_ptr, &ignore);
  4132.          ++i;
  4133.          }
  4134.       }
  4135.  
  4136.    setloc(n);
  4137.    /*
  4138.     * Dereference or copy argument values that are not already in argument
  4139.     *  list as dereferenced values.
  4140.     */
  4141.    for (i = 0; i < nparms && i < nargs;  ++i) {
  4142.       if (must_deref[i]) {
  4143.          if (single[i] == NULL)
  4144.             deref_cd(arg_rslt[i], tmp_loc(arg_loc + i));
  4145.          else {
  4146.             arg_rslt[i] = var_ref(single[i]);
  4147.             cd_add(mk_cpyval(tmp_loc(arg_loc + i), arg_rslt[i]));
  4148.             }
  4149.          }
  4150.       else if (n->n_field[FrstArg + i].n_ptr->reuse)
  4151.          cd_add(mk_cpyval(tmp_loc(arg_loc + i), arg_rslt[i]));
  4152.       tmp_status[arg_loc + i] = InUse;
  4153.       }
  4154.  
  4155.    if (proc->nargs < 0) {
  4156.       var_part = tmp_loc(arg_loc + nparms);
  4157.       tmp_status[arg_loc + nparms] = InUse;
  4158.       if (var_sz <= 0) {
  4159.          cd = alc_ary(3);
  4160.          cd->ElemTyp(0) = A_Str;
  4161.          cd->Str(0) =                 "varargs(NULL, 0, &";
  4162.          cd->ElemTyp(1) = A_ValLoc;
  4163.          cd->ValLoc(1) =               var_part;
  4164.          cd->ElemTyp(2) = A_Str;
  4165.          cd->Str(2) =                 ");";
  4166.          }
  4167.       else {
  4168.          cd = alc_ary(7);
  4169.          cd->ElemTyp(0) = A_Str;
  4170.          cd->Str(0) =                 "varargs(&";
  4171.          cd->ElemTyp(1) = A_ValLoc;
  4172.          cd->ValLoc(1) =               tmp_loc(var_loc);
  4173.          cd->ElemTyp(2) = A_Str;
  4174.          cd->Str(2) =                  ", ";
  4175.          cd->ElemTyp(3) = A_Intgr;
  4176.          cd->Intgr(3) =               var_sz; 
  4177.          cd->ElemTyp(4) = A_Str;
  4178.          cd->Str(4) =                 ", &";
  4179.          cd->ElemTyp(5) = A_ValLoc;
  4180.          cd->ValLoc(5) =               var_part;
  4181.          cd->ElemTyp(6) = A_Str;
  4182.          cd->Str(6) =                 ");";
  4183.          }
  4184.       cd_add(cd);
  4185.       ++nparms;   /* include variable part in call */
  4186.       }
  4187.  
  4188.    if (nparms > 0) {
  4189.       free((char *)must_deref);
  4190.       free((char *)single);
  4191.       free((char *)arg_rslt);
  4192.       }
  4193.  
  4194.    sbuf = (char *)alloc((unsigned int)(strlen(proc->name) + PrfxSz + 3));
  4195.    sprintf(sbuf, "P%s_%s", proc->prefix, proc->name);
  4196.    if (nparms > 0)
  4197.       arg1rslt = tmp_loc(arg_loc);
  4198.    else
  4199.       arg1rslt = NULL;
  4200.    if (proc->ret_flag & (DoesRet | DoesSusp))
  4201.       rslt = chk_alc(rslt, n->lifetime);
  4202.    mk_callop(sbuf, proc->ret_flag, arg1rslt, nargs, rslt, 1);
  4203.    return rslt;
  4204.    }
  4205.  
  4206. /*
  4207.  * endlife - link a temporary variable onto the list to be freed when
  4208.  *  execution reaches a node.
  4209.  */
  4210. static novalue endlife(kind, indx, old, n)
  4211. int kind;
  4212. int indx;
  4213. int old;
  4214. nodeptr n;
  4215.    {
  4216.    struct freetmp *freetmp;
  4217.  
  4218.    if ((freetmp = freetmp_pool) == NULL)
  4219.      freetmp = NewStruct(freetmp);
  4220.    else
  4221.       freetmp_pool = freetmp_pool->next;
  4222.    freetmp->kind = kind;
  4223.    freetmp->indx = indx;
  4224.    freetmp->old = old;
  4225.    freetmp->next = n->freetmp;
  4226.    n->freetmp = freetmp;
  4227.    }
  4228.  
  4229. /*
  4230.  * alc_tmp - allocate a block of temporary variables with the given lifetimes.
  4231.  */
  4232. static int alc_tmp(num, lifetm_ary)
  4233. int num;
  4234. struct tmplftm *lifetm_ary;
  4235.    {
  4236.    int i, j, k;
  4237.    register int status;
  4238.    int *new_status;
  4239.    int new_size;
  4240.  
  4241.    i = 0;
  4242.    for (;;) {
  4243.       if (i + num > status_sz) {
  4244.          /*
  4245.           * The status array is too small, expand it.
  4246.           */
  4247.          new_size = status_sz + Max(num, status_sz);
  4248.          new_status = (int *)alloc((unsigned int)(new_size * sizeof(int)));
  4249.          k = 0;
  4250.          while (k < status_sz) {
  4251.             new_status[k] = tmp_status[k];
  4252.             ++k;
  4253.             }
  4254.          while (k < new_size) {
  4255.             new_status[k] = NotAlloc;
  4256.             ++k;
  4257.             }
  4258.          free((char *)tmp_status);
  4259.          tmp_status = new_status;
  4260.          status_sz = new_size;
  4261.          }
  4262.       for (j = 0; j < num; ++j) {
  4263.          status = tmp_status[i + j];
  4264.          if (status != NotAlloc &&
  4265.             (status == InUse || status <= lifetm_ary[j].lifetime->postn))
  4266.                break;
  4267.          }
  4268.       /*
  4269.        * Did we find a block of temporaries that we can use?
  4270.        */
  4271.       if (j == num) {
  4272.          while (--j >= 0) {
  4273.             endlife(DescTmp, i + j, tmp_status[i + j], lifetm_ary[j].lifetime);
  4274.             tmp_status[i + j] = lifetm_ary[j].cur_status;
  4275.             }
  4276.          if (i + num > num_tmp)
  4277.             num_tmp = i + num;
  4278.          return i;
  4279.          }
  4280.       ++i;
  4281.       }
  4282.    }
  4283.  
  4284. /*
  4285.  * alc_lftm - allocate an array of lifetime information for an argument
  4286.  *  list.
  4287.  */
  4288. static struct tmplftm *alc_lftm(num, args)
  4289. int num;
  4290. union field *args;
  4291.    {
  4292.    struct tmplftm *lifetm_ary;
  4293.    int i;
  4294.  
  4295.    lifetm_ary = (struct tmplftm *)alloc((unsigned int)(num *
  4296.       sizeof(struct tmplftm)));
  4297.    if (args != NULL)
  4298.      for (i = 0; i < num; ++i) {
  4299.         lifetm_ary[i].cur_status = args[i].n_ptr->postn; /* reserved for arg */
  4300.         lifetm_ary[i].lifetime = args[i].n_ptr->lifetime;
  4301.         }
  4302.    return lifetm_ary;
  4303.    }
  4304.  
  4305. /*
  4306.  * alc_itmp - allocate a temporary C integer variable.
  4307.  */
  4308. int alc_itmp(lifetime)
  4309. nodeptr lifetime;
  4310.    {
  4311.    int i, j;
  4312.    int new_size;
  4313.  
  4314.    i = 0;
  4315.    while (i < istatus_sz && itmp_status[i] == InUse)
  4316.       ++i;
  4317.    if (i >= istatus_sz) {
  4318.       /*
  4319.        * The status array is too small, expand it.
  4320.        */
  4321.       free((char *)itmp_status);
  4322.       new_size = istatus_sz * 2;
  4323.       itmp_status = (int *)alloc((unsigned int)(new_size * sizeof(int)));
  4324.       j = 0;
  4325.       while (j < istatus_sz)
  4326.          itmp_status[j++] = InUse;
  4327.       while (j < new_size)
  4328.          itmp_status[j++] = NotAlloc;
  4329.       istatus_sz = new_size;
  4330.       }
  4331.    endlife(CIntTmp, i, NotAlloc, lifetime);
  4332.    itmp_status[i] = InUse;
  4333.    if (num_itmp < i + 1)
  4334.      num_itmp = i + 1;
  4335.    return i;
  4336.    }
  4337.  
  4338. /*
  4339.  * alc_dtmp - allocate a temporary C integer variable.
  4340.  */
  4341. int alc_dtmp(lifetime)
  4342. nodeptr lifetime;
  4343.    {
  4344.    int i, j;
  4345.    int new_size;
  4346.  
  4347.    i = 0;
  4348.    while (i < dstatus_sz && dtmp_status[i] == InUse)
  4349.       ++i;
  4350.    if (i >= dstatus_sz) {
  4351.       /*
  4352.        * The status array is too small, expand it.
  4353.        */
  4354.       free((char *)dtmp_status);
  4355.       new_size = dstatus_sz * 2;
  4356.       dtmp_status = (int *)alloc((unsigned int)(new_size * sizeof(int)));
  4357.       j = 0;
  4358.       while (j < dstatus_sz)
  4359.          dtmp_status[j++] = InUse;
  4360.       while (j < new_size)
  4361.          dtmp_status[j++] = NotAlloc;
  4362.       dstatus_sz = new_size;
  4363.       }
  4364.    endlife(CDblTmp, i, NotAlloc, lifetime);
  4365.    dtmp_status[i] = InUse;
  4366.    if (num_dtmp < i + 1)
  4367.      num_dtmp = i + 1;
  4368.    return i;
  4369.    }
  4370.  
  4371. /*
  4372.  * alc_sbufs - allocate a block of string buffers with the given lifetime.
  4373.  */
  4374. int alc_sbufs(num, lifetime)
  4375. int num;
  4376. nodeptr lifetime;
  4377.    {
  4378.    int i, j, k;
  4379.    int *new_status;
  4380.    int new_size;
  4381.  
  4382.    i = 0;
  4383.    for (;;) {
  4384.       if (i + num > sstatus_sz) {
  4385.          /*
  4386.           * The status array is too small, expand it.
  4387.           */
  4388.          new_size = sstatus_sz + Max(num, sstatus_sz);
  4389.          new_status = (int *)alloc((unsigned int)(new_size * sizeof(int)));
  4390.          k = 0;
  4391.          while (k < sstatus_sz) {
  4392.             new_status[k] = sbuf_status[k];
  4393.             ++k;
  4394.             }
  4395.          while (k < new_size) {
  4396.             new_status[k] = NotAlloc;
  4397.             ++k;
  4398.             }
  4399.          free((char *)sbuf_status);
  4400.          sbuf_status = new_status;
  4401.          sstatus_sz = new_size;
  4402.          }
  4403.       for (j = 0; j < num && sbuf_status[i + j] == NotAlloc; ++j)
  4404.          ;
  4405.       /*
  4406.        * Did we find a block of buffers that we can use?
  4407.        */
  4408.       if (j == num) {
  4409.          while (--j >= 0) {
  4410.             endlife(SBuf, i + j, sbuf_status[i + j], lifetime);
  4411.             sbuf_status[i + j] = InUse;
  4412.             }
  4413.          if (i + num > num_sbuf)
  4414.             num_sbuf = i + num;
  4415.          return i;
  4416.          }
  4417.       ++i;
  4418.       }
  4419.    }
  4420.  
  4421. /*
  4422.  * alc_cbufs - allocate a block of cset buffers with the given lifetime.
  4423.  */
  4424. int alc_cbufs(num, lifetime)
  4425. int num;
  4426. nodeptr lifetime;
  4427.    {
  4428.    int i, j, k;
  4429.    int *new_status;
  4430.    int new_size;
  4431.  
  4432.    i = 0;
  4433.    for (;;) {
  4434.       if (i + num > cstatus_sz) {
  4435.          /*
  4436.           * The status array is too small, expand it.
  4437.           */
  4438.          new_size = cstatus_sz + Max(num, cstatus_sz);
  4439.          new_status = (int *)alloc((unsigned int)(new_size * sizeof(int)));
  4440.          k = 0;
  4441.          while (k < cstatus_sz) {
  4442.             new_status[k] = cbuf_status[k];
  4443.             ++k;
  4444.             }
  4445.          while (k < new_size) {
  4446.             new_status[k] = NotAlloc;
  4447.             ++k;
  4448.             }
  4449.          free((char *)cbuf_status);
  4450.          cbuf_status = new_status;
  4451.          cstatus_sz = new_size;
  4452.          }
  4453.       for (j = 0; j < num && cbuf_status[i + j] == NotAlloc; ++j)
  4454.          ;
  4455.       /*
  4456.        * Did we find a block of buffers that we can use?
  4457.        */
  4458.       if (j == num) {
  4459.          while (--j >= 0) {
  4460.             endlife(CBuf, i + j, cbuf_status[i + j], lifetime);
  4461.             cbuf_status[i + j] = InUse;
  4462.             }
  4463.          if (i + num > num_cbuf)
  4464.             num_cbuf = i + num;
  4465.          return i;
  4466.          }
  4467.       ++i;
  4468.       }
  4469.    }
  4470.