summaryrefslogtreecommitdiff
path: root/src/rtt/rttout.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rtt/rttout.c')
-rw-r--r--src/rtt/rttout.c3821
1 files changed, 3821 insertions, 0 deletions
diff --git a/src/rtt/rttout.c b/src/rtt/rttout.c
new file mode 100644
index 0000000..14c71b7
--- /dev/null
+++ b/src/rtt/rttout.c
@@ -0,0 +1,3821 @@
+#include "rtt.h"
+
+#define NotId 0 /* declarator is not simple identifier */
+#define IsId 1 /* declarator is simple identifier */
+
+#define OrdFunc -1 /* indicates ordinary C function - non-token value */
+
+/*
+ * VArgAlwnc - allowance for the variable part of an argument list in the
+ * most general version of an operation. If it is too small, storage must
+ * be malloced. 3 was chosen because over 90 percent of all writes have
+ * 3 or fewer arguments. It is possible that 4 would be a better number,
+ * but 5 is probably overkill.
+ */
+#define VArgAlwnc 3
+
+/*
+ * Prototypes for static functions.
+ */
+static void cnv_fnc (struct token *t, int typcd,
+ struct node *src, struct node *dflt,
+ struct node *dest, int indent);
+static void chk_conj (struct node *n);
+static void chk_nl (int indent);
+static void chk_rsltblk (int indent);
+static void comp_def (struct node *n);
+static int does_call (struct node *expr);
+static void failure (int indent, int brace);
+static void interp_def (struct node *n);
+static int len_sel (struct node *sel,
+ struct parminfo *strt_prms,
+ struct parminfo *end_prms, int indent);
+static void line_dir (int nxt_line, char *new_fname);
+static int only_proto (struct node *n);
+static void parm_locs (struct sym_entry *op_params);
+static void parm_tnd (struct sym_entry *sym);
+static void prt_runerr (struct token *t, struct node *num,
+ struct node *val, int indent);
+static void prt_tok (struct token *t, int indent);
+static void prt_var (struct node *n, int indent);
+static int real_def (struct node *n);
+static int retval_dcltor (struct node *dcltor, int indent);
+static void ret_value (struct token *t, struct node *n,
+ int indent);
+static void ret_1_arg (struct token *t, struct node *args,
+ int typcd, char *vwrd_asgn, char *arg_rep,
+ int indent);
+static int rt_walk (struct node *n, int indent, int brace);
+static void spcl_start (struct sym_entry *op_params);
+static int tdef_or_extr (struct node *n);
+static void tend_ary (int n);
+static void tend_init (void);
+static void tnd_var (struct sym_entry *sym, char *strct_ptr, char *access, int indent);
+static void tok_line (struct token *t, int indent);
+static void typ_asrt (int typcd, struct node *desc,
+ struct token *tok, int indent);
+static int typ_case (struct node *var, struct node *slct_lst,
+ struct node *dflt,
+ int (*walk)(struct node *n, int xindent,
+ int brace), int maybe_var, int indent);
+static void untend (int indent);
+
+extern char *progname;
+
+int op_type = OrdFunc; /* type of operation */
+char lc_letter; /* f = function, o = operator, k = keyword */
+char uc_letter; /* F = function, O = operator, K = keyword */
+char prfx1; /* 1st char of unique prefix for operation */
+char prfx2; /* 2nd char of unique prefix for operation */
+char *fname = ""; /* current source file name */
+int line = 0; /* current source line number */
+int nxt_sbuf; /* next string buffer index */
+int nxt_cbuf; /* next cset buffer index */
+int abs_ret = SomeType; /* type from abstract return(s) */
+
+int nl = 0; /* flag indicating the a new-line should be output */
+static int no_nl = 0; /* flag to suppress line directives */
+
+static int ntend; /* number of tended descriptor needed */
+static char *tendstrct; /* expression to access struct of tended descriptors */
+static char *rslt_loc; /* expression to access result location */
+static int varargs = 0; /* flag: operation takes variable number of arguments */
+
+static int no_ret_val; /* function has return statement with no value */
+static struct node *fnc_head; /* header of function being "copied" to output */
+
+/*
+ * chk_nl - if a new-line is required, output it and indent the next line.
+ */
+static void chk_nl(indent)
+int indent;
+ {
+ int col;
+
+ if (nl) {
+ /*
+ * new-line required.
+ */
+ putc('\n', out_file);
+ ++line;
+ for (col = 0; col < indent; ++col)
+ putc(' ', out_file);
+ nl = 0;
+ }
+ }
+
+/*
+ * line_dir - Output a line directive.
+ */
+static void line_dir(nxt_line, new_fname)
+int nxt_line;
+char *new_fname;
+ {
+ char *s;
+
+ /*
+ * Make sure line directives are desired in the output. Normally,
+ * blank lines surround the directive for readability. However,`
+ * a preceding blank line is suppressed at the beginning of the
+ * output file. In addition, a blank line is suppressed after
+ * the directive if it would force the line number on the directive
+ * to be 0.
+ */
+ if (line_cntrl) {
+ fprintf(out_file, "\n");
+ if (line != 0)
+ fprintf(out_file, "\n");
+ if (nxt_line == 1)
+ fprintf(out_file, "#line %d \"", nxt_line);
+ else
+ fprintf(out_file, "#line %d \"", nxt_line - 1);
+ for (s = new_fname; *s != '\0'; ++s) {
+ if (*s == '"' || *s == '\\')
+ putc('\\', out_file);
+ putc(*s, out_file);
+ }
+ if (nxt_line == 1)
+ fprintf(out_file, "\"");
+ else
+ fprintf(out_file, "\"\n");
+ nl = 1;
+ --nxt_line;
+ }
+ else if ((nxt_line > line || fname != new_fname) && line != 0) {
+ /*
+ * Line directives are disabled, but we are in a situation where
+ * one or two new-lines are desirable.
+ */
+ if (nxt_line > line + 1 || fname != new_fname)
+ fprintf(out_file, "\n");
+ nl = 1;
+ --nxt_line;
+ }
+ line = nxt_line;
+ fname = new_fname;
+ }
+
+/*
+ * prt_str - print a string to the output file, possibly preceded by
+ * a new-line and indenting.
+ */
+void prt_str(s, indent)
+char *s;
+int indent;
+ {
+ chk_nl(indent);
+ fprintf(out_file, "%s", s);
+ }
+
+/*
+ * tok_line - determine if a line directive is needed to synchronize the
+ * output file name and line number with an input token.
+ */
+static void tok_line(t, indent)
+struct token *t;
+int indent;
+ {
+ int nxt_line;
+
+ /*
+ * Line directives may be suppressed at certain points during code
+ * output. This is done either by rtt itself using the no_nl flag, or
+ * for macros, by the preprocessor using a flag in the token.
+ */
+ if (no_nl)
+ return;
+ if (t->flag & LineChk) {
+ /*
+ * If blank lines can be used in place of a line directive and no
+ * more than 3 are needed, use them. If the line number and file
+ * name are correct, but we need a new-line, we must output a
+ * line directive so the line number is reset after the "new-line".
+ */
+ nxt_line = t->line;
+ if (fname != t->fname || line > nxt_line || line + 2 < nxt_line)
+ line_dir(nxt_line, t->fname);
+ else if (nl && line == nxt_line)
+ line_dir(nxt_line, t->fname);
+ else if (line != nxt_line) {
+ nl = 1;
+ --nxt_line;
+ while (line < nxt_line) { /* above condition limits # interactions */
+ putc('\n', out_file);
+ ++line;
+ }
+ }
+ }
+ chk_nl(indent);
+ }
+
+/*
+ * prt_tok - print a token.
+ */
+static void prt_tok(t, indent)
+struct token *t;
+int indent;
+ {
+ char *s;
+
+ tok_line(t, indent); /* synchronize file name and line number */
+
+ /*
+ * Most tokens contain a string of their exact image. However, string
+ * and character literals lack the surrounding quotes.
+ */
+ s = t->image;
+ switch (t->tok_id) {
+ case StrLit:
+ fprintf(out_file, "\"%s\"", s);
+ break;
+ case LStrLit:
+ fprintf(out_file, "L\"%s\"", s);
+ break;
+ case CharConst:
+ fprintf(out_file, "'%s'", s);
+ break;
+ case LCharConst:
+ fprintf(out_file, "L'%s'", s);
+ break;
+ default:
+ fprintf(out_file, "%s", s);
+ }
+ }
+
+/*
+ * untend - output code to removed the tended descriptors in this
+ * function from the global tended list.
+ */
+static void untend(indent)
+int indent;
+ {
+ ForceNl();
+ prt_str("tend = ", indent);
+ fprintf(out_file, "%s.previous;", tendstrct);
+ ForceNl();
+ /*
+ * For varargs operations, the tended structure might have been
+ * malloced. If so, it must be freed.
+ */
+ if (varargs) {
+ prt_str("if (r_tendp != (struct tend_desc *)&r_tend)", indent);
+ ForceNl();
+ prt_str("free((pointer)r_tendp);", 2 * indent);
+ }
+ }
+
+/*
+ * tnd_var - output an expression to accessed a tended variable.
+ */
+static void tnd_var(sym, strct_ptr, access, indent)
+struct sym_entry *sym;
+char *strct_ptr;
+char *access;
+int indent;
+ {
+ /*
+ * A variable that is a specific block pointer type must be cast
+ * to that pointer type in such a way that it can be used as either
+ * an lvalue or an rvalue: *(struct b_??? **)&???.vword.bptr
+ */
+ if (strct_ptr != NULL) {
+ prt_str("(*(struct ", indent);
+ prt_str(strct_ptr, indent);
+ prt_str("**)&", indent);
+ }
+
+ if (sym->id_type & ByRef) {
+ /*
+ * The tended variable is being accessed indirectly through
+ * a pointer (that is, it is accessed as the argument to a body
+ * function); dereference its identifier.
+ */
+ prt_str("(*", indent);
+ prt_str(sym->image, indent);
+ prt_str(")", indent);
+ }
+ else {
+ if (sym->t_indx >= 0) {
+ /*
+ * The variable is accessed directly as part of the tended structure.
+ */
+ prt_str(tendstrct, indent);
+ fprintf(out_file, ".d[%d]", sym->t_indx);
+ }
+ else {
+ /*
+ * This is a direct access to an operation parameter.
+ */
+ prt_str("r_args[", indent);
+ fprintf(out_file, "%d]", sym->u.param_info.param_num + 1);
+ }
+ }
+ prt_str(access, indent); /* access the vword for tended pointers */
+ if (strct_ptr != NULL)
+ prt_str(")", indent);
+ }
+
+/*
+ * prt_var - print a variable.
+ */
+static void prt_var(n, indent)
+struct node *n;
+int indent;
+ {
+ struct token *t;
+ struct sym_entry *sym;
+
+ t = n->tok;
+ tok_line(t, indent); /* synchronize file name and line nuber */
+ sym = n->u[0].sym;
+ switch (sym->id_type & ~ByRef) {
+ case TndDesc:
+ /*
+ * Simple tended descriptor.
+ */
+ tnd_var(sym, NULL, "", indent);
+ break;
+ case TndStr:
+ /*
+ * Tended character pointer.
+ */
+ tnd_var(sym, NULL, ".vword.sptr", indent);
+ break;
+ case TndBlk:
+ /*
+ * Tended block pointer.
+ */
+ tnd_var(sym, sym->u.tnd_var.blk_name, ".vword.bptr",
+ indent);
+ break;
+ case RtParm:
+ case DrfPrm:
+ switch (sym->u.param_info.cur_loc) {
+ case PrmTend:
+ /*
+ * Simple tended parameter.
+ */
+ tnd_var(sym, NULL, "", indent);
+ break;
+ case PrmCStr:
+ /*
+ * Parameter converted to a (tended) string.
+ */
+ tnd_var(sym, NULL, ".vword.sptr", indent);
+ break;
+ case PrmInt:
+ /*
+ * Parameter converted to a C integer.
+ */
+ chk_nl(indent);
+ fprintf(out_file, "r_i%d", sym->u.param_info.param_num);
+ break;
+ case PrmDbl:
+ /*
+ * Parameter converted to a C double.
+ */
+ chk_nl(indent);
+ fprintf(out_file, "r_d%d", sym->u.param_info.param_num);
+ break;
+ default:
+ errt2(t, "Conflicting conversions for: ", t->image);
+ }
+ break;
+ case RtParm | VarPrm:
+ case DrfPrm | VarPrm:
+ /*
+ * Parameter representing variable part of argument list.
+ */
+ prt_str("(&", indent);
+ if (sym->t_indx >= 0)
+ fprintf(out_file, "%s.d[%d])", tendstrct, sym->t_indx);
+ else
+ fprintf(out_file, "r_args[%d])", sym->u.param_info.param_num + 1);
+ break;
+ case VArgLen:
+ /*
+ * Length of variable part of argument list.
+ */
+ prt_str("(r_nargs - ", indent);
+ fprintf(out_file, "%d)", params->u.param_info.param_num);
+ break;
+ case RsltLoc:
+ /*
+ * "result" the result location of the operation.
+ */
+ prt_str(rslt_loc, indent);
+ break;
+ case Label:
+ /*
+ * Statement label.
+ */
+ prt_str(sym->image, indent);
+ break;
+ case OtherDcl:
+ /*
+ * Some other type of variable: accessed by identifier. If this
+ * is a body function, it may be passed by reference and need
+ * a level of pointer dereferencing.
+ */
+ if (sym->id_type & ByRef)
+ prt_str("(*",indent);
+ prt_str(sym->image, indent);
+ if (sym->id_type & ByRef)
+ prt_str(")",indent);
+ break;
+ }
+ }
+
+/*
+ * does_call - determine if an expression contains a function call by
+ * walking its syntax tree.
+ */
+static int does_call(expr)
+struct node *expr;
+ {
+ int n_subs;
+ int i;
+
+ if (expr == NULL)
+ return 0;
+ if (expr->nd_id == BinryNd && expr->tok->tok_id == ')')
+ return 1; /* found a function call */
+
+ switch (expr->nd_id) {
+ case ExactCnv: case PrimryNd: case SymNd:
+ n_subs = 0;
+ break;
+ case CompNd:
+ /*
+ * Check field 0 below, field 1 is not a subtree, check field 2 here.
+ */
+ n_subs = 1;
+ if (does_call(expr->u[2].child))
+ return 1;
+ break;
+ case IcnTypNd: case PstfxNd: case PreSpcNd: case PrefxNd:
+ n_subs = 1;
+ break;
+ case AbstrNd: case BinryNd: case CommaNd: case ConCatNd: case LstNd:
+ case StrDclNd:
+ n_subs = 2;
+ break;
+ case TrnryNd:
+ n_subs = 3;
+ break;
+ case QuadNd:
+ n_subs = 4;
+ break;
+ default:
+ fprintf(stdout, "rtt internal error: unknown node type\n");
+ exit(EXIT_FAILURE);
+ }
+
+ for (i = 0; i < n_subs; ++i)
+ if (does_call(expr->u[i].child))
+ return 1;
+
+ return 0;
+ }
+
+/*
+ * prt_runerr - print code to implement runerr().
+ */
+static void prt_runerr(t, num, val, indent)
+struct token *t;
+struct node *num;
+struct node *val;
+int indent;
+ {
+ if (op_type == OrdFunc)
+ errt1(t, "'runerr' may not be used in an ordinary C function");
+
+ tok_line(t, indent); /* synchronize file name and line number */
+ prt_str("{", indent);
+ ForceNl();
+ prt_str("err_msg(", indent);
+ c_walk(num, indent, 0); /* error number */
+ if (val == NULL)
+ prt_str(", NULL);", indent); /* no offending value */
+ else {
+ prt_str(", &(", indent);
+ c_walk(val, indent, 0); /* offending value */
+ prt_str("));", indent);
+ }
+ /*
+ * Handle error conversion. Indicate that operation may fail because
+ * of error conversion and produce the necessary code.
+ */
+ cur_impl->ret_flag |= DoesEFail;
+ failure(indent, 1);
+ prt_str("}", indent);
+ ForceNl();
+ }
+
+/*
+ * typ_name - convert a type code to a string that can be used to
+ * output "T_" or "D_" type codes.
+ */
+char *typ_name(typcd, tok)
+int typcd;
+struct token *tok;
+ {
+ if (typcd == Empty_type)
+ errt1(tok, "it is meaningless to assert a type of empty_type");
+ else if (typcd == Any_value)
+ errt1(tok, "it is useless to assert a type of any_value");
+ else if (typcd < 0 || typcd == str_typ)
+ return NULL;
+ else
+ return icontypes[typcd].cap_id;
+ /*NOTREACHED*/
+ return 0; /* avoid gcc warning */
+ }
+
+/*
+ * Produce a C conditional expression to check a descriptor for a
+ * particular type.
+ */
+static void typ_asrt(typcd, desc, tok, indent)
+int typcd;
+struct node *desc;
+struct token *tok;
+int indent;
+ {
+ tok_line(tok, indent);
+
+ if (typcd == str_typ) {
+ /*
+ * Check dword for the absense of a "not qualifier" flag.
+ */
+ prt_str("(!((", indent);
+ c_walk(desc, indent, 0);
+ prt_str(").dword & F_Nqual))", indent);
+ }
+ else if (typcd == TypVar) {
+ /*
+ * Check dword for the presense of a "variable" flag.
+ */
+ prt_str("(((", indent);
+ c_walk(desc, indent, 0);
+ prt_str(").dword & D_Var) == D_Var)", indent);
+ }
+ else if (typcd == int_typ) {
+ /*
+ * If large integers are supported, an integer can be either
+ * an ordinary integer or a large integer.
+ */
+ ForceNl();
+ prt_str("#ifdef LargeInts", 0);
+ ForceNl();
+ prt_str("(((", indent);
+ c_walk(desc, indent, 0);
+ prt_str(").dword == D_Integer) || ((", indent);
+ c_walk(desc, indent, 0);
+ prt_str(").dword == D_Lrgint))", indent);
+ ForceNl();
+ prt_str("#else\t\t\t\t\t/* LargeInts */", 0);
+ ForceNl();
+ prt_str("((", indent);
+ c_walk(desc, indent, 0);
+ prt_str(").dword == D_Integer)", indent);
+ ForceNl();
+ prt_str("#endif\t\t\t\t\t/* LargeInts */", 0);
+ ForceNl();
+ }
+ else {
+ /*
+ * Check dword for a specific type code.
+ */
+ prt_str("((", indent);
+ c_walk(desc, indent, 0);
+ prt_str(").dword == D_", indent);
+ prt_str(typ_name(typcd, tok), indent);
+ prt_str(")", indent);
+ }
+ }
+
+/*
+ * retval_dcltor - convert the "declarator" part of function declaration
+ * into a declarator for the variable "r_retval" of the same type
+ * as the function result type, outputing the new declarator. This
+ * variable is a temporary location to store the result of the argument
+ * to a C return statement.
+ */
+static int retval_dcltor(dcltor, indent)
+struct node *dcltor;
+int indent;
+ {
+ int flag;
+
+ switch (dcltor->nd_id) {
+ case ConCatNd:
+ c_walk(dcltor->u[0].child, indent, 0);
+ retval_dcltor(dcltor->u[1].child, indent);
+ return NotId;
+ case PrimryNd:
+ /*
+ * We have reached the function name. Replace it with "r_retval"
+ * and tell caller we have found it.
+ */
+ prt_str("r_retval", indent);
+ return IsId;
+ case PrefxNd:
+ /*
+ * (...)
+ */
+ prt_str("(", indent);
+ flag = retval_dcltor(dcltor->u[0].child, indent);
+ prt_str(")", indent);
+ return flag;
+ case BinryNd:
+ if (dcltor->tok->tok_id == ')') {
+ /*
+ * Function declaration. If this is the declarator that actually
+ * defines the function being processed, discard the paramater
+ * list including parentheses.
+ */
+ if (retval_dcltor(dcltor->u[0].child, indent) == NotId) {
+ prt_str("(", indent);
+ c_walk(dcltor->u[1].child, indent, 0);
+ prt_str(")", indent);
+ }
+ }
+ else {
+ /*
+ * Array.
+ */
+ retval_dcltor(dcltor->u[0].child, indent);
+ prt_str("[", indent);
+ c_walk(dcltor->u[1].child, indent, 0);
+ prt_str("]", indent);
+ }
+ return NotId;
+ }
+ err1("rtt internal error detected in function retval_dcltor()");
+ /*NOTREACHED*/
+ return 0; /* avoid gcc warning */
+ }
+
+/*
+ * cnv_fnc - produce code to handle RTT cnv: and def: constructs.
+ */
+static void cnv_fnc(t, typcd, src, dflt, dest, indent)
+struct token *t;
+int typcd;
+struct node *src;
+struct node *dflt;
+struct node *dest;
+int indent;
+ {
+ int dflt_to_ptr;
+ int loc;
+ int is_cstr;
+
+ if (src->nd_id == SymNd && src->u[0].sym->id_type & VarPrm)
+ errt1(t, "converting entire variable part of param list not supported");
+
+ tok_line(t, indent); /* synchronize file name and line number */
+
+ /*
+ * Initial assumptions: result of conversion is a tended location
+ * and is not tended C string.
+ */
+ loc = PrmTend;
+ is_cstr = 0;
+
+ /*
+ * Print the name of the conversion function. If it is a conversion
+ * with a default value, determine (through dflt_to_prt) if the
+ * default value is passed by-reference instead of by-value.
+ */
+ prt_str(cnv_name(typcd, dflt, &dflt_to_ptr), indent);
+ prt_str("(", indent);
+
+ /*
+ * Determine what parameter scope, if any, is established by this
+ * conversion. If the conversion needs a buffer, allocate it and
+ * put it in the argument list.
+ */
+ switch (typcd) {
+ case TypCInt:
+ case TypECInt:
+ loc = PrmInt;
+ break;
+ case TypCDbl:
+ loc = PrmDbl;
+ break;
+ case TypCStr:
+ is_cstr = 1;
+ break;
+ case TypTStr:
+ fprintf(out_file, "r_sbuf[%d], ", nxt_sbuf++);
+ break;
+ case TypTCset:
+ fprintf(out_file, "&r_cbuf[%d], ", nxt_cbuf++);
+ break;
+ }
+
+ /*
+ * Output source of conversion.
+ */
+ prt_str("&(", indent);
+ c_walk(src, indent, 0);
+ prt_str("), ", indent);
+
+ /*
+ * If there is a default value, output it, taking its address if necessary.
+ */
+ if (dflt != NULL) {
+ if (dflt_to_ptr)
+ prt_str("&(", indent);
+ c_walk(dflt, indent, 0);
+ if (dflt_to_ptr)
+ prt_str("), ", indent);
+ else
+ prt_str(", ", indent);
+ }
+
+ /*
+ * Output the destination of the conversion. This may or may not be
+ * the same as the source.
+ */
+ prt_str("&(", indent);
+ if (dest == NULL) {
+ /*
+ * Convert "in place", changing the location of a paramater if needed.
+ */
+ if (src->nd_id == SymNd && src->u[0].sym->id_type & (RtParm | DrfPrm)) {
+ if (src->u[0].sym->id_type & DrfPrm)
+ src->u[0].sym->u.param_info.cur_loc = loc;
+ else
+ errt1(t, "only dereferenced parameter can be converted in-place");
+ }
+ else if ((loc != PrmTend) | is_cstr)
+ errt1(t,
+ "only ordinary parameters can be converted in-place to C values");
+ c_walk(src, indent, 0);
+ if (is_cstr) {
+ /*
+ * The parameter must be accessed as a tended C string, but only
+ * now, after the "destination" code has been produced as a full
+ * descriptor.
+ */
+ src->u[0].sym->u.param_info.cur_loc = PrmCStr;
+ }
+ }
+ else {
+ /*
+ * Convert to an explicit destination.
+ */
+ if (is_cstr) {
+ /*
+ * Access the destination as a full descriptor even though it
+ * must be declared as a tended C string.
+ */
+ if (dest->nd_id != SymNd || (dest->u[0].sym->id_type != TndStr &&
+ dest->u[0].sym->id_type != TndDesc))
+ errt1(t,
+ "dest. of C_string conv. must be tended descriptor or char *");
+ tnd_var(dest->u[0].sym, NULL, "", indent);
+ }
+ else
+ c_walk(dest, indent, 0);
+ }
+ prt_str("))", indent);
+ }
+
+/*
+ * cnv_name - produce name of conversion routine. Warning, name is
+ * constructed in a static buffer. Also determine if a default
+ * must be passed "by reference".
+ */
+char *cnv_name(typcd, dflt, dflt_to_ptr)
+int typcd;
+struct node *dflt;
+int *dflt_to_ptr;
+ {
+ static char buf[15];
+ int by_ref;
+
+ /*
+ * The names of simple conversion and defaulting conversions have
+ * the same suffixes, but different prefixes.
+ */
+ if (dflt == NULL)
+ strcpy(buf , "cnv_");
+ else
+ strcpy(buf, "def_");
+
+ by_ref = 0;
+ switch (typcd) {
+ case TypCInt:
+ strcat(buf, "c_int");
+ break;
+ case TypCDbl:
+ strcat(buf, "c_dbl");
+ break;
+ case TypCStr:
+ strcat(buf, "c_str");
+ break;
+ case TypTStr:
+ strcat(buf, "tstr");
+ by_ref = 1;
+ break;
+ case TypTCset:
+ strcat(buf, "tcset");
+ by_ref = 1;
+ break;
+ case TypEInt:
+ strcat(buf, "eint");
+ break;
+ case TypECInt:
+ strcat(buf, "ec_int");
+ break;
+ default:
+ if (typcd == cset_typ) {
+ strcat(buf, "cset");
+ by_ref = 1;
+ }
+ else if (typcd == int_typ)
+ strcat(buf, "int");
+ else if (typcd == real_typ)
+ strcat(buf, "real");
+ else if (typcd == str_typ) {
+ strcat(buf, "str");
+ by_ref = 1;
+ }
+ }
+ if (dflt_to_ptr != NULL)
+ *dflt_to_ptr = by_ref;
+ return buf;
+ }
+
+/*
+ * ret_value - produce code to set the result location of an operation
+ * using the expression on a return or suspend.
+ */
+static void ret_value(t, n, indent)
+struct token *t;
+struct node *n;
+int indent;
+ {
+ struct node *caller;
+ struct node *args;
+ int typcd;
+
+ if (n == NULL)
+ errt1(t, "there is no default return value for run-time operations");
+
+ if (n->nd_id == SymNd && n->u[0].sym->id_type == RsltLoc) {
+ /*
+ * return/suspend result;
+ *
+ * result already where it needs to be.
+ */
+ return;
+ }
+
+ if (n->nd_id == PrefxNd && n->tok != NULL) {
+ switch (n->tok->tok_id) {
+ case C_Integer:
+ /*
+ * return/suspend C_integer <expr>;
+ */
+ prt_str(rslt_loc, indent);
+ prt_str(".vword.integr = ", indent);
+ c_walk(n->u[0].child, indent + IndentInc, 0);
+ prt_str(";", indent);
+ ForceNl();
+ prt_str(rslt_loc, indent);
+ prt_str(".dword = D_Integer;", indent);
+ chkabsret(t, int_typ); /* compare return with abstract return */
+ return;
+ case C_Double:
+ /*
+ * return/suspend C_double <expr>;
+ */
+ prt_str(rslt_loc, indent);
+ prt_str(".vword.bptr = (union block *)alcreal(", indent);
+ c_walk(n->u[0].child, indent + IndentInc, 0);
+ prt_str(");", indent + IndentInc);
+ ForceNl();
+ prt_str(rslt_loc, indent);
+ prt_str(".dword = D_Real;", indent);
+ /*
+ * The allocation of the real block may fail.
+ */
+ chk_rsltblk(indent);
+ chkabsret(t, real_typ); /* compare return with abstract return */
+ return;
+ case C_String:
+ /*
+ * return/suspend C_string <expr>;
+ */
+ prt_str(rslt_loc, indent);
+ prt_str(".vword.sptr = ", indent);
+ c_walk(n->u[0].child, indent + IndentInc, 0);
+ prt_str(";", indent);
+ ForceNl();
+ prt_str(rslt_loc, indent);
+ prt_str(".dword = strlen(", indent);
+ prt_str(rslt_loc, indent);
+ prt_str(".vword.sptr);", indent);
+ chkabsret(t, str_typ); /* compare return with abstract return */
+ return;
+ }
+ }
+ else if (n->nd_id == BinryNd && n->tok->tok_id == ')') {
+ /*
+ * Return value is in form of function call, see if it is really
+ * a descriptor constructor.
+ */
+ caller = n->u[0].child;
+ args = n->u[1].child;
+ if (caller->nd_id == SymNd) {
+ switch (caller->tok->tok_id) {
+ case IconType:
+ typcd = caller->u[0].sym->u.typ_indx;
+ switch (icontypes[typcd].rtl_ret) {
+ case TRetBlkP:
+ /*
+ * return/suspend <type>(<block-pntr>);
+ */
+ ret_1_arg(t, args, typcd, ".vword.bptr = (union block *)",
+ "(bp)", indent);
+ break;
+ case TRetDescP:
+ /*
+ * return/suspend <type>(<desc-pntr>);
+ */
+ ret_1_arg(t, args, typcd, ".vword.descptr = (dptr)",
+ "(dp)", indent);
+ break;
+ case TRetCharP:
+ /*
+ * return/suspend <type>(<char-pntr>);
+ */
+ ret_1_arg(t, args, typcd, ".vword.sptr = (char *)",
+ "(s)", indent);
+ break;
+ case TRetCInt:
+ /*
+ * return/suspend <type>(<integer>);
+ */
+ ret_1_arg(t, args, typcd, ".vword.integr = (word)",
+ "(i)", indent);
+ break;
+ case TRetSpcl:
+ if (typcd == str_typ) {
+ /*
+ * return/suspend string(<len>, <char-pntr>);
+ */
+ if (args == NULL || args->nd_id != CommaNd ||
+ args->u[0].child->nd_id == CommaNd)
+ errt1(t, "wrong no. of args for string(n, s)");
+ prt_str(rslt_loc, indent);
+ prt_str(".vword.sptr = ", indent);
+ c_walk(args->u[1].child, indent + IndentInc, 0);
+ prt_str(";", indent);
+ ForceNl();
+ prt_str(rslt_loc, indent);
+ prt_str(".dword = ", indent);
+ c_walk(args->u[0].child, indent + IndentInc, 0);
+ prt_str(";", indent);
+ }
+ else if (typcd == stv_typ) {
+ /*
+ * return/suspend tvsubs(<desc-pntr>, <start>, <len>);
+ */
+ if (args == NULL || args->nd_id != CommaNd ||
+ args->u[0].child->nd_id != CommaNd ||
+ args->u[0].child->u[0].child->nd_id == CommaNd)
+ errt1(t, "wrong no. of args for tvsubs(dp, i, j)");
+ no_nl = 1;
+ prt_str("SubStr(&", indent);
+ prt_str(rslt_loc, indent);
+ prt_str(", ", indent);
+ c_walk(args->u[0].child->u[0].child, indent + IndentInc,
+ 0);
+ prt_str(", ", indent + IndentInc);
+ c_walk(args->u[1].child, indent + IndentInc, 0);
+ prt_str(", ", indent + IndentInc);
+ c_walk(args->u[0].child->u[1].child, indent + IndentInc,
+ 0);
+ prt_str(");", indent + IndentInc);
+ no_nl = 0;
+ /*
+ * The allocation of the substring trapped variable
+ * block may fail.
+ */
+ chk_rsltblk(indent);
+ chkabsret(t, stv_typ); /* compare to abstract return */
+ }
+ break;
+ }
+ chkabsret(t, typcd); /* compare return with abstract return */
+ return;
+ case Named_var:
+ /*
+ * return/suspend named_var(<desc-pntr>);
+ */
+ if (args == NULL || args->nd_id == CommaNd)
+ errt1(t, "wrong no. of args for named_var(dp)");
+ prt_str(rslt_loc, indent);
+ prt_str(".vword.descptr = ", indent);
+ c_walk(args, indent + IndentInc, 0);
+ prt_str(";", indent);
+ ForceNl();
+ prt_str(rslt_loc, indent);
+ prt_str(".dword = D_Var;", indent);
+ chkabsret(t, TypVar); /* compare return with abstract return */
+ return;
+ case Struct_var:
+ /*
+ * return/suspend struct_var(<desc-pntr>, <block_pntr>);
+ */
+ if (args == NULL || args->nd_id != CommaNd ||
+ args->u[0].child->nd_id == CommaNd)
+ errt1(t, "wrong no. of args for struct_var(dp, bp)");
+ prt_str(rslt_loc, indent);
+ prt_str(".vword.descptr = (dptr)", indent);
+ c_walk(args->u[1].child, indent + IndentInc, 0);
+ prt_str(";", indent);
+ ForceNl();
+ prt_str(rslt_loc, indent);
+ prt_str(".dword = D_Var + ((word *)", indent);
+ c_walk(args->u[0].child, indent + IndentInc, 0);
+ prt_str(" - (word *)", indent+IndentInc);
+ prt_str(rslt_loc, indent);
+ prt_str(".vword.descptr);", indent+IndentInc);
+ ForceNl();
+ chkabsret(t, TypVar); /* compare return with abstract return */
+ return;
+ }
+ }
+ }
+
+ /*
+ * If it is not one of the special returns, it is just a return of
+ * a descriptor.
+ */
+ prt_str(rslt_loc, indent);
+ prt_str(" = ", indent);
+ c_walk(n, indent + IndentInc, 0);
+ prt_str(";", indent);
+ chkabsret(t, SomeType); /* check for preceding abstract return */
+ }
+
+/*
+ * ret_1_arg - produce code for a special return/suspend with one argument.
+ */
+static void ret_1_arg(t, args, typcd, vwrd_asgn, arg_rep, indent)
+struct token *t;
+struct node *args;
+int typcd;
+char *vwrd_asgn;
+char *arg_rep;
+int indent;
+ {
+ if (args == NULL || args->nd_id == CommaNd)
+ errt3(t, "wrong no. of args for", icontypes[typcd].id, arg_rep);
+
+ /*
+ * Assignment to vword of result descriptor.
+ */
+ prt_str(rslt_loc, indent);
+ prt_str(vwrd_asgn, indent);
+ c_walk(args, indent + IndentInc, 0);
+ prt_str(";", indent);
+ ForceNl();
+
+ /*
+ * Assignment to dword of result descriptor.
+ */
+ prt_str(rslt_loc, indent);
+ prt_str(".dword = D_", indent);
+ prt_str(icontypes[typcd].cap_id, indent);
+ prt_str(";", indent);
+ }
+
+/*
+ * chk_rsltblk - the result value contains an allocated block, make sure
+ * the allocation succeeded.
+ */
+static void chk_rsltblk(indent)
+int indent;
+ {
+ ForceNl();
+ prt_str("if (", indent);
+ prt_str(rslt_loc, indent);
+ prt_str(".vword.bptr == NULL) {", indent);
+ ForceNl();
+ prt_str("err_msg(307, NULL);", indent + IndentInc);
+ ForceNl();
+ /*
+ * Handle error conversion. Indicate that operation may fail because
+ * of error conversion and produce the necessary code.
+ */
+ cur_impl->ret_flag |= DoesEFail;
+ failure(indent + IndentInc, 1);
+ prt_str("}", indent + IndentInc);
+ ForceNl();
+ }
+
+/*
+ * failure - produce code for fail or efail.
+ */
+static void failure(indent, brace)
+int indent;
+int brace;
+ {
+ /*
+ * If there are tended variables, they must be removed from the tended
+ * list. The C function may or may not return an explicit signal.
+ */
+ ForceNl();
+ if (ntend != 0) {
+ if (!brace)
+ prt_str("{", indent);
+ untend(indent);
+ ForceNl();
+ if (fnc_ret == RetSig)
+ prt_str("return A_Resume;", indent);
+ else
+ prt_str("return;", indent);
+ if (!brace) {
+ ForceNl();
+ prt_str("}", indent);
+ }
+ }
+ else
+ if (fnc_ret == RetSig)
+ prt_str("return A_Resume;", indent);
+ else
+ prt_str("return;", indent);
+ ForceNl();
+ }
+
+/*
+ * c_walk - walk the syntax tree for extended C code and output the
+ * corresponding ordinary C. Return and indication of whether execution
+ * falls through the code.
+ */
+int c_walk(n, indent, brace)
+struct node *n;
+int indent;
+int brace;
+ {
+ struct token *t;
+ struct node *n1;
+ struct sym_entry *sym;
+ int fall_thru;
+ int save_break;
+ static int does_break = 0;
+ static int may_brnchto; /* may reach end of code by branching into middle */
+
+ if (n == NULL)
+ return 1;
+
+ t = n->tok;
+
+ switch (n->nd_id) {
+ case PrimryNd:
+ switch (t->tok_id) {
+ case Fail:
+ if (op_type == OrdFunc)
+ errt1(t, "'fail' may not be used in an ordinary C function");
+ cur_impl->ret_flag |= DoesFail;
+ failure(indent, brace);
+ chkabsret(t, SomeType); /* check preceding abstract return */
+ return 0;
+ case Errorfail:
+ if (op_type == OrdFunc)
+ errt1(t,
+ "'errorfail' may not be used in an ordinary C function");
+ cur_impl->ret_flag |= DoesEFail;
+ failure(indent, brace);
+ return 0;
+ case Break:
+ prt_tok(t, indent);
+ prt_str(";", indent);
+ does_break = 1;
+ return 0;
+ default:
+ /*
+ * Other "primary" expressions are just their token image,
+ * possibly followed by a semicolon.
+ */
+ prt_tok(t, indent);
+ if (t->tok_id == Continue)
+ prt_str(";", indent);
+ return 1;
+ }
+ case PrefxNd:
+ switch (t->tok_id) {
+ case Sizeof:
+ prt_tok(t, indent); /* sizeof */
+ prt_str("(", indent);
+ c_walk(n->u[0].child, indent, 0);
+ prt_str(")", indent);
+ return 1;
+ case '{':
+ /*
+ * Initializer list.
+ */
+ prt_tok(t, indent + IndentInc); /* { */
+ c_walk(n->u[0].child, indent + IndentInc, 0);
+ prt_str("}", indent + IndentInc);
+ return 1;
+ case Default:
+ prt_tok(t, indent - IndentInc); /* default (un-indented) */
+ prt_str(": ", indent - IndentInc);
+ fall_thru = c_walk(n->u[0].child, indent, 0);
+ may_brnchto = 1;
+ return fall_thru;
+ case Goto:
+ prt_tok(t, indent); /* goto */
+ prt_str(" ", indent);
+ c_walk(n->u[0].child, indent, 0);
+ prt_str(";", indent);
+ return 0;
+ case Return:
+ if (n->u[0].child != NULL)
+ no_ret_val = 0; /* note that return statement has no value */
+
+ if (op_type == OrdFunc || fnc_ret == RetInt ||
+ fnc_ret == RetDbl) {
+ /*
+ * ordinary C return: ignore C_integer, C_double, and
+ * C_string qualifiers on return expression (the first
+ * two may legally occur when fnc_ret is RetInt or RetDbl).
+ */
+ n1 = n->u[0].child;
+ if (n1 != NULL && n1->nd_id == PrefxNd && n1->tok != NULL) {
+ switch (n1->tok->tok_id) {
+ case C_Integer:
+ case C_Double:
+ case C_String:
+ n1 = n1->u[0].child;
+ }
+ }
+ if (ntend != 0) {
+ /*
+ * There are tended variables that must be removed from
+ * the tended list.
+ */
+ if (!brace)
+ prt_str("{", indent);
+ if (does_call(n1)) {
+ /*
+ * The return expression contains a function call;
+ * the variables must remain tended while it is
+ * computed, so compute it into a temporary variable
+ * named r_retval.Output a declaration for r_retval;
+ * its type must match the return type of the C
+ * function.
+ */
+ ForceNl();
+ prt_str("register ", indent);
+ if (op_type == OrdFunc) {
+ no_nl = 1;
+ just_type(fnc_head->u[0].child, indent, 0);
+ prt_str(" ", indent);
+ retval_dcltor(fnc_head->u[1].child, indent);
+ prt_str(";", indent);
+ no_nl = 0;
+ }
+ else if (fnc_ret == RetInt)
+ prt_str("C_integer r_retval;", indent);
+ else /* fnc_ret == RetDbl */
+ prt_str("double r_retval;", indent);
+ ForceNl();
+
+ /*
+ * Output code to compute the return value, untend
+ * the variable, then return the value.
+ */
+ prt_str("r_retval = ", indent);
+ c_walk(n1, indent + IndentInc, 0);
+ prt_str(";", indent);
+ untend(indent);
+ ForceNl();
+ prt_str("return r_retval;", indent);
+ }
+ else {
+ /*
+ * It is safe to untend the variables and return
+ * the result value directly with a return
+ * statement.
+ */
+ untend(indent);
+ ForceNl();
+ prt_tok(t, indent); /* return */
+ prt_str(" ", indent);
+ c_walk(n1, indent, 0);
+ prt_str(";", indent);
+ }
+ if (!brace) {
+ ForceNl();
+ prt_str("}", indent);
+ }
+ ForceNl();
+ }
+ else {
+ /*
+ * There are no tended variable, just output the
+ * return expression.
+ */
+ prt_tok(t, indent); /* return */
+ prt_str(" ", indent);
+ c_walk(n1, indent, 0);
+ prt_str(";", indent);
+ }
+
+ /*
+ * If this is a body function, check the return against
+ * preceding abstract returns.
+ */
+ if (fnc_ret == RetInt)
+ chkabsret(n->tok, int_typ);
+ else if (fnc_ret == RetDbl)
+ chkabsret(n->tok, real_typ);
+ }
+ else {
+ /*
+ * Return from Icon operation. Indicate that the operation
+ * returns, compute the value into the result location,
+ * untend variables if necessary, and return a signal
+ * if the function requires one.
+ */
+ cur_impl->ret_flag |= DoesRet;
+ ForceNl();
+ if (!brace) {
+ prt_str("{", indent);
+ ForceNl();
+ }
+ ret_value(t, n->u[0].child, indent);
+ if (ntend != 0)
+ untend(indent);
+ ForceNl();
+ if (fnc_ret == RetSig)
+ prt_str("return A_Continue;", indent);
+ else if (fnc_ret == RetNoVal)
+ prt_str("return;", indent);
+ ForceNl();
+ if (!brace) {
+ prt_str("}", indent);
+ ForceNl();
+ }
+ }
+ return 0;
+ case Suspend:
+ if (op_type == OrdFunc)
+ errt1(t, "'suspend' may not be used in an ordinary C function"
+ );
+ cur_impl->ret_flag |= DoesSusp; /* note suspension */
+ ForceNl();
+ if (!brace) {
+ prt_str("{", indent);
+ ForceNl();
+ }
+ prt_str("register int signal;", indent + IndentInc);
+ ForceNl();
+ ret_value(t, n->u[0].child, indent);
+ ForceNl();
+ /*
+ * The operator suspends by calling the success continuation
+ * if there is one or just returns if there is none. For
+ * the interpreter, interp() is the success continuation.
+ * A non-A_Resume signal from the success continuation must
+ * returned to the caller. If there are tended variables
+ * they must be removed from the tended list before a signal
+ * is returned.
+ */
+ if (iconx_flg) {
+ #ifdef EventMon
+ switch (op_type) {
+ case TokFunction:
+ prt_str(
+ "if ((signal = interp(G_Fsusp, r_args)) != A_Resume) {",
+ indent);
+ break;
+ case Operator:
+ case Keyword:
+ prt_str(
+ "if ((signal = interp(G_Osusp, r_args)) != A_Resume) {",
+ indent);
+ break;
+ default:
+ prt_str(
+ "if ((signal = interp(G_Csusp, r_args)) != A_Resume) {",
+ indent);
+ }
+ #else /* EventMon */
+ prt_str(
+ "if ((signal = interp(G_Csusp, r_args)) != A_Resume) {",
+ indent);
+ #endif /* EventMon */
+ }
+ else {
+ prt_str("if (r_s_cont == (continuation)NULL) {", indent);
+ if (ntend != 0)
+ untend(indent + IndentInc);
+ ForceNl();
+ prt_str("return A_Continue;", indent + IndentInc);
+ ForceNl();
+ prt_str("}", indent + IndentInc);
+ ForceNl();
+ prt_str("else if ((signal = (*r_s_cont)()) != A_Resume) {",
+ indent);
+ }
+ ForceNl();
+ if (ntend != 0)
+ untend(indent + IndentInc);
+ ForceNl();
+ prt_str("return signal;", indent + IndentInc);
+ ForceNl();
+ prt_str("}", indent + IndentInc);
+ if (!brace) {
+ prt_str("}", indent);
+ ForceNl();
+ }
+ return 1;
+ case '(':
+ /*
+ * Parenthesized expression.
+ */
+ prt_tok(t, indent); /* ( */
+ fall_thru = c_walk(n->u[0].child, indent, 0);
+ prt_str(")", indent);
+ return fall_thru;
+ default:
+ /*
+ * All other prefix expressions are printed as the token
+ * image of the operation followed by the operand.
+ */
+ prt_tok(t, indent);
+ c_walk(n->u[0].child, indent, 0);
+ return 1;
+ }
+ case PstfxNd:
+ /*
+ * All postfix expressions are printed as the operand followed
+ * by the token image of the operation.
+ */
+ fall_thru = c_walk(n->u[0].child, indent, 0);
+ prt_tok(t, indent);
+ return fall_thru;
+ case PreSpcNd:
+ /*
+ * This prefix expression (pointer indication in a declaration) needs
+ * a space after it.
+ */
+ prt_tok(t, indent);
+ c_walk(n->u[0].child, indent, 0);
+ prt_str(" ", indent);
+ return 1;
+ case SymNd:
+ /*
+ * Identifier.
+ */
+ prt_var(n, indent);
+ return 1;
+ case BinryNd:
+ switch (t->tok_id) {
+ case '[':
+ /*
+ * subscripting expression or declaration: <expr> [ <expr> ]
+ */
+ n1 = n->u[0].child;
+ c_walk(n->u[0].child, indent, 0);
+ prt_str("[", indent);
+ c_walk(n->u[1].child, indent, 0);
+ prt_str("]", indent);
+ return 1;
+ case '(':
+ /*
+ * cast: ( <type> ) <expr>
+ */
+ prt_tok(t, indent); /* ) */
+ c_walk(n->u[0].child, indent, 0);
+ prt_str(")", indent);
+ c_walk(n->u[1].child, indent, 0);
+ return 1;
+ case ')':
+ /*
+ * function call or declaration: <expr> ( <expr-list> )
+ */
+ c_walk(n->u[0].child, indent, 0);
+ prt_str("(", indent);
+ c_walk(n->u[1].child, indent, 0);
+ prt_tok(t, indent); /* ) */
+ return call_ret(n->u[0].child);
+ case Struct:
+ case Union:
+ /*
+ * struct/union <ident>
+ * struct/union <opt-ident> { <field-list> }
+ */
+ prt_tok(t, indent); /* struct or union */
+ prt_str(" ", indent);
+ c_walk(n->u[0].child, indent, 0);
+ if (n->u[1].child != NULL) {
+ /*
+ * Field declaration list.
+ */
+ prt_str(" {", indent);
+ c_walk(n->u[1].child, indent + IndentInc, 0);
+ ForceNl();
+ prt_str("}", indent);
+ }
+ return 1;
+ case TokEnum:
+ /*
+ * enum <ident>
+ * enum <opt-ident> { <enum-list> }
+ */
+ prt_tok(t, indent); /* enum */
+ prt_str(" ", indent);
+ c_walk(n->u[0].child, indent, 0);
+ if (n->u[1].child != NULL) {
+ /*
+ * enumerator list.
+ */
+ prt_str(" {", indent);
+ c_walk(n->u[1].child, indent + IndentInc, 0);
+ prt_str("}", indent);
+ }
+ return 1;
+ case ';':
+ /*
+ * <type-specs> <declarator> ;
+ */
+ c_walk(n->u[0].child, indent, 0);
+ prt_str(" ", indent);
+ c_walk(n->u[1].child, indent, 0);
+ prt_tok(t, indent); /* ; */
+ return 1;
+ case ':':
+ /*
+ * <label> : <statement>
+ */
+ c_walk(n->u[0].child, indent, 0);
+ prt_tok(t, indent); /* : */
+ prt_str(" ", indent);
+ fall_thru = c_walk(n->u[1].child, indent, 0);
+ may_brnchto = 1;
+ return fall_thru;
+ case Case:
+ /*
+ * case <expr> : <statement>
+ */
+ prt_tok(t, indent - IndentInc); /* case (un-indented) */
+ prt_str(" ", indent);
+ c_walk(n->u[0].child, indent - IndentInc, 0);
+ prt_str(": ", indent - IndentInc);
+ fall_thru = c_walk(n->u[1].child, indent, 0);
+ may_brnchto = 1;
+ return fall_thru;
+ case Switch:
+ /*
+ * switch ( <expr> ) <statement>
+ *
+ * <statement> is double indented so that case and default
+ * statements can be un-indented and come out indented 1
+ * with respect to the switch. Statements that are not
+ * "labeled" with case or default are indented one more
+ * than those that are labeled.
+ */
+ prt_tok(t, indent); /* switch */
+ prt_str(" (", indent);
+ c_walk(n->u[0].child, indent, 0);
+ prt_str(")", indent);
+ prt_str(" ", indent);
+ save_break = does_break;
+ fall_thru = c_walk(n->u[1].child, indent + 2 * IndentInc, 0);
+ fall_thru |= does_break;
+ does_break = save_break;
+ return fall_thru;
+ case While: {
+ struct node *n0;
+ /*
+ * While ( <expr> ) <statement>
+ */
+ n0 = n->u[0].child;
+ prt_tok(t, indent); /* while */
+ prt_str(" (", indent);
+ c_walk(n0, indent, 0);
+ prt_str(")", indent);
+ prt_str(" ", indent);
+ save_break = does_break;
+ c_walk(n->u[1].child, indent + IndentInc, 0);
+ /*
+ * check for an infinite loop, while (1) ... :
+ * a condition consisting of an IntConst with image=="1"
+ * and no breaks in the body.
+ */
+ if (n0->nd_id == PrimryNd && n0->tok->tok_id == IntConst &&
+ !strcmp(n0->tok->image,"1") && !does_break)
+ fall_thru = 0;
+ else
+ fall_thru = 1;
+ does_break = save_break;
+ return fall_thru;
+ }
+ case Do:
+ /*
+ * do <statement> <while> ( <expr> )
+ */
+ prt_tok(t, indent); /* do */
+ prt_str(" ", indent);
+ c_walk(n->u[0].child, indent + IndentInc, 0);
+ ForceNl();
+ prt_str("while (", indent);
+ save_break = does_break;
+ c_walk(n->u[1].child, indent, 0);
+ does_break = save_break;
+ prt_str(");", indent);
+ return 1;
+ case '.':
+ case Arrow:
+ /*
+ * Field access: <expr> . <expr> and <expr> -> <expr>
+ */
+ c_walk(n->u[0].child, indent, 0);
+ prt_tok(t, indent); /* . or -> */
+ c_walk(n->u[1].child, indent, 0);
+ return 1;
+ case Runerr:
+ /*
+ * runerr ( <error-number> )
+ * runerr ( <error-number> , <offending-value> )
+ */
+ prt_runerr(t, n->u[0].child, n->u[1].child, indent);
+ return 0;
+ case Is:
+ /*
+ * is : <type> ( <expr> )
+ */
+ typ_asrt(icn_typ(n->u[0].child), n->u[1].child,
+ n->u[0].child->tok, indent);
+ return 1;
+ default:
+ /*
+ * All other binary expressions are infix notation and
+ * are printed with spaces around the operator.
+ */
+ c_walk(n->u[0].child, indent, 0);
+ prt_str(" ", indent);
+ prt_tok(t, indent);
+ prt_str(" ", indent);
+ c_walk(n->u[1].child, indent, 0);
+ return 1;
+ }
+ case LstNd:
+ /*
+ * <declaration-part> <declaration-part>
+ *
+ * Need space between parts
+ */
+ c_walk(n->u[0].child, indent, 0);
+ prt_str(" ", indent);
+ c_walk(n->u[1].child, indent, 0);
+ return 1;
+ case ConCatNd:
+ /*
+ * <some-code> <some-code>
+ *
+ * Various lists of code parts that do not need space between them.
+ */
+ if (c_walk(n->u[0].child, indent, 0))
+ return c_walk(n->u[1].child, indent, 0);
+ else {
+ /*
+ * Cannot directly reach the second piece of code, see if
+ * it is possible to branch into it.
+ */
+ may_brnchto = 0;
+ fall_thru = c_walk(n->u[1].child, indent, 0);
+ return may_brnchto & fall_thru;
+ }
+ case CommaNd:
+ /*
+ * <expr> , <expr>
+ */
+ c_walk(n->u[0].child, indent, 0);
+ prt_tok(t, indent);
+ prt_str(" ", indent);
+ return c_walk(n->u[1].child, indent, 0);
+ case StrDclNd:
+ /*
+ * Structure field declaration. Bit field declarations have
+ * a semicolon and a field width.
+ */
+ c_walk(n->u[0].child, indent, 0);
+ if (n->u[1].child != NULL) {
+ prt_str(": ", indent);
+ c_walk(n->u[1].child, indent, 0);
+ }
+ return 1;
+ case CompNd:
+ /*
+ * Compound statement.
+ */
+ if (brace)
+ tok_line(t, indent); /* just synch. file name and line number */
+ else
+ prt_tok(t, indent); /* { */
+ c_walk(n->u[0].child, indent, 0);
+ /*
+ * we are in an inner block. tended locations may need to
+ * be set to values from declaration initializations.
+ */
+ for (sym = n->u[1].sym; sym!= NULL; sym = sym->u.tnd_var.next) {
+ if (sym->u.tnd_var.init != NULL) {
+ prt_str(tendstrct, IndentInc);
+ fprintf(out_file, ".d[%d]", sym->t_indx);
+ switch (sym->id_type) {
+ case TndDesc:
+ prt_str(" = ", IndentInc);
+ break;
+ case TndStr:
+ prt_str(".vword.sptr = ", IndentInc);
+ break;
+ case TndBlk:
+ prt_str(".vword.bptr = (union block *)",
+ IndentInc);
+ break;
+ }
+ c_walk(sym->u.tnd_var.init, 2 * IndentInc, 0);
+ prt_str(";", 2 * IndentInc);
+ ForceNl();
+ }
+ }
+ /*
+ * If there are no declarations, suppress braces that
+ * may be required for a one-statement body; we already
+ * have a set.
+ */
+ if (n->u[0].child == NULL && n->u[1].sym == NULL)
+ fall_thru = c_walk(n->u[2].child, indent, 1);
+ else
+ fall_thru = c_walk(n->u[2].child, indent, 0);
+ if (!brace) {
+ ForceNl();
+ prt_str("}", indent);
+ }
+ return fall_thru;
+ case TrnryNd:
+ switch (t->tok_id) {
+ case '?':
+ /*
+ * <expr> ? <expr> : <expr>
+ */
+ c_walk(n->u[0].child, indent, 0);
+ prt_str(" ", indent);
+ prt_tok(t, indent); /* ? */
+ prt_str(" ", indent);
+ c_walk(n->u[1].child, indent, 0);
+ prt_str(" : ", indent);
+ c_walk(n->u[2].child, indent, 0);
+ return 1;
+ case If:
+ /*
+ * if ( <expr> ) <statement>
+ * if ( <expr> ) <statement> else <statement>
+ */
+ prt_tok(t, indent); /* if */
+ prt_str(" (", indent);
+ c_walk(n->u[0].child, indent + IndentInc, 0);
+ prt_str(") ", indent);
+ fall_thru = c_walk(n->u[1].child, indent + IndentInc, 0);
+ n1 = n->u[2].child;
+ if (n1 == NULL)
+ fall_thru = 1;
+ else {
+ /*
+ * There is an else statement. Don't indent an
+ * "else if"
+ */
+ ForceNl();
+ prt_str("else ", indent);
+ if (n1->nd_id == TrnryNd && n1->tok->tok_id == If)
+ fall_thru |= c_walk(n1, indent, 0);
+ else
+ fall_thru |= c_walk(n1, indent + IndentInc, 0);
+ }
+ return fall_thru;
+ case Type_case:
+ /*
+ * type_case <expr> of { <section-list> }
+ * type_case <expr> of { <section-list> <default-clause> }
+ */
+ return typ_case(n->u[0].child, n->u[1].child, n->u[2].child,
+ c_walk, 1, indent);
+ case Cnv:
+ /*
+ * cnv : <type> ( <source> , <destination> )
+ */
+ cnv_fnc(t, icn_typ(n->u[0].child), n->u[1].child, NULL,
+ n->u[2].child,
+ indent);
+ return 1;
+ }
+ case QuadNd:
+ switch (t->tok_id) {
+ case For:
+ /*
+ * for ( <expr> ; <expr> ; <expr> ) <statement>
+ */
+ prt_tok(t, indent); /* for */
+ prt_str(" (", indent);
+ c_walk(n->u[0].child, indent, 0);
+ prt_str("; ", indent);
+ c_walk(n->u[1].child, indent, 0);
+ prt_str("; ", indent);
+ c_walk(n->u[2].child, indent, 0);
+ prt_str(") ", indent);
+ save_break = does_break;
+ c_walk(n->u[3].child, indent + IndentInc, 0);
+ if (n->u[1].child == NULL && !does_break)
+ fall_thru = 0;
+ else
+ fall_thru = 1;
+ does_break = save_break;
+ return fall_thru;
+ case Def:
+ /*
+ * def : <type> ( <source> , <default> , <destination> )
+ */
+ cnv_fnc(t, icn_typ(n->u[0].child), n->u[1].child, n->u[2].child,
+ n->u[3].child, indent);
+ return 1;
+ }
+ }
+ /*NOTREACHED*/
+ return 0; /* avoid gcc warning */
+ }
+
+/*
+ * call_ret - decide whether a function being called might return.
+ */
+int call_ret(n)
+struct node *n;
+ {
+ /*
+ * Assume functions return except for c_exit(), fatalerr(), and syserr().
+ */
+ if (n->tok != NULL &&
+ (strcmp("c_exit", n->tok->image) == 0 ||
+ strcmp("fatalerr", n->tok->image) == 0 ||
+ strcmp("syserr", n->tok->image) == 0))
+ return 0;
+ else
+ return 1;
+ }
+
+/*
+ * new_prmloc - allocate an array large enough to hold a flag for every
+ * parameter of the current operation. This flag indicates where
+ * the parameter is in terms of scopes created by conversions.
+ */
+struct parminfo *new_prmloc()
+ {
+ struct parminfo *parminfo;
+ int nparams;
+ int i;
+
+ if (params == NULL)
+ return NULL;
+ nparams = params->u.param_info.param_num + 1;
+ parminfo = alloc(nparams * sizeof(struct parminfo));
+ for (i = 0; i < nparams; ++i) {
+ parminfo[i].cur_loc = 0;
+ parminfo [i].parm_mod = 0;
+ }
+ return parminfo;
+ }
+
+/*
+ * ld_prmloc - load parameter location information that has been
+ * saved in an arrary into the symbol table.
+ */
+void ld_prmloc(parminfo)
+struct parminfo *parminfo;
+ {
+ struct sym_entry *sym;
+ int param_num;
+
+ for (sym = params; sym != NULL; sym = sym->u.param_info.next) {
+ param_num = sym->u.param_info.param_num;
+ if (sym->id_type & DrfPrm) {
+ sym->u.param_info.cur_loc = parminfo[param_num].cur_loc;
+ sym->u.param_info.parm_mod = parminfo[param_num].parm_mod;
+ }
+ }
+ }
+
+/*
+ * sv_prmloc - save parameter location information from the the symbol table
+ * into an array.
+ */
+void sv_prmloc(parminfo)
+struct parminfo *parminfo;
+ {
+ struct sym_entry *sym;
+ int param_num;
+
+ for (sym = params; sym != NULL; sym = sym->u.param_info.next) {
+ param_num = sym->u.param_info.param_num;
+ if (sym->id_type & DrfPrm) {
+ parminfo[param_num].cur_loc = sym->u.param_info.cur_loc;
+ parminfo[param_num].parm_mod = sym->u.param_info.parm_mod;
+ }
+ }
+ }
+
+/*
+ * mrg_prmloc - merge parameter location information in the symbol table
+ * with other information already saved in an array. This may result
+ * in conflicting location information, but conflicts are only detected
+ * when a parameter is actually used.
+ */
+void mrg_prmloc(parminfo)
+struct parminfo *parminfo;
+ {
+ struct sym_entry *sym;
+ int param_num;
+
+ for (sym = params; sym != NULL; sym = sym->u.param_info.next) {
+ param_num = sym->u.param_info.param_num;
+ if (sym->id_type & DrfPrm) {
+ parminfo[param_num].cur_loc |= sym->u.param_info.cur_loc;
+ parminfo[param_num].parm_mod |= sym->u.param_info.parm_mod;
+ }
+ }
+ }
+
+/*
+ * clr_prmloc - indicate that this execution path contributes nothing
+ * to the location of parameters.
+ */
+void clr_prmloc()
+ {
+ struct sym_entry *sym;
+
+ for (sym = params; sym != NULL; sym = sym->u.param_info.next) {
+ if (sym->id_type & DrfPrm) {
+ sym->u.param_info.cur_loc = 0;
+ sym->u.param_info.parm_mod = 0;
+ }
+ }
+ }
+
+/*
+ * typ_case - translate a type_case statement into C. This is called
+ * while walking a syntax tree of either RTL code or C code; the parameter
+ * "walk" is a function used to process the subtrees within the type_case
+ * statement.
+ */
+static int typ_case(var, slct_lst, dflt, walk, maybe_var, indent)
+struct node *var;
+struct node *slct_lst;
+struct node *dflt;
+int (*walk)(struct node *n, int xindent, int brace);
+int maybe_var;
+int indent;
+ {
+ struct node *lst;
+ struct node *select;
+ struct node *slctor;
+ struct parminfo *strt_prms;
+ struct parminfo *end_prms;
+ int remaining;
+ int first;
+ int fnd_slctrs;
+ int maybe_str = 1;
+ int dflt_lbl;
+ int typcd;
+ int fall_thru;
+ char *s;
+
+ /*
+ * This statement involves multiple paths that may establish new
+ * scopes for parameters. Remember the starting scope information
+ * and initialize an array in which to compute the final information.
+ */
+ strt_prms = new_prmloc();
+ sv_prmloc(strt_prms);
+ end_prms = new_prmloc();
+
+ /*
+ * First look for cases that must be checked with "if" statements.
+ * These include string qualifiers and variables.
+ */
+ remaining = 0; /* number of cases skipped in first pass */
+ first = 1; /* next case to be output is the first */
+ if (dflt == NULL)
+ fall_thru = 1;
+ else
+ fall_thru = 0;
+ for (lst = slct_lst; lst != NULL; lst = lst->u[0].child) {
+ select = lst->u[1].child;
+ fnd_slctrs = 0; /* flag: found type selections for clause for this pass */
+ /*
+ * A selection clause may include several types.
+ */
+ for (slctor = select->u[0].child; slctor != NULL; slctor =
+ slctor->u[0].child) {
+ typcd = icn_typ(slctor->u[1].child);
+ if(typ_name(typcd, slctor->u[1].child->tok) == NULL) {
+ /*
+ * This type must be checked with the "if". Is this the
+ * first condition checked for this clause? Is this the
+ * first clause output?
+ */
+ if (fnd_slctrs)
+ prt_str(" || ", indent);
+ else {
+ if (first)
+ first = 0;
+ else {
+ ForceNl();
+ prt_str("else ", indent);
+ }
+ prt_str("if (", indent);
+ fnd_slctrs = 1;
+ }
+
+ /*
+ * Output type check
+ */
+ typ_asrt(typcd, var, slctor->u[1].child->tok, indent + IndentInc);
+
+ if (typcd == str_typ)
+ maybe_str = 0; /* string has been taken care of */
+ else if (typcd == Variable)
+ maybe_var = 0; /* variable has been taken care of */
+ }
+ else
+ ++remaining;
+ }
+ if (fnd_slctrs) {
+ /*
+ * We have found and output type selections for this clause;
+ * output the body of the clause. Remember any changes to
+ * paramter locations caused by type conversions within the
+ * clause.
+ */
+ prt_str(") {", indent + IndentInc);
+ ForceNl();
+ if ((*walk)(select->u[1].child, indent + IndentInc, 1)) {
+ fall_thru |= 1;
+ mrg_prmloc(end_prms);
+ }
+ prt_str("}", indent + IndentInc);
+ ForceNl();
+ ld_prmloc(strt_prms);
+ }
+ }
+ /*
+ * The rest of the cases can be checked with a "switch" statement, look
+ * for them..
+ */
+ if (remaining == 0) {
+ if (dflt != NULL) {
+ /*
+ * There are no cases to handle with a switch statement, but there
+ * is a default clause; handle it with an "else".
+ */
+ prt_str("else {", indent);
+ ForceNl();
+ fall_thru |= (*walk)(dflt, indent + IndentInc, 1);
+ ForceNl();
+ prt_str("}", indent + IndentInc);
+ ForceNl();
+ }
+ }
+ else {
+ /*
+ * If an "if" statement was output, the "switch" must be in its "else"
+ * clause.
+ */
+ if (!first)
+ prt_str("else ", indent);
+
+ /*
+ * A switch statement cannot handle types that are not simple type
+ * codes. If these have not taken care of, output code to check them.
+ * This will either branch around the switch statement or into
+ * its default clause.
+ */
+ if (maybe_str || maybe_var) {
+ dflt_lbl = lbl_num++; /* allocate a label number */
+ prt_str("{", indent);
+ ForceNl();
+ prt_str("if (((", indent);
+ c_walk(var, indent + IndentInc, 0);
+ prt_str(").dword & D_Typecode) != D_Typecode) ", indent);
+ ForceNl();
+ prt_str("goto L", indent + IndentInc);
+ fprintf(out_file, "%d; /* default */ ", dflt_lbl);
+ ForceNl();
+ }
+
+ no_nl = 1; /* suppress #line directives */
+ prt_str("switch (Type(", indent);
+ c_walk(var, indent + IndentInc, 0);
+ prt_str(")) {", indent + IndentInc);
+ no_nl = 0;
+ ForceNl();
+
+ /*
+ * Loop through the case clauses producing code for them.
+ */
+ for (lst = slct_lst; lst != NULL; lst = lst->u[0].child) {
+ select = lst->u[1].child;
+ fnd_slctrs = 0;
+ /*
+ * A selection clause may include several types.
+ */
+ for (slctor = select->u[0].child; slctor != NULL; slctor =
+ slctor->u[0].child) {
+ typcd = icn_typ(slctor->u[1].child);
+ s = typ_name(typcd, slctor->u[1].child->tok);
+ if (s != NULL) {
+ /*
+ * A type selection has been found that can be checked
+ * in the switch statement. Note that large integers
+ * require special handling.
+ */
+ fnd_slctrs = 1;
+
+ if (typcd == int_typ) {
+ ForceNl();
+ prt_str("#ifdef LargeInts", 0);
+ ForceNl();
+ prt_str("case T_Lrgint: ", indent + IndentInc);
+ ForceNl();
+ prt_str("#endif /* LargeInts */", 0);
+ ForceNl();
+ }
+
+ prt_str("case T_", indent + IndentInc);
+ prt_str(s, indent + IndentInc);
+ prt_str(": ", indent + IndentInc);
+ }
+ }
+ if (fnd_slctrs) {
+ /*
+ * We have found and output type selections for this clause;
+ * output the body of the clause. Remember any changes to
+ * paramter locations caused by type conversions within the
+ * clause.
+ */
+ ForceNl();
+ if ((*walk)(select->u[1].child, indent + 2 * IndentInc, 0)) {
+ fall_thru |= 1;
+ ForceNl();
+ prt_str("break;", indent + 2 * IndentInc);
+ mrg_prmloc(end_prms);
+ }
+ ForceNl();
+ ld_prmloc(strt_prms);
+ }
+ }
+ if (dflt != NULL) {
+ /*
+ * This type_case statement has a default clause. If there is
+ * a branch into this clause, output the label. Remember any
+ * changes to paramter locations caused by type conversions
+ * within the clause.
+ */
+ ForceNl();
+ prt_str("default:", indent + 1 * IndentInc);
+ ForceNl();
+ if (maybe_str || maybe_var) {
+ prt_str("L", 0);
+ fprintf(out_file, "%d: ; /* default */", dflt_lbl);
+ ForceNl();
+ }
+ if ((*walk)(dflt, indent + 2 * IndentInc, 0)) {
+ fall_thru |= 1;
+ mrg_prmloc(end_prms);
+ }
+ ForceNl();
+ ld_prmloc(strt_prms);
+ }
+ prt_str("}", indent + IndentInc);
+
+ if (maybe_str || maybe_var) {
+ if (dflt == NULL) {
+ /*
+ * There is a branch around the switch statement. Output
+ * the label.
+ */
+ ForceNl();
+ prt_str("L", 0);
+ fprintf(out_file, "%d: ; /* default */", dflt_lbl);
+ }
+ ForceNl();
+ prt_str("}", indent + IndentInc);
+ }
+ ForceNl();
+ }
+
+ /*
+ * Put ending parameter locations into effect.
+ */
+ mrg_prmloc(end_prms);
+ ld_prmloc(end_prms);
+ if (strt_prms != NULL)
+ free(strt_prms);
+ if (end_prms != NULL)
+ free(end_prms);
+ return fall_thru;
+ }
+
+/*
+ * chk_conj - see if the left argument of a conjunction is an in-place
+ * conversion of a parameter other than a conversion to C_integer or
+ * C_double. If so issue a warning.
+ */
+static void chk_conj(n)
+struct node *n;
+ {
+ struct node *cnv_type;
+ struct node *src;
+ struct node *dest;
+ int typcd;
+
+ if (n->nd_id == BinryNd && n->tok->tok_id == And)
+ n = n->u[1].child;
+
+ switch (n->nd_id) {
+ case TrnryNd:
+ /*
+ * Must be Cnv.
+ */
+ cnv_type = n->u[0].child;
+ src = n->u[1].child;
+ dest = n->u[2].child;
+ break;
+ case QuadNd:
+ /*
+ * Must be Def.
+ */
+ cnv_type = n->u[0].child;
+ src = n->u[1].child;
+ dest = n->u[3].child;
+ break;
+ default:
+ return; /* not a conversion */
+ }
+
+ /*
+ * A conversion has been found. See if it meets the criteria for
+ * issuing a warning.
+ */
+
+ if (src->nd_id != SymNd || !(src->u[0].sym->id_type & DrfPrm))
+ return; /* not a dereferenced parameter */
+
+ typcd = icn_typ(cnv_type);
+ switch (typcd) {
+ case TypCInt:
+ case TypCDbl:
+ case TypECInt:
+ return;
+ }
+
+ if (dest != NULL)
+ return; /* not an in-place convertion */
+
+ fprintf(stderr,
+ "%s: file %s, line %d, warning: in-place conversion may or may not be\n",
+ progname, cnv_type->tok->fname, cnv_type->tok->line);
+ fprintf(stderr, "\tundone on subsequent failure.\n");
+ }
+
+/*
+ * len_sel - translate a clause form a len_case statement into a C case
+ * clause. Return an indication of whether execution falls through the
+ * clause.
+ */
+static int len_sel(sel, strt_prms, end_prms, indent)
+struct node *sel;
+struct parminfo *strt_prms;
+struct parminfo *end_prms;
+int indent;
+ {
+ int fall_thru;
+
+ prt_str("case ", indent);
+ prt_tok(sel->tok, indent + IndentInc); /* integer selection */
+ prt_str(":", indent + IndentInc);
+ fall_thru = rt_walk(sel->u[0].child, indent + IndentInc, 0);/* clause body */
+ ForceNl();
+
+ if (fall_thru) {
+ prt_str("break;", indent + IndentInc);
+ ForceNl();
+ /*
+ * Remember any changes to paramter locations caused by type conversions
+ * within the clause.
+ */
+ mrg_prmloc(end_prms);
+ }
+
+ ld_prmloc(strt_prms);
+ return fall_thru;
+ }
+
+/*
+ * rt_walk - walk the part of the syntax tree containing rtt code, producing
+ * code for the most-general version of the routine.
+ */
+static int rt_walk(n, indent, brace)
+struct node *n;
+int indent;
+int brace;
+ {
+ struct token *t, *t1;
+ struct node *n1, *errnum;
+ int fall_thru;
+
+ if (n == NULL)
+ return 1;
+
+ t = n->tok;
+
+ switch (n->nd_id) {
+ case PrefxNd:
+ switch (t->tok_id) {
+ case '{':
+ /*
+ * RTL code: { <actions> }
+ */
+ if (brace)
+ tok_line(t, indent); /* just synch file name and line num */
+ else
+ prt_tok(t, indent); /* { */
+ fall_thru = rt_walk(n->u[0].child, indent, 1);
+ if (!brace)
+ prt_str("}", indent);
+ return fall_thru;
+ case '!':
+ /*
+ * RTL type-checking and conversions: ! <simple-type-check>
+ */
+ prt_tok(t, indent);
+ rt_walk(n->u[0].child, indent, 0);
+ return 1;
+ case Body:
+ case Inline:
+ /*
+ * RTL code: body { <c-code> }
+ * inline { <c-code> }
+ */
+ fall_thru = c_walk(n->u[0].child, indent, brace);
+ if (!fall_thru)
+ clr_prmloc();
+ return fall_thru;
+ }
+ break;
+ case BinryNd:
+ switch (t->tok_id) {
+ case Runerr:
+ /*
+ * RTL code: runerr( <message-number> )
+ * runerr( <message-number>, <descriptor> )
+ */
+ prt_runerr(t, n->u[0].child, n->u[1].child, indent);
+
+ /*
+ * Execution cannot continue on this execution path.
+ */
+ clr_prmloc();
+ return 0;
+ case And:
+ /*
+ * RTL type-checking and conversions:
+ * <type-check> && <type_check>
+ */
+ chk_conj(n->u[0].child); /* is a warning needed? */
+ rt_walk(n->u[0].child, indent, 0);
+ prt_str(" ", indent);
+ prt_tok(t, indent); /* && */
+ prt_str(" ", indent);
+ rt_walk(n->u[1].child, indent, 0);
+ return 1;
+ case Is:
+ /*
+ * RTL type-checking and conversions:
+ * is: <icon-type> ( <variable> )
+ */
+ typ_asrt(icn_typ(n->u[0].child), n->u[1].child,
+ n->u[0].child->tok, indent);
+ return 1;
+ }
+ break;
+ case ConCatNd:
+ /*
+ * "Glue" for two constructs.
+ */
+ fall_thru = rt_walk(n->u[0].child, indent, 0);
+ return fall_thru & rt_walk(n->u[1].child, indent, 0);
+ case AbstrNd:
+ /*
+ * Ignore abstract type computations while producing C code
+ * for library routines.
+ */
+ return 1;
+ case TrnryNd:
+ switch (t->tok_id) {
+ case If: {
+ /*
+ * RTL code for "if" statements:
+ * if <type-check> then <action>
+ * if <type-check> then <action> else <action>
+ *
+ * <type-check> may include parameter conversions that create
+ * new scoping. It is necessary to keep track of paramter
+ * types and locations along success and failure paths of
+ * these conversions. The "then" and "else" actions may
+ * also establish new scopes.
+ */
+ struct parminfo *then_prms = NULL;
+ struct parminfo *else_prms;
+
+ /*
+ * Save the current parameter locations. These are in
+ * effect on the failure path of any type conversions
+ * in the condition of the "if".
+ */
+ else_prms = new_prmloc();
+ sv_prmloc(else_prms);
+
+ prt_tok(t, indent); /* if */
+ prt_str(" (", indent);
+ n1 = n->u[0].child;
+ rt_walk(n1, indent + IndentInc, 0); /* type check */
+ prt_str(") {", indent);
+
+ /*
+ * If the condition is negated, the failure path is to the "then"
+ * and the success path is to the "else".
+ */
+ if (n1->nd_id == PrefxNd && n1->tok->tok_id == '!') {
+ then_prms = else_prms;
+ else_prms = new_prmloc();
+ sv_prmloc(else_prms);
+ ld_prmloc(then_prms);
+ }
+
+ /*
+ * Then Clause.
+ */
+ fall_thru = rt_walk(n->u[1].child, indent + IndentInc, 1);
+ ForceNl();
+ prt_str("}", indent + IndentInc);
+
+ /*
+ * Determine if there is an else clause and merge parameter
+ * location information from the alternate paths through
+ * the statement.
+ */
+ n1 = n->u[2].child;
+ if (n1 == NULL) {
+ if (fall_thru)
+ mrg_prmloc(else_prms);
+ ld_prmloc(else_prms);
+ fall_thru = 1;
+ }
+ else {
+ if (then_prms == NULL)
+ then_prms = new_prmloc();
+ if (fall_thru)
+ sv_prmloc(then_prms);
+ ld_prmloc(else_prms);
+ ForceNl();
+ prt_str("else {", indent);
+ if (rt_walk(n1, indent + IndentInc, 1)) { /* else clause */
+ fall_thru = 1;
+ mrg_prmloc(then_prms);
+ }
+ ForceNl();
+ prt_str("}", indent + IndentInc);
+ ld_prmloc(then_prms);
+ }
+ ForceNl();
+ if (then_prms != NULL)
+ free(then_prms);
+ if (else_prms != NULL)
+ free(else_prms);
+ }
+ return fall_thru;
+ case Len_case: {
+ /*
+ * RTL code:
+ * len_case <variable> of {
+ * <integer>: <action>
+ * ...
+ * default: <action>
+ * }
+ */
+ struct parminfo *strt_prms;
+ struct parminfo *end_prms;
+
+ /*
+ * A case may contain parameter conversions that create new
+ * scopes. Remember the parameter locations at the start
+ * of the len_case statement.
+ */
+ strt_prms = new_prmloc();
+ sv_prmloc(strt_prms);
+ end_prms = new_prmloc();
+
+ n1 = n->u[0].child;
+ if (!(n1->u[0].sym->id_type & VArgLen))
+ errt1(t, "len_case must select on length of vararg");
+ /*
+ * The len_case statement is implemented as a C switch
+ * statement.
+ */
+ prt_str("switch (", indent);
+ prt_var(n1, indent);
+ prt_str(") {", indent);
+ ForceNl();
+ fall_thru = 0;
+ for (n1 = n->u[1].child; n1->nd_id == ConCatNd;
+ n1 = n1->u[0].child)
+ fall_thru |= len_sel(n1->u[1].child, strt_prms, end_prms,
+ indent + IndentInc);
+ fall_thru |= len_sel(n1, strt_prms, end_prms,
+ indent + IndentInc);
+
+ /*
+ * Handle default clause.
+ */
+ prt_str("default:", indent + IndentInc);
+ ForceNl();
+ fall_thru |= rt_walk(n->u[2].child, indent + 2 * IndentInc, 0);
+ ForceNl();
+ prt_str("}", indent + IndentInc);
+ ForceNl();
+
+ /*
+ * Put into effect the location of parameters at the end
+ * of the len_case statement.
+ */
+ mrg_prmloc(end_prms);
+ ld_prmloc(end_prms);
+ if (strt_prms != NULL)
+ free(strt_prms);
+ if (end_prms != NULL)
+ free(end_prms);
+ }
+ return fall_thru;
+ case Type_case: {
+ /*
+ * RTL code:
+ * type_case <variable> of {
+ * <icon_type> : ... <icon_type> : <action>
+ * ...
+ * }
+ *
+ * last clause may be: default: <action>
+ */
+ int maybe_var;
+ struct node *var;
+ struct sym_entry *sym;
+
+ /*
+ * If we can determine that the value being checked is
+ * not a variable reference, we don't have to produce code
+ * to check for that possibility.
+ */
+ maybe_var = 1;
+ var = n->u[0].child;
+ if (var->nd_id == SymNd) {
+ sym = var->u[0].sym;
+ switch(sym->id_type) {
+ case DrfPrm:
+ case OtherDcl:
+ case TndDesc:
+ case TndStr:
+ case RsltLoc:
+ if (sym->nest_lvl > 1) {
+ /*
+ * The thing being tested is either a
+ * dereferenced parameter or a local
+ * descriptor which could only have been
+ * set by a conversion which does not
+ * produce a variable reference.
+ */
+ maybe_var = 0;
+ }
+ }
+ }
+ return typ_case(var, n->u[1].child, n->u[2].child, rt_walk,
+ maybe_var, indent);
+ }
+ case Cnv:
+ /*
+ * RTL code: cnv: <type> ( <source> )
+ * cnv: <type> ( <source> , <destination> )
+ */
+ cnv_fnc(t, icn_typ(n->u[0].child), n->u[1].child, NULL,
+ n->u[2].child, indent);
+ return 1;
+ case Arith_case: {
+ /*
+ * arith_case (<variable>, <variable>) of {
+ * C_integer: <statement>
+ * integer: <statement>
+ * C_double: <statement>
+ * }
+ *
+ * This construct does type conversions and provides
+ * alternate execution paths. It is necessary to keep
+ * track of parameter locations.
+ */
+ struct parminfo *strt_prms;
+ struct parminfo *end_prms;
+ struct parminfo *tmp_prms;
+
+ strt_prms = new_prmloc();
+ sv_prmloc(strt_prms);
+ end_prms = new_prmloc();
+ tmp_prms = new_prmloc();
+
+ fall_thru = 0;
+
+ n1 = n->u[2].child; /* contains actions for the 3 cases */
+
+ /*
+ * Set up an error number node for use in runerr().
+ */
+ t1 = copy_t(t);
+ t1->tok_id = IntConst;
+ t1->image = "102";
+ errnum = node0(PrimryNd, t1);
+
+ /*
+ * Try converting both arguments to a C_integer.
+ */
+ tok_line(t, indent);
+ prt_str("if (", indent);
+ cnv_fnc(t, TypECInt, n->u[0].child, NULL, NULL, indent);
+ prt_str(" && ", indent);
+ cnv_fnc(t, TypECInt, n->u[1].child, NULL, NULL, indent);
+ prt_str(") ", indent);
+ ForceNl();
+ if (rt_walk(n1->u[0].child, indent + IndentInc, 0)) {
+ fall_thru |= 1;
+ mrg_prmloc(end_prms);
+ }
+ ForceNl();
+
+ /*
+ * Try converting both arguments to an integer.
+ */
+ prt_str("#ifdef LargeInts", 0);
+ ForceNl();
+ ld_prmloc(strt_prms);
+ tok_line(t, indent);
+ prt_str("else if (", indent);
+ cnv_fnc(t, TypEInt, n->u[0].child, NULL, NULL, indent);
+ prt_str(" && ", indent);
+ cnv_fnc(t, TypEInt, n->u[1].child, NULL, NULL, indent);
+ prt_str(") ", indent);
+ ForceNl();
+ if (rt_walk(n1->u[1].child, indent + IndentInc, 0)) {
+ fall_thru |= 1;
+ mrg_prmloc(end_prms);
+ }
+ ForceNl();
+ prt_str("#endif\t\t\t\t\t/* LargeInts */", 0);
+ ForceNl();
+
+ /*
+ * Try converting both arguments to a C_double
+ */
+ ld_prmloc(strt_prms);
+ prt_str("else {", indent);
+ ForceNl();
+ tok_line(t, indent + IndentInc);
+ prt_str("if (!", indent + IndentInc);
+ cnv_fnc(t, TypCDbl, n->u[0].child, NULL, NULL,
+ indent + IndentInc);
+ prt_str(")", indent + IndentInc);
+ ForceNl();
+ sv_prmloc(tmp_prms); /* use original parm locs for error */
+ ld_prmloc(strt_prms);
+ prt_runerr(t, errnum, n->u[0].child, indent + 2 * IndentInc);
+ ld_prmloc(tmp_prms);
+ tok_line(t, indent + IndentInc);
+ prt_str("if (!", indent + IndentInc);
+ cnv_fnc(t, TypCDbl, n->u[1].child, NULL, NULL,
+ indent + IndentInc);
+ prt_str(") ", indent + IndentInc);
+ ForceNl();
+ sv_prmloc(tmp_prms); /* use original parm locs for error */
+ ld_prmloc(strt_prms);
+ prt_runerr(t, errnum, n->u[1].child, indent + 2 * IndentInc);
+ ld_prmloc(tmp_prms);
+ if (rt_walk(n1->u[2].child, indent + IndentInc, 0)) {
+ fall_thru |= 1;
+ mrg_prmloc(end_prms);
+ }
+ ForceNl();
+ prt_str("}", indent + IndentInc);
+ ForceNl();
+
+ ld_prmloc(end_prms);
+ free(strt_prms);
+ free(end_prms);
+ free(tmp_prms);
+ free_tree(errnum);
+ return fall_thru;
+ }
+ }
+ case QuadNd:
+ /*
+ * RTL code: def: <type> ( <source> , <default>)
+ * def: <type> ( <source> , <default> , <destination> )
+ */
+ cnv_fnc(t, icn_typ(n->u[0].child), n->u[1].child, n->u[2].child,
+ n->u[3].child, indent);
+ return 1;
+ }
+ /*NOTREACHED*/
+ return 0; /* avoid gcc warning */
+ }
+
+/*
+ * spcl_dcls - print special declarations for tended variables, parameter
+ * conversions, and buffers.
+ */
+void spcl_dcls(op_params)
+struct sym_entry *op_params; /* operation parameters or NULL */
+ {
+ register struct sym_entry *sym;
+ struct sym_entry *sym1;
+
+ /*
+ * Output declarations for buffers and locations to hold conversions
+ * to C values.
+ */
+ spcl_start(op_params);
+
+ /*
+ * Determine if this operation takes a variable number of arguments.
+ * Use that information in deciding how large a tended array to
+ * declare.
+ */
+ varargs = (op_params != NULL && op_params->id_type & VarPrm);
+ if (varargs)
+ tend_ary(ntend + VArgAlwnc - 1);
+ else
+ tend_ary(ntend);
+
+ if (varargs) {
+ /*
+ * This operation takes a variable number of arguments. A declaration
+ * for a tended array has been made that will usually hold them, but
+ * sometimes it is necessary to malloc() a tended array at run
+ * time. Produce code to check for this.
+ */
+ cur_impl->ret_flag |= DoesEFail; /* error conversion from allocation */
+ prt_str("struct tend_desc *r_tendp;", IndentInc);
+ ForceNl();
+ prt_str("int r_n;\n", IndentInc);
+ ++line;
+ ForceNl();
+ prt_str("if (r_nargs <= ", IndentInc);
+ fprintf(out_file, "%d)", op_params->u.param_info.param_num + VArgAlwnc);
+ ForceNl();
+ prt_str("r_tendp = (struct tend_desc *)&r_tend;", 2 * IndentInc);
+ ForceNl();
+ prt_str("else {", IndentInc);
+ ForceNl();
+ prt_str(
+ "r_tendp = (struct tend_desc *)malloc((sizeof(struct tend_desc)",
+ 2 * IndentInc);
+ ForceNl();
+ prt_str("", 3 * IndentInc);
+ fprintf(out_file, "+ (r_nargs + %d) * sizeof(struct descrip)));",
+ ntend - 2 - op_params->u.param_info.param_num);
+ ForceNl();
+ prt_str("if (r_tendp == NULL) {", 2 * IndentInc);
+ ForceNl();
+ prt_str("err_msg(305, NULL);", 3 * IndentInc);
+ ForceNl();
+ prt_str("return A_Resume;", 3 * IndentInc);
+ ForceNl();
+ prt_str("}", 3 * IndentInc);
+ ForceNl();
+ prt_str("}", 2 * IndentInc);
+ ForceNl();
+ tendstrct = "(*r_tendp)";
+ }
+ else
+ tendstrct = "r_tend";
+
+ /*
+ * Produce code to initialize the tended array. These are for tended
+ * declarations and parameters.
+ */
+ tend_init(); /* initializations for tended declarations. */
+ if (varargs) {
+ /*
+ * This operation takes a variable number of arguments. Produce code
+ * to dereference or copy this into its portion of the tended
+ * array.
+ */
+ prt_str("for (r_n = ", IndentInc);
+ fprintf(out_file, "%d; r_n < r_nargs; ++r_n)",
+ op_params->u.param_info.param_num);
+ ForceNl();
+ if (op_params->id_type & DrfPrm) {
+ prt_str("deref(&r_args[r_n], &", IndentInc * 2);
+ fprintf(out_file, "%s.d[r_n + %d]);", tendstrct, ntend - 1 -
+ op_params->u.param_info.param_num);
+ }
+ else {
+ prt_str(tendstrct, IndentInc * 2);
+ fprintf(out_file, ".d[r_n + %d] = r_args[r_n];", ntend - 1 -
+ op_params->u.param_info.param_num);
+ }
+ ForceNl();
+ sym = op_params->u.param_info.next;
+ }
+ else
+ sym = op_params; /* no variable part of arg list */
+
+ /*
+ * Go through the fixed part of the parameter list, producing code
+ * to copy/dereference parameters into the tended array.
+ */
+ while (sym != NULL) {
+ /*
+ * A there may be identifiers for dereferenced and/or undereferenced
+ * versions of a paramater. If there are both, sym1 references the
+ * second identifier.
+ */
+ sym1 = sym->u.param_info.next;
+ if (sym1 != NULL && sym->u.param_info.param_num !=
+ sym1->u.param_info.param_num)
+ sym1 = NULL; /* the next entry is not for the same parameter */
+
+ /*
+ * If there are not enough arguments to supply a value for this
+ * parameter, set it to the null value.
+ */
+ prt_str("if (", IndentInc);
+ fprintf(out_file, "r_nargs > %d) {", sym->u.param_info.param_num);
+ ForceNl();
+ parm_tnd(sym);
+ if (sym1 != NULL) {
+ ForceNl();
+ parm_tnd(sym1);
+ }
+ ForceNl();
+ prt_str("} else {", IndentInc);
+ ForceNl();
+ prt_str(tendstrct, IndentInc * 2);
+ fprintf(out_file, ".d[%d].dword = D_Null;", sym->t_indx);
+ if (sym1 != NULL) {
+ ForceNl();
+ prt_str(tendstrct, IndentInc * 2);
+ fprintf(out_file, ".d[%d].dword = D_Null;", sym1->t_indx);
+ }
+ ForceNl();
+ prt_str("}", 2 * IndentInc);
+ ForceNl();
+ if (sym1 == NULL)
+ sym = sym->u.param_info.next;
+ else
+ sym = sym1->u.param_info.next;
+ }
+
+ /*
+ * Finish setting up the tended array structure and link it into the tended
+ * list.
+ */
+ if (ntend != 0) {
+ prt_str(tendstrct, IndentInc);
+ if (varargs)
+ fprintf(out_file, ".num = %d + Max(r_nargs - %d, 0);", ntend - 1,
+ op_params->u.param_info.param_num);
+ else
+ fprintf(out_file, ".num = %d;", ntend);
+ ForceNl();
+ prt_str(tendstrct, IndentInc);
+ prt_str(".previous = tend;", IndentInc);
+ ForceNl();
+ prt_str("tend = (struct tend_desc *)&", IndentInc);
+ fprintf(out_file, "%s;", tendstrct);
+ ForceNl();
+ }
+ }
+
+/*
+ * spcl_start - do initial work for outputing special declarations. Output
+ * declarations for buffers and locations to hold conversions to C values.
+ * Determine what tended locations are needed for parameters.
+ */
+static void spcl_start(op_params)
+struct sym_entry *op_params;
+ {
+ ForceNl();
+ if (n_tmp_str > 0) {
+ prt_str("char r_sbuf[", IndentInc);
+ fprintf(out_file, "%d][MaxCvtLen];", n_tmp_str);
+ ForceNl();
+ }
+ if (n_tmp_cset > 0) {
+ prt_str("struct b_cset r_cbuf[", IndentInc);
+ fprintf(out_file, "%d];", n_tmp_cset);
+ ForceNl();
+ }
+ if (tend_lst == NULL)
+ ntend = 0;
+ else
+ ntend = tend_lst->t_indx + 1;
+ parm_locs(op_params); /* see what parameter conversion there are */
+ }
+
+/*
+ * tend_ary - write struct containing array of tended descriptors.
+ */
+static void tend_ary(n)
+int n;
+ {
+ if (n == 0)
+ return;
+ prt_str("struct {", IndentInc);
+ ForceNl();
+ prt_str("struct tend_desc *previous;", 2 * IndentInc);
+ ForceNl();
+ prt_str("int num;", 2 * IndentInc);
+ ForceNl();
+ prt_str("struct descrip d[", 2 * IndentInc);
+ fprintf(out_file, "%d];", n);
+ ForceNl();
+ prt_str("} r_tend;\n", 2 * IndentInc);
+ ++line;
+ ForceNl();
+ }
+
+/*
+ * tend_init - produce code to initialize entries in the tended array
+ * corresponding to tended declarations. Default initializations are
+ * supplied when there is none in the declaration.
+ */
+static void tend_init()
+ {
+ register struct init_tend *tnd;
+
+ for (tnd = tend_lst; tnd != NULL; tnd = tnd->next) {
+ switch (tnd->init_typ) {
+ case TndDesc:
+ /*
+ * Simple tended declaration.
+ */
+ prt_str(tendstrct, IndentInc);
+ if (tnd->init == NULL)
+ fprintf(out_file, ".d[%d].dword = D_Null;", tnd->t_indx);
+ else {
+ fprintf(out_file, ".d[%d] = ", tnd->t_indx);
+ c_walk(tnd->init, 2 * IndentInc, 0);
+ prt_str(";", 2 * IndentInc);
+ }
+ break;
+ case TndStr:
+ /*
+ * Tended character pointer.
+ */
+ prt_str(tendstrct, IndentInc);
+ if (tnd->init == NULL)
+ fprintf(out_file, ".d[%d] = emptystr;", tnd->t_indx);
+ else {
+ fprintf(out_file, ".d[%d].dword = 0;", tnd->t_indx);
+ ForceNl();
+ prt_str(tendstrct, IndentInc);
+ fprintf(out_file, ".d[%d].vword.sptr = ", tnd->t_indx);
+ c_walk(tnd->init, 2 * IndentInc, 0);
+ prt_str(";", 2 * IndentInc);
+ }
+ break;
+ case TndBlk:
+ /*
+ * A tended block pointer of some kind.
+ */
+ prt_str(tendstrct, IndentInc);
+ if (tnd->init == NULL)
+ fprintf(out_file, ".d[%d] = nullptr;", tnd->t_indx);
+ else {
+ fprintf(out_file, ".d[%d].dword = F_Ptr | F_Nqual;",tnd->t_indx);
+ ForceNl();
+ prt_str(tendstrct, IndentInc);
+ fprintf(out_file, ".d[%d].vword.bptr = (union block *)",
+ tnd->t_indx);
+ c_walk(tnd->init, 2 * IndentInc, 0);
+ prt_str(";", 2 * IndentInc);
+ }
+ break;
+ }
+ ForceNl();
+ }
+ }
+
+/*
+ * parm_tnd - produce code to put a parameter in its tended location.
+ */
+static void parm_tnd(sym)
+struct sym_entry *sym;
+ {
+ /*
+ * A parameter may either be dereferenced into its tended location
+ * or copied.
+ */
+ if (sym->id_type & DrfPrm) {
+ prt_str("deref(&r_args[", IndentInc * 2);
+ fprintf(out_file, "%d], &%s.d[%d]);", sym->u.param_info.param_num,
+ tendstrct, sym->t_indx);
+ }
+ else {
+ prt_str(tendstrct, IndentInc * 2);
+ fprintf(out_file, ".d[%d] = r_args[%d];", sym->t_indx,
+ sym->u.param_info.param_num);
+ }
+ }
+
+/*
+ * parm_locs - determine what locations are needed to hold parameters and
+ * their conversions. Produce declarations for the C_integer and C_double
+ * locations.
+ */
+static void parm_locs(op_params)
+struct sym_entry *op_params;
+ {
+ struct sym_entry *next_parm;
+
+ /*
+ * Parameters are stored in reverse order: Recurse down the list
+ * and perform processing on the way back.
+ */
+ if (op_params == NULL)
+ return;
+ next_parm = op_params->u.param_info.next;
+ parm_locs(next_parm);
+
+ /*
+ * For interpreter routines, extra tended descriptors are only needed
+ * when both dereferenced and undereferenced values are requested.
+ */
+ if (iconx_flg && (next_parm == NULL ||
+ op_params->u.param_info.param_num != next_parm->u.param_info.param_num))
+ op_params->t_indx = -1;
+ else
+ op_params->t_indx = ntend++;
+ if (op_params->u.param_info.non_tend & PrmInt) {
+ prt_str("C_integer r_i", IndentInc);
+ fprintf(out_file, "%d;", op_params->u.param_info.param_num);
+ ForceNl();
+ }
+ if (op_params->u.param_info.non_tend & PrmDbl) {
+ prt_str("double r_d", IndentInc);
+ fprintf(out_file, "%d;", op_params->u.param_info.param_num);
+ ForceNl();
+ }
+ }
+
+/*
+ * real_def - see if a declaration really defines storage.
+ */
+static int real_def(n)
+struct node *n;
+ {
+ struct node *dcl_lst;
+
+ dcl_lst = n->u[1].child;
+ /*
+ * If no variables are being defined this must be a tag declaration.
+ */
+ if (dcl_lst == NULL)
+ return 0;
+
+ if (only_proto(dcl_lst))
+ return 0;
+
+ if (tdef_or_extr(n->u[0].child))
+ return 0;
+
+ return 1;
+ }
+
+/*
+ * only_proto - see if this declarator list contains only function prototypes.
+ */
+static int only_proto(n)
+struct node *n;
+ {
+ switch (n->nd_id) {
+ case CommaNd:
+ return only_proto(n->u[0].child) & only_proto(n->u[1].child);
+ case ConCatNd:
+ /*
+ * Optional pointer.
+ */
+ return only_proto(n->u[1].child);
+ case BinryNd:
+ switch (n->tok->tok_id) {
+ case '=':
+ return only_proto(n->u[0].child);
+ case '[':
+ /*
+ * At this point, assume array declarator is not part of
+ * prototype.
+ */
+ return 0;
+ case ')':
+ /*
+ * Prototype (or forward declaration).
+ */
+ return 1;
+ }
+ case PrefxNd:
+ /*
+ * Parenthesized.
+ */
+ return only_proto(n->u[0].child);
+ case PrimryNd:
+ /*
+ * At this point, assume it is not a prototype.
+ */
+ return 0;
+ }
+ err1("rtt internal error detected in function only_proto()");
+ /*NOTREACHED*/
+ return 0; /* avoid gcc warning */
+ }
+
+/*
+ * tdef_or_extr - see if this is a typedef or extern.
+ */
+static int tdef_or_extr(n)
+struct node *n;
+ {
+ switch (n->nd_id) {
+ case LstNd:
+ return tdef_or_extr(n->u[0].child) | tdef_or_extr(n->u[1].child);
+ case BinryNd:
+ /*
+ * struct, union, or enum.
+ */
+ return 0;
+ case PrimryNd:
+ if (n->tok->tok_id == Extern || n->tok->tok_id == Typedef)
+ return 1;
+ else
+ return 0;
+ }
+ err1("rtt internal error detected in function tdef_or_extr()");
+ /*NOTREACHED*/
+ return 0; /* avoid gcc warning */
+ }
+
+/*
+ * dclout - output an ordinary global C declaration.
+ */
+void dclout(n)
+struct node *n;
+ {
+ if (!enable_out)
+ return; /* output disabled */
+ if (real_def(n))
+ def_fnd = 1; /* this declaration defines a run-time object */
+ c_walk(n, 0, 0);
+ free_tree(n);
+ }
+
+/*
+ * fncout - output code for a C function.
+ */
+void fncout(head, prm_dcl, block)
+struct node *head;
+struct node *prm_dcl;
+struct node *block;
+ {
+ if (!enable_out)
+ return; /* output disabled */
+
+ def_fnd = 1; /* this declaration defines a run-time object */
+
+ nxt_sbuf = 0; /* clear number of string buffers */
+ nxt_cbuf = 0; /* clear number of cset buffers */
+
+ /*
+ * Output the function header and the parameter declarations.
+ */
+ fnc_head = head;
+ c_walk(head, 0, 0);
+ prt_str(" ", 0);
+ c_walk(prm_dcl, 0, 0);
+ prt_str(" ", 0);
+
+ /*
+ * Handle outer block.
+ */
+ prt_tok(block->tok, IndentInc); /* { */
+ c_walk(block->u[0].child, IndentInc, 0); /* non-tended declarations */
+ spcl_dcls(NULL); /* tended declarations */
+ no_ret_val = 1;
+ c_walk(block->u[2].child, IndentInc, 0); /* statement list */
+ if (ntend != 0 && no_ret_val) {
+ /*
+ * This function contains no return statements with values, assume
+ * that the programmer is using the implicit return at the end
+ * of the function and update the tending of descriptors.
+ */
+ untend(IndentInc);
+ }
+ ForceNl();
+ prt_str("}", IndentInc);
+ ForceNl();
+
+ /*
+ * free storage.
+ */
+ free_tree(head);
+ free_tree(prm_dcl);
+ free_tree(block);
+ pop_cntxt();
+ clr_def();
+ }
+
+/*
+ * defout - output operation definitions (except for constant keywords)
+ */
+void defout(n)
+struct node *n;
+ {
+ struct sym_entry *sym, *sym1;
+
+ if (!enable_out)
+ return; /* output disabled */
+
+ nxt_sbuf = 0;
+ nxt_cbuf = 0;
+
+ /*
+ * Somewhat different code is produced for the interpreter and compiler.
+ */
+ if (iconx_flg)
+ interp_def(n);
+ else
+ comp_def(n);
+
+ free_tree(n);
+ /*
+ * The declarations for the declare statement are not associated with
+ * any compound statement and must be freed here.
+ */
+ sym = dcl_stk->tended;
+ while (sym != NULL) {
+ sym1 = sym;
+ sym = sym->u.tnd_var.next;
+ free_sym(sym1);
+ }
+ while (decl_lst != NULL) {
+ sym1 = decl_lst;
+ decl_lst = decl_lst->u.declare_var.next;
+ free_sym(sym1);
+ }
+ op_type = OrdFunc;
+ pop_cntxt();
+ clr_def();
+ }
+
+/*
+ * comp_def - output code for the compiler for operation definitions.
+ */
+static void comp_def(n)
+struct node *n;
+ {
+ #ifdef Rttx
+ fprintf(stdout,
+ "rtt was compiled to only support the interpreter, use -x\n");
+ exit(EXIT_FAILURE);
+ #else /* Rttx */
+ struct sym_entry *sym;
+ struct node *n1;
+ FILE *f_save;
+
+ char buf1[5];
+ char buf[MaxPath];
+ char *cname;
+ long min_result;
+ long max_result;
+ int ret_flag;
+ int resume;
+ char *name;
+ char *s;
+
+ f_save = out_file;
+
+ /*
+ * Note if the result location is explicitly referenced and note
+ * how it is accessed in the generated code.
+ */
+ cur_impl->use_rslt = sym_lkup(str_rslt)->u.referenced;
+ rslt_loc = "(*r_rslt)";
+
+ /*
+ * In several contexts, letters are used to distinguish kinds of operations.
+ */
+ switch (op_type) {
+ case TokFunction:
+ lc_letter = 'f';
+ uc_letter = 'F';
+ break;
+ case Keyword:
+ lc_letter = 'k';
+ uc_letter = 'K';
+ break;
+ case Operator:
+ lc_letter = 'o';
+ uc_letter = 'O';
+ }
+ prfx1 = cur_impl->prefix[0];
+ prfx2 = cur_impl->prefix[1];
+
+ if (op_type != Keyword) {
+ /*
+ * First pass through the operation: produce most general routine.
+ */
+ fnc_ret = RetSig; /* most general routine always returns a signal */
+
+ /*
+ * Compute the file name in which to output the function.
+ */
+ sprintf(buf1, "%c_%c%c", lc_letter, prfx1, prfx2);
+ cname = salloc(makename(buf, SourceDir, buf1, CSuffix));
+ if ((out_file = fopen(cname, "w")) == NULL)
+ err2("cannot open output file", cname);
+ else
+ addrmlst(cname, out_file);
+
+ prologue(); /* output standard comments and preprocessor directives */
+
+ /*
+ * Output function header that corresponds to standard calling
+ * convensions. The function name is constructed from the letter
+ * for the operation type, the prefix that makes the function
+ * name unique, and the name of the operation.
+ */
+ fprintf(out_file, "int %c%c%c_%s(r_nargs, r_args, r_rslt, r_s_cont)\n",
+ uc_letter, prfx1, prfx2, cur_impl->name);
+ fprintf(out_file, "int r_nargs;\n");
+ fprintf(out_file, "dptr r_args;\n");
+ fprintf(out_file, "dptr r_rslt;\n");
+ fprintf(out_file, "continuation r_s_cont;");
+ fname = cname;
+ line = 12;
+ ForceNl();
+ prt_str("{", IndentInc);
+ ForceNl();
+
+ /*
+ * Output ordinary declarations from declare clause.
+ */
+ for (sym = decl_lst; sym != NULL; sym = sym->u.declare_var.next) {
+ c_walk(sym->u.declare_var.tqual, IndentInc, 0);
+ prt_str(" ", IndentInc);
+ c_walk(sym->u.declare_var.dcltor, IndentInc, 0);
+ if ((n1 = sym->u.declare_var.init) != NULL) {
+ prt_str(" = ", IndentInc);
+ c_walk(n1, IndentInc, 0);
+ }
+ prt_str(";", IndentInc);
+ }
+
+ /*
+ * Output code for special declarations along with code to initial
+ * them. This includes buffers and tended locations for parameters
+ * and tended variables.
+ */
+ spcl_dcls(params);
+
+ if (rt_walk(n, IndentInc, 0)) { /* body of operation */
+ if (n->nd_id == ConCatNd)
+ s = n->u[1].child->tok->fname;
+ else
+ s = n->tok->fname;
+ fprintf(stderr, "%s: file %s, warning: ", progname, s);
+ fprintf(stderr, "execution may fall off end of operation \"%s\"\n",
+ cur_impl->name);
+ }
+
+ ForceNl();
+ prt_str("}\n", IndentInc);
+ if (fclose(out_file) != 0)
+ err2("cannot close ", cname);
+ put_c_fl(cname, 1); /* note name of output file for operation */
+ }
+
+ /*
+ * Second pass through operation: produce in-line code and special purpose
+ * routines.
+ */
+ for (sym = params; sym != NULL; sym = sym->u.param_info.next)
+ if (sym->id_type & DrfPrm)
+ sym->u.param_info.cur_loc = PrmTend; /* reset location of parameter */
+ in_line(n);
+
+ /*
+ * Insure that the fail/return/suspend statements are consistent
+ * with the result sequence indicated.
+ */
+ min_result = cur_impl->min_result;
+ max_result = cur_impl->max_result;
+ ret_flag = cur_impl->ret_flag;
+ resume = cur_impl->resume;
+ name = cur_impl->name;
+ if (min_result == NoRsltSeq && ret_flag & (DoesFail|DoesRet|DoesSusp))
+ err2(name,
+ ": result sequence of {}, but fail, return, or suspend present");
+ if (min_result != NoRsltSeq && ret_flag == 0)
+ err2(name,
+ ": result sequence indicated, no fail, return, or suspend present");
+ if (max_result != NoRsltSeq) {
+ if (max_result == 0 && ret_flag & (DoesRet|DoesSusp))
+ err2(name,
+ ": result sequence of 0 length, but return or suspend present");
+ if (max_result != 0 && !(ret_flag & (DoesRet | DoesSusp)))
+ err2(name,
+ ": result sequence length > 0, but no return or suspend present");
+ if ((max_result == UnbndSeq || max_result > 1 || resume) &&
+ !(ret_flag & DoesSusp))
+ err2(name,
+ ": result sequence indicates suspension, but no suspend present");
+ if ((max_result != UnbndSeq && max_result <= 1 && !resume) &&
+ ret_flag & DoesSusp)
+ err2(name,
+ ": result sequence indicates no suspension, but suspend present");
+ }
+ if (min_result != NoRsltSeq && max_result != UnbndSeq &&
+ min_result > max_result)
+ err2(name, ": minimum result sequence length greater than maximum");
+
+ out_file = f_save;
+#endif /* Rttx */
+ }
+
+/*
+ * interp_def - output code for the interpreter for operation definitions.
+ */
+static void interp_def(n)
+struct node *n;
+ {
+ struct sym_entry *sym;
+ struct node *n1;
+ int nparms;
+ int has_underef;
+ char letter;
+ char *name;
+ char *s;
+
+ /*
+ * Note how result location is accessed in generated code.
+ */
+ rslt_loc = "r_args[0]";
+
+ /*
+ * Determine if the operation has any undereferenced parameters.
+ */
+ has_underef = 0;
+ for (sym = params; sym != NULL; sym = sym->u.param_info.next)
+ if (sym->id_type & RtParm) {
+ has_underef = 1;
+ break;
+ }
+
+ /*
+ * Determine the nuber of parameters. A negative value is used
+ * to indicate an operation that takes a variable number of
+ * arguments.
+ */
+ if (params == NULL)
+ nparms = 0;
+ else {
+ nparms = params->u.param_info.param_num + 1;
+ if (params->id_type & VarPrm)
+ nparms = -nparms;
+ }
+
+ fnc_ret = RetSig; /* interpreter routine always returns a signal */
+ name = cur_impl->name;
+
+ /*
+ * Determine what letter is used to prefix the operation name.
+ */
+ switch (op_type) {
+ case TokFunction:
+ letter = 'Z';
+ break;
+ case Keyword:
+ letter = 'K';
+ break;
+ case Operator:
+ letter = 'O';
+ }
+
+ fprintf(out_file, "\n");
+ if (op_type != Keyword) {
+ /*
+ * Output prototype. Operations taking a variable number of arguments
+ * have an extra parameter: the number of arguments.
+ */
+ fprintf(out_file, "int %c%s (", letter, name);
+ if (params != NULL && (params->id_type & VarPrm))
+ fprintf(out_file, "int r_nargs, ");
+ fprintf(out_file, "dptr r_args);\n");
+ ++line;
+
+ /*
+ * Output procedure block.
+ */
+ switch (op_type) {
+ case TokFunction:
+ fprintf(out_file, "FncBlock(%s, %d, %d)\n\n", name, nparms,
+ (has_underef ? -1 : 0));
+ ++line;
+ break;
+ case Operator:
+ if (strcmp(cur_impl->op,"\\") == 0)
+ fprintf(out_file, "OpBlock(%s, %d, \"%s\", 0)\n\n", name, nparms,
+ "\\\\");
+ else
+ fprintf(out_file, "OpBlock(%s, %d, \"%s\", 0)\n\n", name, nparms,
+ cur_impl->op);
+ ++line;
+ }
+ }
+
+ /*
+ * Output function header. Operations taking a variable number of arguments
+ * have an extra parameter: the number of arguments.
+ */
+ fprintf(out_file, "int %c%s(", letter, name);
+ if (params != NULL && (params->id_type & VarPrm))
+ fprintf(out_file, "r_nargs, ");
+ fprintf(out_file, "r_args)\n");
+ ++line;
+ if (params != NULL && (params->id_type & VarPrm)) {
+ fprintf(out_file, "int r_nargs;\n");
+ ++line;
+ }
+ fprintf(out_file, "dptr r_args;");
+ ++line;
+ ForceNl();
+ prt_str("{", IndentInc);
+
+ /*
+ * Output ordinary declarations from the declare clause.
+ */
+ ForceNl();
+ for (sym = decl_lst; sym != NULL; sym = sym->u.declare_var.next) {
+ c_walk(sym->u.declare_var.tqual, IndentInc, 0);
+ prt_str(" ", IndentInc);
+ c_walk(sym->u.declare_var.dcltor, IndentInc, 0);
+ if ((n1 = sym->u.declare_var.init) != NULL) {
+ prt_str(" = ", IndentInc);
+ c_walk(n1, IndentInc, 0);
+ }
+ prt_str(";", IndentInc);
+ }
+
+ /*
+ * Output special declarations and initial processing.
+ */
+ tendstrct = "r_tend";
+ spcl_start(params);
+ tend_ary(ntend);
+ if (has_underef && params != NULL && params->id_type == (VarPrm | DrfPrm))
+ prt_str("int r_n;\n", IndentInc);
+ tend_init();
+
+ /*
+ * See which parameters need to be dereferenced. If all are dereferenced,
+ * it is done by before the routine is called.
+ */
+ if (has_underef) {
+ sym = params;
+ if (sym != NULL && sym->id_type & VarPrm) {
+ if (sym->id_type & DrfPrm) {
+ /*
+ * There is a variable part of the parameter list and it
+ * must be dereferenced.
+ */
+ prt_str("for (r_n = ", IndentInc);
+ fprintf(out_file, "%d; r_n <= r_nargs; ++r_n)",
+ sym->u.param_info.param_num + 1);
+ ForceNl();
+ prt_str("Deref(r_args[r_n]);", IndentInc * 2);
+ ForceNl();
+ }
+ sym = sym->u.param_info.next;
+ }
+
+ /*
+ * Produce code to dereference any fixed parameters that need to be.
+ */
+ while (sym != NULL) {
+ if (sym->id_type & DrfPrm) {
+ /*
+ * Tended index of -1 indicates that the parameter can be
+ * dereferened in-place (this is the usual case).
+ */
+ if (sym->t_indx == -1) {
+ prt_str("Deref(r_args[", IndentInc * 2);
+ fprintf(out_file, "%d]);", sym->u.param_info.param_num + 1);
+ }
+ else {
+ prt_str("deref(&r_args[", IndentInc * 2);
+ fprintf(out_file, "%d], &r_tend.d[%d]);",
+ sym->u.param_info.param_num + 1, sym->t_indx);
+ }
+ }
+ ForceNl();
+ sym = sym->u.param_info.next;
+ }
+ }
+
+ /*
+ * Finish setting up the tended array structure and link it into the tended
+ * list.
+ */
+ if (ntend != 0) {
+ prt_str("r_tend.num = ", IndentInc);
+ fprintf(out_file, "%d;", ntend);
+ ForceNl();
+ prt_str("r_tend.previous = tend;", IndentInc);
+ ForceNl();
+ prt_str("tend = (struct tend_desc *)&r_tend;", IndentInc);
+ ForceNl();
+ }
+
+ if (rt_walk(n, IndentInc, 0)) { /* body of operation */
+ if (n->nd_id == ConCatNd)
+ s = n->u[1].child->tok->fname;
+ else
+ s = n->tok->fname;
+ fprintf(stderr, "%s: file %s, warning: ", progname, s);
+ fprintf(stderr, "execution may fall off end of operation \"%s\"\n",
+ cur_impl->name);
+ }
+ ForceNl();
+ prt_str("}\n", IndentInc);
+ }
+
+/*
+ * keyconst - produce code for a constant keyword.
+ */
+void keyconst(t)
+struct token *t;
+ {
+ struct il_code *il;
+ int n;
+
+ if (iconx_flg) {
+ /*
+ * For the interpreter, output a C function implementing the keyword.
+ */
+ rslt_loc = "r_args[0]"; /* result location */
+
+ fprintf(out_file, "\n");
+ fprintf(out_file, "int K%s(r_args)\n", cur_impl->name);
+ fprintf(out_file, "dptr r_args;");
+ line += 2;
+ ForceNl();
+ prt_str("{", IndentInc);
+ ForceNl();
+ switch (t->tok_id) {
+ case StrLit:
+ prt_str(rslt_loc, IndentInc);
+ prt_str(".vword.sptr = \"", IndentInc);
+ n = prt_i_str(out_file, t->image, (int)strlen(t->image));
+ prt_str("\";", IndentInc);
+ ForceNl();
+ prt_str(rslt_loc, IndentInc);
+ fprintf(out_file, ".dword = %d;", n);
+ break;
+ case CharConst:
+ prt_str("static struct b_cset cset_blk = ", IndentInc);
+ cset_init(out_file, bitvect(t->image, (int)strlen(t->image)));
+ ForceNl();
+ prt_str(rslt_loc, IndentInc);
+ prt_str(".dword = D_Cset;", IndentInc);
+ ForceNl();
+ prt_str(rslt_loc, IndentInc);
+ prt_str(".vword.bptr = (union block *)&cset_blk;", IndentInc);
+ break;
+ case DblConst:
+ prt_str("static struct b_real real_blk = {T_Real, ", IndentInc);
+ fprintf(out_file, "%s};", t->image);
+ ForceNl();
+ prt_str(rslt_loc, IndentInc);
+ prt_str(".dword = D_Real;", IndentInc);
+ ForceNl();
+ prt_str(rslt_loc, IndentInc);
+ prt_str(".vword.bptr = (union block *)&real_blk;", IndentInc);
+ break;
+ case IntConst:
+ prt_str(rslt_loc, IndentInc);
+ prt_str(".dword = D_Integer;", IndentInc);
+ ForceNl();
+ prt_str(rslt_loc, IndentInc);
+ prt_str(".vword.integr = ", IndentInc);
+ prt_str(t->image, IndentInc);
+ prt_str(";", IndentInc);
+ break;
+ }
+ ForceNl();
+ prt_str("return A_Continue;", IndentInc);
+ ForceNl();
+ prt_str("}\n", IndentInc);
+ ++line;
+ ForceNl();
+ }
+ else {
+ /*
+ * For the compiler, make an entry in the data base for the keyword.
+ */
+ cur_impl->use_rslt = 0;
+
+ il = new_il(IL_Const, 2);
+ switch (t->tok_id) {
+ case StrLit:
+ il->u[0].n = str_typ;
+ il->u[1].s = alloc(strlen(t->image) + 3);
+ sprintf(il->u[1].s, "\"%s\"", t->image);
+ break;
+ case CharConst:
+ il->u[0].n = cset_typ;
+ il->u[1].s = alloc(strlen(t->image) + 3);
+ sprintf(il->u[1].s, "'%s'", t->image);
+ break;
+ case DblConst:
+ il->u[0].n = real_typ;
+ il->u[1].s = t->image;
+ break;
+ case IntConst:
+ il->u[0].n = int_typ;
+ il->u[1].s = t->image;
+ break;
+ }
+ cur_impl->in_line = il;
+ }
+
+ /*
+ * Reset the translator and free storage.
+ */
+ op_type = OrdFunc;
+ free_t(t);
+ pop_cntxt();
+ clr_def();
+ }
+
+/*
+ * keepdir - A preprocessor directive to be kept has been encountered.
+ * If it is #passthru, print just the body of the directive, otherwise
+ * print the whole thing.
+ */
+void keepdir(t)
+struct token *t;
+ {
+ char *s;
+
+ tok_line(t, 0);
+ s = t->image;
+ if (strncmp(s, "#passthru", 9) == 0)
+ s = s + 10;
+ fprintf(out_file, "%s\n", s);
+ line += 1;
+ }
+
+/*
+ * prologue - print standard comments and preprocessor directives at the
+ * start of an output file.
+ */
+void prologue()
+ {
+ id_comment(out_file);
+ fprintf(out_file, "%s", compiler_def);
+ fprintf(out_file, "#include \"%s\"\n\n", inclname);
+ }