#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 ; */ 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 ; */ 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 ; */ 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 (); */ ret_1_arg(t, args, typcd, ".vword.bptr = (union block *)", "(bp)", indent); break; case TRetDescP: /* * return/suspend (); */ ret_1_arg(t, args, typcd, ".vword.descptr = (dptr)", "(dp)", indent); break; case TRetCharP: /* * return/suspend (); */ ret_1_arg(t, args, typcd, ".vword.sptr = (char *)", "(s)", indent); break; case TRetCInt: /* * return/suspend (); */ ret_1_arg(t, args, typcd, ".vword.integr = (word)", "(i)", indent); break; case TRetSpcl: if (typcd == str_typ) { /* * return/suspend string(, ); */ 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(, , ); */ 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(); */ 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(, ); */ 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: [ ] */ 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: ( ) */ 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: ( ) */ 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 * struct/union { } */ 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 * enum { } */ 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 ';': /* * ; */ 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 ':': /* *