summaryrefslogtreecommitdiff
path: root/src/rtt/rttilc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rtt/rttilc.c')
-rw-r--r--src/rtt/rttilc.c1402
1 files changed, 1402 insertions, 0 deletions
diff --git a/src/rtt/rttilc.c b/src/rtt/rttilc.c
new file mode 100644
index 0000000..70839ef
--- /dev/null
+++ b/src/rtt/rttilc.c
@@ -0,0 +1,1402 @@
+/*
+ * rttilc.c - routines to construct pieces of C code to put in the data base
+ * as in-line code.
+ *
+ * In-line C code is represented internally as a linked list of structures.
+ * The information contained in each structure depends on the type of code
+ * being represented. Some structures contain other fragments of C code.
+ * Code that does not require special processing is stored as strings. These
+ * strings are accumulated in a buffer until it is full or code that cannot
+ * be represented as a string must be produced. At that point, the string
+ * in placed in a structure and put on the list.
+ */
+#include "rtt.h"
+
+#ifndef Rttx
+
+/*
+ * prototypes for static functions.
+ */
+static void add_ptr (struct node *dcltor);
+static void alloc_ilc (int il_c_type);
+static void flush_str (void);
+static void ilc_chnl (struct token *t);
+static void ilc_cnv (struct node *cnv_typ, struct node *src,
+ struct node *dflt, struct node *dest);
+static void ilc_cgoto (int neg, struct node *cond, word lbl);
+static void ilc_goto (word lbl);
+static void ilc_lbl (word lbl);
+static void ilc_ret (struct token *t, int ilc_typ, struct node *n);
+static void ilc_str (char *s);
+static void ilc_tok (struct token *t);
+static void ilc_var (struct sym_entry *sym, int just_desc, int may_mod);
+static void ilc_walk (struct node *n, int may_mod, int const_cast);
+static void init_ilc (void);
+static void insrt_str (void);
+static void new_ilc (int il_c_type);
+static struct il_c *sep_ilc (char *s1,struct node *n,char *s2);
+
+#define SBufSz 256
+
+static char sbuf[SBufSz]; /* buffer for constructing fragments of code */
+static int nxt_char; /* next position in sbuf */
+static struct token *line_ref; /* "recent" token for comparing line number */
+static struct il_c ilc_base; /* base for list of in-line C code */
+static struct il_c *ilc_cur; /* current end of list of in-line C code */
+static int insert_nl; /* flag: new-line should be inserted in code */
+static word cont_lbl = 0; /* destination label for C continue statement */
+static word brk_lbl = 0; /* destination label for C break statement */
+
+/*
+ * inlin_c - Create a self-contained piece of in-line C code from a syntax
+ * sub-tree.
+ */
+struct il_c *inlin_c(n, may_mod)
+struct node *n;
+int may_mod;
+ {
+ init_ilc(); /* initialize code list and string buffer */
+ ilc_walk(n, may_mod, 0); /* translate the syntax sub-tree */
+ flush_str(); /* flush string buffer to code list */
+ return ilc_base.next;
+ }
+
+/*
+ * simpl_dcl - produce a simple declaration both in the output file and as
+ * in-line C code.
+ */
+struct il_c *simpl_dcl(tqual, addr_of, sym)
+char *tqual;
+int addr_of;
+struct sym_entry *sym;
+ {
+ init_ilc(); /* initialize code list and string buffer */
+ prt_str(tqual, 0);
+ ilc_str(tqual);
+ if (addr_of) {
+ prt_str("*", 0);
+ ilc_str("*");
+ }
+ prt_str(sym->image, 0);
+ ilc_str(sym->image);
+ prt_str(";", 0);
+ ForceNl();
+ flush_str(); /* flush string buffer to code list */
+ return ilc_base.next;
+ }
+
+/*
+ * parm_dcl - produce the declaration for a parameter to a body function.
+ * Print it in the output file and proceduce in-line C code for it.
+ */
+struct il_c *parm_dcl(addr_of, sym)
+int addr_of;
+struct sym_entry *sym;
+ {
+ init_ilc(); /* initialize code list and string buffer */
+
+ /*
+ * Produce type-qualifier list, but without non-type information.
+ */
+ just_type(sym->u.declare_var.tqual, 0, 1);
+ prt_str(" ", 0);
+ ilc_str(" ");
+
+ /*
+ * If the caller requested another level of indirection on the
+ * declaration add it.
+ */
+ if (addr_of)
+ add_ptr(sym->u.declare_var.dcltor);
+ else {
+ c_walk(sym->u.declare_var.dcltor, 0, 0);
+ ilc_walk(sym->u.declare_var.dcltor, 0, 0);
+ }
+ prt_str(";", 0);
+ ForceNl();
+ flush_str(); /* flush string buffer to code list */
+ return ilc_base.next;
+ }
+
+/*
+ * add_ptr - add another level of indirection to a declarator. Print it in
+ * the output file and proceduce in-line C code.
+ */
+static void add_ptr(dcltor)
+struct node *dcltor;
+ {
+ while (dcltor->nd_id == ConCatNd) {
+ c_walk(dcltor->u[0].child, IndentInc, 0);
+ ilc_walk(dcltor->u[0].child, 0, 0);
+ dcltor = dcltor->u[1].child;
+ }
+ switch (dcltor->nd_id) {
+ case PrimryNd:
+ /*
+ * We have reached the name, add a level of indirection.
+ */
+ prt_str("(*", IndentInc);
+ ilc_str("(*");
+ prt_str(dcltor->tok->image, IndentInc);
+ ilc_str(dcltor->tok->image);
+ prt_str(")", IndentInc);
+ ilc_str(")");
+ break;
+ case PrefxNd:
+ /*
+ * (...)
+ */
+ prt_str("(", IndentInc);
+ ilc_str("(");
+ add_ptr(dcltor->u[0].child);
+ prt_str(")", IndentInc);
+ ilc_str(")");
+ break;
+ case BinryNd:
+ if (dcltor->tok->tok_id == ')') {
+ /*
+ * Function declaration.
+ */
+ add_ptr(dcltor->u[0].child);
+ prt_str("(", IndentInc);
+ ilc_str("(");
+ c_walk(dcltor->u[1].child, IndentInc, 0);
+ ilc_walk(dcltor->u[1].child, 0, 0);
+ prt_str(")", IndentInc);
+ ilc_str(")");
+ }
+ else {
+ /*
+ * Array.
+ */
+ add_ptr(dcltor->u[0].child);
+ prt_str("[", IndentInc);
+ ilc_str("[");
+ c_walk(dcltor->u[1].child, IndentInc, 0);
+ ilc_walk(dcltor->u[1].child, 0, 0);
+ prt_str("]", IndentInc);
+ ilc_str("]");
+ }
+ }
+ }
+
+/*
+ * bdy_prm - produce the code that must be be supplied as the argument
+ * to the call of a body function.
+ */
+struct il_c *bdy_prm(addr_of, just_desc, sym, may_mod)
+int addr_of;
+int just_desc;
+struct sym_entry *sym;
+int may_mod;
+ {
+ init_ilc(); /* initialize code list and string buffer */
+ if (addr_of)
+ ilc_str("&("); /* call-by-reference parameter */
+ ilc_var(sym, just_desc, may_mod); /* variable to pass as argument */
+ if (addr_of)
+ ilc_str(")");
+ flush_str(); /* flush string buffer to code list */
+ return ilc_base.next;
+ }
+
+/*
+ * ilc_dcl - produce in-line code for a C declaration.
+ */
+struct il_c *ilc_dcl(tqual, dcltor, init)
+struct node *tqual;
+struct node *dcltor;
+struct node *init;
+ {
+ init_ilc(); /* initialize code list and string buffer */
+ ilc_walk(tqual, 0, 0);
+ ilc_str(" ");
+ ilc_walk(dcltor, 0, 0);
+ if (init != NULL) {
+ ilc_str(" = ");
+ ilc_walk(init, 0, 0);
+ }
+ ilc_str(";");
+ flush_str(); /* flush string buffer to code list */
+ return ilc_base.next;
+ }
+
+
+/*
+ * init_ilc - initialize the code list by pointing to ilc_base. Initialize
+ * the string buffer.
+ */
+static void init_ilc()
+ {
+ nxt_char = 0;
+ line_ref = NULL;
+ insert_nl = 0;
+ ilc_base.il_c_type = 0;
+ ilc_base.next = NULL;
+ ilc_cur = &ilc_base;
+ }
+
+
+/*
+ * - ilc_chnl - check for new-line.
+ */
+static void ilc_chnl(t)
+struct token *t;
+ {
+ /*
+ * See if this is a reasonable place to put a newline.
+ */
+ if (t->flag & LineChk) {
+ if (line_ref != NULL &&
+ (t->fname != line_ref->fname || t->line != line_ref->line))
+ insert_nl = 1;
+ line_ref = t;
+ }
+ }
+
+/*
+ * ilc_tok - convert a token to its string representation, quoting it
+ * if it is a string or character literal.
+ */
+static void ilc_tok(t)
+struct token *t;
+ {
+ char *s;
+
+ ilc_chnl(t);
+ s = t->image;
+ switch (t->tok_id) {
+ case StrLit:
+ ilc_str("\"");
+ ilc_str(s);
+ ilc_str("\"");
+ break;
+ case LStrLit:
+ ilc_str("L\"");
+ ilc_str(s);
+ ilc_str("\"");
+ break;
+ case CharConst:
+ ilc_str("'");
+ ilc_str(s);
+ ilc_str("'");
+ break;
+ case LCharConst:
+ ilc_str("L'");
+ ilc_str(s);
+ ilc_str("'");
+ break;
+ default:
+ ilc_str(s);
+ }
+ }
+
+/*
+ * ilc_str - append a string to the string buffer.
+ */
+static void ilc_str(s)
+char *s;
+ {
+ /*
+ * see if a new-line is needed before the string
+ */
+ if (insert_nl && (nxt_char == 0 || sbuf[nxt_char - 1] != '\n')) {
+ insert_nl = 0;
+ ilc_str("\n");
+ }
+
+ /*
+ * Put the string in the buffer. If the buffer is full, flush it
+ * to an element in the in-line code list.
+ */
+ while (*s != '\0') {
+ if (nxt_char >= SBufSz - 1)
+ insrt_str();
+ sbuf[nxt_char++] = *s++;
+ }
+ }
+
+/*
+ * insrt_str - insert the string in the buffer into the list of in-line
+ * code.
+ */
+static void insrt_str()
+ {
+ alloc_ilc(ILC_Str);
+ sbuf[nxt_char] = '\0';
+ ilc_cur->s = salloc(sbuf);
+ nxt_char = 0;
+ }
+
+/*
+ * flush_str - if the string buffer is not empty, flush it to the list
+ * of in-line code.
+ */
+static void flush_str()
+ {
+ if (insert_nl)
+ ilc_str("");
+ if (nxt_char != 0)
+ insrt_str();
+ }
+
+/*
+ * new_ilc - create a new element for the list of in-line C code. This
+ * is called for non-string elements. If necessary it flushes the
+ * string buffer to another element first.
+ */
+static void new_ilc(il_c_type)
+int il_c_type;
+ {
+ flush_str();
+ alloc_ilc(il_c_type);
+ }
+
+/*
+ * alloc_ilc - allocate a new element for the list of in-line C code
+ * and add it to the list.
+ */
+static void alloc_ilc(il_c_type)
+int il_c_type;
+ {
+ int i;
+ ilc_cur->next = NewStruct(il_c);
+ ilc_cur = ilc_cur->next;
+ ilc_cur->next = NULL;
+ ilc_cur->il_c_type = il_c_type;
+ for (i = 0; i < 3; ++i)
+ ilc_cur->code[i] = NULL;
+ ilc_cur->n = 0;
+ ilc_cur->s = NULL;
+ }
+
+/*
+ * sep_ilc - translate the syntax tree, n, (possibly surrounding it by
+ * strings) into a sub-list of in-line C code, remove the sub-list from
+ * the main list, and return it.
+ */
+static struct il_c *sep_ilc(s1, n, s2)
+char *s1;
+struct node *n;
+char *s2;
+ {
+ struct il_c *ilc;
+
+ ilc = ilc_cur; /* remember the starting point in the main list */
+ if (s1 != NULL)
+ ilc_str(s1);
+ ilc_walk(n, 0, 0);
+ if (s2 != NULL)
+ ilc_str(s2);
+ flush_str();
+
+ /*
+ * Reset the main list to its condition upon entry, and return the sublist
+ * created from s1, n, and s2.
+ */
+ ilc_cur = ilc;
+ ilc = ilc_cur->next;
+ ilc_cur->next = NULL;
+ return ilc;
+ }
+
+/*
+ * ilc_var - create in-line C code for a variable in the symbol table.
+ */
+static void ilc_var(sym, just_desc, may_mod)
+struct sym_entry *sym;
+int just_desc;
+int may_mod;
+ {
+ if (sym->il_indx >= 0) {
+ /*
+ * This symbol will be in symbol table iconc builds from the
+ * data base entry. iconc needs to know if this is a modifying
+ * reference so it can perform optimizations. This is indicated by
+ * may_mod. Some variables are implemented as the vword of a
+ * descriptor. Sometime the entire descriptor must be accessed.
+ * This is indicated by just_desc.
+ */
+ if (may_mod) {
+ new_ilc(ILC_Mod);
+ if (sym->id_type & DrfPrm)
+ sym->u.param_info.parm_mod |= 1;
+ }
+ else
+ new_ilc(ILC_Ref);
+ ilc_cur->n = sym->il_indx;
+ if (just_desc)
+ ilc_cur->s = "d";
+ }
+ else switch (sym->id_type) {
+ case TndDesc:
+ /*
+ * variable declared: tended struct descrip ...
+ */
+ new_ilc(ILC_Tend);
+ ilc_cur->n = sym->t_indx; /* index into tended variables */
+ break;
+ case TndStr:
+ /*
+ * variable declared: tended char *...
+ */
+ new_ilc(ILC_Tend);
+ ilc_cur->n = sym->t_indx; /* index into tended variables */
+ ilc_str(".vword.sptr"); /* get string pointer from vword union */
+ break;
+ case TndBlk:
+ /*
+ * If blk_name field is null, this variable was declared:
+ * tended union block *...
+ * otherwise it was declared:
+ * tended struct <blk_name> *...
+ */
+ if (sym->u.tnd_var.blk_name != NULL) {
+ /*
+ * Cast the "union block *" from the vword to the correct
+ * struct pointer. This cast can be used as an r-value or
+ * an l-value.
+ */
+ ilc_str("(*(struct ");
+ ilc_str(sym->u.tnd_var.blk_name);
+ ilc_str("**)&");
+ }
+ new_ilc(ILC_Tend);
+ ilc_cur->n = sym->t_indx; /* index into tended variables */
+ ilc_str(".vword.bptr"); /* get block pointer from vword union */
+ if (sym->u.tnd_var.blk_name != NULL)
+ ilc_str(")");
+ break;
+ case RsltLoc:
+ /*
+ * This is the special variable for the result of the operation.
+ * iconc needs to know if this is a modifying reference so it
+ * can perform optimizations.
+ */
+ if (may_mod)
+ new_ilc(ILC_Mod);
+ else
+ new_ilc(ILC_Ref);
+ ilc_cur->n = RsltIndx;
+ break;
+ default:
+ /*
+ * This is a variable with an ordinary declaration. Access it by
+ * its identifier.
+ */
+ ilc_str(sym->image);
+ }
+ }
+
+/*
+ * ilc_walk - walk the syntax tree for C code producing a list of "in-line"
+ * code. This function needs to know if the code is in a modifying context,
+ * such as the left-hand-side of an assignment.
+ */
+static void ilc_walk(n, may_mod, const_cast)
+struct node *n;
+int may_mod;
+int const_cast;
+ {
+ struct token *t;
+ struct node *n1;
+ struct node *n2;
+ struct sym_entry *sym;
+ word cont_sav;
+ word brk_sav;
+ word l1, l2;
+ int typcd;
+
+ if (n == NULL)
+ return;
+
+ t = n->tok;
+
+ switch (n->nd_id) {
+ case PrimryNd:
+ /*
+ * Primary expressions consisting of a single token.
+ */
+ switch (t->tok_id) {
+ case Fail:
+ /*
+ * fail statement. Note that this operaion can fail, output
+ * the corresponding "in-line" code, and make sure we have
+ * seen an abstract clause of some kind.
+ */
+ cur_impl->ret_flag |= DoesFail;
+ insert_nl = 1;
+ new_ilc(ILC_Fail);
+ insert_nl = 1;
+ line_ref = NULL;
+ chkabsret(t, SomeType);
+ break;
+ case Errorfail:
+ /*
+ * errorfail statement. Note that this operaion can do error
+ * conversion and output the corresponding "in-line" code.
+ */
+ cur_impl->ret_flag |= DoesEFail;
+ insert_nl = 1;
+ new_ilc(ILC_EFail);
+ insert_nl = 1;
+ line_ref = NULL;
+ break;
+ case Break:
+ /*
+ * iconc can only handle gotos for transfer of control in
+ * in-line code. A break label has been established for
+ * the current loop; transform the "break" into a goto.
+ */
+ ilc_goto(brk_lbl);
+ break;
+ case Continue:
+ /*
+ * iconc can only handle gotos for transfer of control in
+ * in-line code. A continue label has been established for
+ * the current loop; transform the "continue" into a goto.
+ */
+ ilc_goto(cont_lbl);
+ break;
+ default:
+ /*
+ * No special processing is needed for this primary
+ * expression, just output the image of the token.
+ */
+ ilc_tok(t);
+ }
+ break;
+ case PrefxNd:
+ /*
+ * Expressions with one operand that are introduced by a token.
+ * Note, "default :" does not appear here because switch
+ * statements are not allowed in in-line code.
+ */
+ switch (t->tok_id) {
+ case Sizeof:
+ /*
+ * sizeof(...)
+ */
+ ilc_tok(t);
+ ilc_str("(");
+ ilc_walk(n->u[0].child, 0, 0);
+ ilc_str(")");
+ break;
+ case '{':
+ /*
+ * initializer: { ... }
+ */
+ ilc_tok(t);
+ ilc_walk(n->u[0].child, 0, 0);
+ ilc_str("}");
+ break;
+ case Goto:
+ /*
+ * goto <label>;
+ */
+ ilc_goto(n->u[0].child->u[0].sym->u.lbl_num);
+ break;
+ case Return:
+ /*
+ * return <expression>;
+ * Indicate that this operation can return, then perform
+ * processing to categorize the kind of return statement
+ * and produce appropriate in-line code.
+ */
+ cur_impl->ret_flag |= DoesRet;
+ ilc_ret(t, ILC_Ret, n->u[0].child);
+ break;
+ case Suspend:
+ /*
+ * suspend <expression>;
+ * Indicate that this operation can suspend, then perform
+ * processing to categorize the kind of suspend statement
+ * and produce appropriate in-line code.
+ */
+ cur_impl->ret_flag |= DoesSusp;
+ ilc_ret(t, ILC_Susp, n->u[0].child);
+ break;
+ case '(':
+ /*
+ * ( ... )
+ */
+ ilc_tok(t);
+ ilc_walk(n->u[0].child, may_mod, const_cast);
+ ilc_str(")");
+ break;
+ case Incr:
+ case Decr:
+ /*
+ * The operand might be modified, otherwise nothing special
+ * is needed.
+ */
+ ilc_tok(t);
+ ilc_walk(n->u[0].child, 1, 0);
+ break;
+ case '&':
+ /*
+ * Unless the address is cast to a const pointer, this
+ * might be a modifiying reference.
+ */
+ ilc_tok(t);
+ if (const_cast)
+ ilc_walk(n->u[0].child, 0, 0);
+ else
+ ilc_walk(n->u[0].child, 1, 0);
+ break;
+ default:
+ /*
+ * Nothing special is needed, just output the image of
+ * the prefix operation followed by its operand.
+ */
+ ilc_tok(t);
+ ilc_walk(n->u[0].child, 0, 0);
+ }
+ break;
+ case PstfxNd:
+ /*
+ * postfix notation: ';', '++', and '--'. The later two
+ * modify their operands.
+ */
+ if (t->tok_id == ';')
+ ilc_walk(n->u[0].child, 0, 0);
+ else
+ ilc_walk(n->u[0].child, 1, 0);
+ ilc_tok(t);
+ break;
+ case PreSpcNd:
+ /*
+ * Prefix notation that needs a space after the expression;
+ * used for pointer/type qualifier lists.
+ */
+ ilc_tok(t);
+ ilc_walk(n->u[0].child, 0, 0);
+ ilc_str(" ");
+ break;
+ case SymNd:
+ /*
+ * Identifier in symbol table. See if it start a new line. Note
+ * that we need to know whether this is a modifying reference.
+ */
+ ilc_chnl(n->tok);
+ ilc_var(n->u[0].sym, 0, may_mod);
+ break;
+ case BinryNd:
+ switch (t->tok_id) {
+ case '[':
+ /*
+ * Expression or declaration:
+ * <expr1> [ <expr2> ]
+ */
+ ilc_walk(n->u[0].child, may_mod, 0);
+ ilc_str("[");
+ ilc_walk(n->u[1].child, 0, 0);
+ ilc_str("]");
+ break;
+ case '(':
+ /*
+ * ( <type> ) expr
+ */
+ ilc_tok(t);
+ ilc_walk(n->u[0].child, 0, 0);
+ ilc_str(")");
+ /*
+ * See if the is a const cast.
+ */
+ for (n1 = n->u[0].child; n1->nd_id == LstNd; n1 = n1->u[0].child)
+ ;
+ if (n1->nd_id == PrimryNd && n1->tok->tok_id == Const)
+ ilc_walk(n->u[1].child, 0, 1);
+ else
+ ilc_walk(n->u[1].child, 0, 0);
+ break;
+ case ')':
+ /*
+ * Expression or declaration:
+ * <expr> ( <arg-list> )
+ */
+ ilc_walk(n->u[0].child, 0, 0);
+ ilc_str("(");
+ ilc_walk(n->u[1].child, 0, 0);
+ ilc_tok(t);
+ break;
+ case Struct:
+ case Union:
+ case TokEnum:
+ /*
+ * <struct-union-enum> <identifier>
+ * <struct-union-enum> { <component-list> }
+ * <struct-union-enum> <identifier> { <component-list> }
+ */
+ ilc_tok(t);
+ ilc_str(" ");
+ ilc_walk(n->u[0].child, 0, 0);
+ if (n->u[1].child != NULL) {
+ ilc_str(" {");
+ ilc_walk(n->u[1].child, 0, 0);
+ ilc_str("}");
+ }
+ break;
+ case ';':
+ /*
+ * <type specifiers> <declarator> ;
+ */
+ ilc_walk(n->u[0].child, 0, 0);
+ ilc_str(" ");
+ ilc_walk(n->u[1].child, 0, 0);
+ ilc_tok(t);
+ break;
+ case ':':
+ /*
+ * <label> : <statement>
+ */
+ ilc_lbl(n->u[0].child->u[0].sym->u.lbl_num);
+ ilc_walk(n->u[1].child, 0, 0);
+ break;
+ case Switch:
+ errt1(t, "switch statement not supported in in-line code");
+ break;
+ case While:
+ /*
+ * Convert "while (c) s" into [conditional] gotos and labels.
+ * Establish labels for break and continue statements
+ * within s.
+ */
+ brk_sav = brk_lbl;
+ cont_sav = cont_lbl;
+ cont_lbl = lbl_num++;
+ brk_lbl = lbl_num++;
+ ilc_lbl(cont_lbl); /* L1: */
+ ilc_cgoto(1, n->u[0].child, brk_lbl); /* if (!(c)) goto L2; */
+ ilc_walk(n->u[1].child, 0, 0); /* s */
+ ilc_goto(cont_lbl); /* goto L1; */
+ ilc_lbl(brk_lbl); /* L2: */
+ brk_lbl = brk_sav;
+ cont_lbl = cont_sav;
+ break;
+ case Do:
+ /*
+ * Convert "do s while (c);" loop into a conditional goto and
+ * label. Establish labels for break and continue statements
+ * within s.
+ */
+ brk_sav = brk_lbl;
+ cont_sav = cont_lbl;
+ cont_lbl = lbl_num++;
+ brk_lbl = lbl_num++;
+ ilc_lbl(cont_lbl); /* L1: */
+ ilc_walk(n->u[0].child, 0, 0); /* s */
+ ilc_cgoto(0, n->u[1].child, cont_lbl); /* if (c) goto L1 */
+ ilc_lbl(brk_lbl);
+ brk_lbl = brk_sav;
+ cont_lbl = cont_sav;
+ break;
+ case '.':
+ /*
+ * <expr1> . <expr2>
+ */
+ ilc_walk(n->u[0].child, may_mod, 0);
+ ilc_tok(t);
+ ilc_walk(n->u[1].child, 0, 0);
+ break;
+ case Arrow:
+ /*
+ * <expr1> -> <expr2>
+ */
+ ilc_walk(n->u[0].child, 0, 0);
+ ilc_tok(t);
+ ilc_walk(n->u[1].child, 0, 0);
+ break;
+ case Runerr:
+ /*
+ * runerr ( <expr> ) ;
+ * runerr ( <expr> , <expr> ) ;
+ */
+ ilc_str("err_msg(");
+ ilc_walk(n->u[0].child, 0, 0);
+ if (n->u[1].child == NULL)
+ ilc_str(", NULL);");
+ else {
+ ilc_str(", &(");
+ ilc_walk(n->u[1].child, 0, 0);
+ ilc_str("));");
+ }
+ /*
+ * Handle error conversion.
+ */
+ cur_impl->ret_flag |= DoesEFail;
+ insert_nl = 1;
+ new_ilc(ILC_EFail);
+ insert_nl = 1;
+ break;
+ case Is:
+ /*
+ * is : <type-name> ( <expr> )
+ */
+ typcd = icn_typ(n->u[0].child);
+ n1 = n->u[1].child;
+ if (typcd == str_typ) {
+ ilc_str("(!((");
+ ilc_walk(n1, 0, 0);
+ ilc_str(").dword & F_Nqual))");
+ }
+ else if (typcd == Variable) {
+ ilc_str("(((");
+ ilc_walk(n1, 0, 0);
+ ilc_str(").dword & D_Var) == D_Var)");
+ }
+ else if (typcd == int_typ) {
+ ForceNl();
+ prt_str("#ifdef LargeInts", 0);
+ ForceNl();
+
+ ilc_str("(((");
+ ilc_walk(n1, 0, 0);
+ ilc_str(").dword == D_Integer) || ((");
+ ilc_walk(n1, 0, 0);
+ ilc_str(").dword == D_Lrgint))");
+
+ ForceNl();
+ prt_str("#else /* LargeInts */", 0);
+ ForceNl();
+
+ ilc_str("((");
+ ilc_walk(n1, 0, 0);
+ ilc_str(").dword == D_Integer)");
+
+ ForceNl();
+ prt_str("#endif /* LargeInts */", 0);
+ ForceNl();
+ }
+ else {
+ ilc_str("((");
+ ilc_walk(n1, 0, 0);
+ ilc_str(").dword == D_");
+ ilc_str(typ_name(typcd, n->u[0].child->tok));
+ ilc_str(")");
+ }
+ break;
+ case '=':
+ case MultAsgn:
+ case DivAsgn:
+ case ModAsgn:
+ case PlusAsgn:
+ case MinusAsgn:
+ case LShftAsgn:
+ case RShftAsgn:
+ case AndAsgn:
+ case XorAsgn:
+ case OrAsgn:
+ /*
+ * Assignment operation (or initialization or specification
+ * of enumeration value). Left-hand-side may be modified.
+ */
+ ilc_walk(n->u[0].child, 1, 0);
+ ilc_str(" ");
+ ilc_tok(t);
+ ilc_str(" ");
+ ilc_walk(n->u[1].child, 0, 0);
+ break;
+ default:
+ /*
+ * Simple binary operator. Nothing special is needed,
+ * just put space around the operator.
+ */
+ ilc_walk(n->u[0].child, 0, 0);
+ ilc_str(" ");
+ ilc_tok(t);
+ ilc_str(" ");
+ ilc_walk(n->u[1].child, 0, 0);
+ break;
+ }
+ break;
+ case LstNd:
+ /*
+ * Consecutive expressions that need a space between them.
+ */
+ ilc_walk(n->u[0].child, 0, 0);
+ ilc_str(" ");
+ ilc_walk(n->u[1].child, 0, 0);
+ break;
+ case ConCatNd:
+ /*
+ * Consecutive expressions that don't need space between them.
+ */
+ ilc_walk(n->u[0].child, 0, 0);
+ ilc_walk(n->u[1].child, 0, 0);
+ break;
+ case CommaNd:
+ ilc_walk(n->u[0].child, 0, 0);
+ ilc_tok(t);
+ ilc_str(" ");
+ ilc_walk(n->u[1].child, 0, 0);
+ break;
+ case StrDclNd:
+ /*
+ * struct field declarator. May be a bit field.
+ */
+ ilc_walk(n->u[0].child, 0, 0);
+ if (n->u[1].child != NULL) {
+ ilc_str(": ");
+ ilc_walk(n->u[1].child, 0, 0);
+ }
+ break;
+ case CompNd: {
+ /*
+ * Compound statement. May have declarations including tended
+ * declarations that are separated out.
+ */
+ struct node *dcls;
+
+ /*
+ * If the in-line code has declarations, the block must
+ * be surrounded by braces. Braces are special constructs
+ * because iconc must not delete one without the other
+ * during code optimization.
+ */
+ dcls = n->u[0].child;
+ if (dcls != NULL) {
+ insert_nl = 1;
+ new_ilc(ILC_LBrc);
+ insert_nl = 1;
+ line_ref = NULL;
+ ilc_walk(dcls, 0, 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) {
+ new_ilc(ILC_Tend);
+ ilc_cur->n = sym->t_indx;
+
+ /*
+ * See if the variable is just the vword of the descriptor.
+ */
+ switch (sym->id_type) {
+ case TndDesc:
+ ilc_str(" = ");
+ break;
+ case TndStr:
+ ilc_str(".vword.sptr = ");
+ break;
+ case TndBlk:
+ ilc_str(".vword.bptr = (union block *)");
+ break;
+ }
+ ilc_walk(sym->u.tnd_var.init, 0, 0); /* initial value */
+ ilc_str(";");
+ }
+ }
+
+ ilc_walk(n->u[2].child, 0, 0); /* body of compound statement */
+
+ if (dcls != NULL) {
+ insert_nl = 1;
+ new_ilc(ILC_RBrc); /* closing brace */
+ insert_nl = 1;
+ line_ref = NULL;
+ }
+ }
+ break;
+ case TrnryNd:
+ switch (t->tok_id) {
+ case '?':
+ /*
+ * <expr> ? <expr> : <expr>
+ */
+ ilc_walk(n->u[0].child, 0, 0);
+ ilc_str(" ");
+ ilc_tok(t);
+ ilc_str(" ");
+ ilc_walk(n->u[1].child, 0, 0);
+ ilc_str(" : ");
+ ilc_walk(n->u[2].child, 0, 0);
+ break;
+ case If:
+ /*
+ * Convert if statement into [conditional] gotos and labels.
+ */
+ n1 = n->u[1].child;
+ n2 = n->u[2].child;
+ l1 = lbl_num++;
+ if (n2 == NULL) { /* if (c) then s */
+ ilc_cgoto(1, n->u[0].child, l1); /* if (!(c)) goto L1; */
+ ilc_walk(n1, 0, 0); /* s */
+ ilc_lbl(l1); /* L1: */
+ }
+ else { /* if (c) then s1 else s2 */
+ ilc_cgoto(0, n->u[0].child, l1); /* if (c) goto L1; */
+ ilc_walk(n2, 0, 0); /* s2 */
+ l2 = lbl_num++;
+ ilc_goto(l2); /* goto L2; */
+ ilc_lbl(l1); /* L1: */
+ ilc_walk(n1, 0, 0); /* s1 */
+ ilc_lbl(l2); /* L2: */
+ }
+ break;
+ case Type_case:
+ errt1(t, "type case statement not supported in in-line code");
+ break;
+ case Cnv:
+ /*
+ * cnv : <type> ( <expr> , <expr> )
+ */
+ ilc_cnv(n->u[0].child, n->u[1].child, NULL, n->u[2].child);
+ break;
+ }
+ break;
+ case QuadNd:
+ switch (t->tok_id) {
+ case For:
+ /*
+ * convert "for (e1; e2; e3) s" into [conditional] gotos and
+ * labels.
+ */
+ brk_sav = brk_lbl;
+ cont_sav = cont_lbl;
+ l1 = lbl_num++;
+ cont_lbl = lbl_num++;
+ brk_lbl = lbl_num++;
+ ilc_walk(n->u[0].child, 0, 0); /* e1; */
+ ilc_str(";");
+ ilc_lbl(l1); /* L1: */
+ n2 = n->u[1].child;
+ if (n2 != NULL)
+ ilc_cgoto(1, n2, brk_lbl); /* if (!(e2)) goto L2; */
+ ilc_walk(n->u[3].child, 0, 0); /* s */
+ ilc_lbl(cont_lbl);
+ ilc_walk(n->u[2].child, 0, 0); /* e3; */
+ ilc_str(";");
+ ilc_goto(l1); /* goto L1 */
+ ilc_lbl(brk_lbl); /* L2: */
+ brk_lbl = brk_sav;
+ cont_lbl = cont_sav;
+ break;
+ case Def:
+ ilc_cnv(n->u[0].child, n->u[1].child, n->u[2].child,
+ n->u[3].child);
+ break;
+ }
+ break;
+ }
+ }
+
+/*
+ * ilc_cnv - produce code for a cnv: or def: statement.
+ */
+static void ilc_cnv(cnv_typ, src, dflt, dest)
+struct node *cnv_typ;
+struct node *src;
+struct node *dflt;
+struct node *dest;
+ {
+ int dflt_to_ptr;
+ int typcd;
+
+ /*
+ * Get the name of the conversion routine for the given type
+ * and determine whether the conversion routine needs a
+ * pointer to the default value (if there is one) rather
+ * the the value itself.
+ */
+ typcd = icn_typ(cnv_typ);
+ ilc_str(cnv_name(typcd, dflt, &dflt_to_ptr));
+ ilc_str("(");
+
+ /*
+ * If this is a conversion to a temporary string or cset, the
+ * conversion routine needs a temporary buffer in which to
+ * perform the conversion.
+ */
+ switch (typcd) {
+ case TypTStr:
+ new_ilc(ILC_SBuf);
+ ilc_str(", ");
+ break;
+ case TypTCset:
+ new_ilc(ILC_CBuf);
+ ilc_str(", ");
+ break;
+ }
+
+ /*
+ * Produce code for the source expression.
+ */
+ ilc_str("&(");
+ ilc_walk(src, 0, 0);
+ ilc_str("), ");
+
+ /*
+ * Produce code for the default expression, if there is one.
+ */
+ if (dflt != NULL) {
+ if (dflt_to_ptr)
+ ilc_str("&(");
+ ilc_walk(dflt, 0, 0);
+ if (dflt_to_ptr)
+ ilc_str("), ");
+ else
+ ilc_str(", ");
+ }
+
+ /*
+ * Produce code for the destination expression.
+ */
+ ilc_str("&(");
+ ilc_walk(dest, 1, 0);
+ ilc_str("))");
+ }
+
+/*
+ * ilc_ret - produce in-line code for suspend/return statement.
+ */
+static void ilc_ret(t, ilc_typ, n)
+struct token *t;
+int ilc_typ;
+struct node *n;
+ {
+ struct node *caller;
+ struct node *args;
+ int typcd;
+
+ insert_nl = 1;
+ line_ref = NULL;
+ new_ilc(ilc_typ);
+
+ if (n->nd_id == SymNd && n->u[0].sym->id_type == RsltLoc) {
+ /*
+ * return/suspend result;
+ */
+ ilc_cur->n = RetNone;
+ return;
+ }
+
+ if (n->nd_id == PrefxNd && n->tok != NULL) {
+ switch (n->tok->tok_id) {
+ case C_Integer:
+ /*
+ * return/suspend C_integer <expr>;
+ */
+ ilc_cur->n = TypCInt;
+ ilc_cur->code[0] = sep_ilc(NULL, n->u[0].child, NULL);
+ chkabsret(t, int_typ);
+ return;
+ case C_Double:
+ /*
+ * return/suspend C_double <expr>;
+ */
+ ilc_cur->n = TypCDbl;
+ ilc_cur->code[0] = sep_ilc(NULL, n->u[0].child, NULL);
+ chkabsret(t, real_typ);
+ return;
+ case C_String:
+ /*
+ * return/suspend C_string <expr>;
+ */
+ ilc_cur->n = TypCStr;
+ ilc_cur->code[0] = sep_ilc(NULL, n->u[0].child, NULL);
+ chkabsret(t, str_typ);
+ 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;
+ ilc_cur->n = typcd;
+ switch (icontypes[typcd].rtl_ret) {
+ case TRetBlkP:
+ case TRetDescP:
+ case TRetCharP:
+ case TRetCInt:
+ /*
+ * return/suspend <type>(<value>);
+ */
+ ilc_cur->code[0] = sep_ilc(NULL, args, NULL);
+ break;
+ case TRetSpcl:
+ if (typcd == str_typ) {
+ /*
+ * return/suspend string(<len>, <char-pntr>);
+ */
+ ilc_cur->code[0] = sep_ilc(NULL, args->u[0].child,NULL);
+ ilc_cur->code[1] = sep_ilc(NULL, args->u[1].child,NULL);
+ }
+ else if (typcd == stv_typ) {
+ /*
+ * return/suspend tvsubs(<desc-pntr>, <start>, <len>);
+ */
+ ilc_cur->n = stv_typ;
+ ilc_cur->code[0] = sep_ilc(NULL,
+ args->u[0].child->u[0].child, NULL);
+ ilc_cur->code[1] = sep_ilc(NULL,
+ args->u[0].child->u[1].child, NULL);
+ ilc_cur->code[2] = sep_ilc(NULL, args->u[1].child,
+ NULL);
+ chkabsret(t, stv_typ);
+ }
+ break;
+ }
+ chkabsret(t, typcd);
+ return;
+ case Named_var:
+ /*
+ * return/suspend named_var(<desc-pntr>);
+ */
+ ilc_cur->n = RetNVar;
+ ilc_cur->code[0] = sep_ilc(NULL, args, NULL);
+ chkabsret(t, TypVar);
+ return;
+ case Struct_var:
+ /*
+ * return/suspend struct_var(<desc-pntr>, <block_pntr>);
+ */
+ ilc_cur->n = RetSVar;
+ ilc_cur->code[0] = sep_ilc(NULL, args->u[0].child, NULL);
+ ilc_cur->code[1] = sep_ilc(NULL, args->u[1].child, NULL);
+ chkabsret(t, TypVar);
+ return;
+ }
+ }
+ }
+
+ /*
+ * If it is not one of the special returns, it is just a return of
+ * a descriptor.
+ */
+ ilc_cur->n = RetDesc;
+ ilc_cur->code[0] = sep_ilc(NULL, n, NULL);
+ chkabsret(t, SomeType);
+ }
+
+/*
+ * ilc_goto - produce in-line C code for a goto to a numbered label.
+ */
+static void ilc_goto(lbl)
+word lbl;
+ {
+ insert_nl = 1;
+ new_ilc(ILC_Goto);
+ ilc_cur->n = lbl;
+ insert_nl = 1;
+ line_ref = NULL;
+ }
+
+/*
+ * ilc_cgoto - produce in-line C code for a conditional goto to a numbered
+ * label. The condition may be negated.
+ */
+static void ilc_cgoto(neg, cond, lbl)
+int neg;
+struct node *cond;
+word lbl;
+ {
+ insert_nl = 1;
+ line_ref = NULL;
+ new_ilc(ILC_CGto);
+ if (neg)
+ ilc_cur->code[0] = sep_ilc("!(", cond, ")");
+ else
+ ilc_cur->code[0] = sep_ilc(NULL, cond, NULL);
+ ilc_cur->n = lbl;
+ insert_nl = 1;
+ line_ref = NULL;
+ }
+
+/*
+ * ilc_lbl - produce in-line C code for a numbered label.
+ */
+static void ilc_lbl(lbl)
+word lbl;
+ {
+ insert_nl = 1;
+ new_ilc(ILC_Lbl);
+ ilc_cur->n = lbl;
+ insert_nl = 1;
+ line_ref = NULL;
+ }
+#endif /* Rttx */
+
+/*
+ * chkabsret - make sure a previous abstract return statement
+ * was encountered and that it is consistent with this return,
+ * suspend, or fail.
+ */
+void chkabsret(tok, ret_typ)
+struct token *tok;
+int ret_typ;
+ {
+ if (abs_ret == NoAbstr)
+ errt2(tok, tok->image, " with no preceding abstract return");
+
+ /*
+ * We only check for type consistency when it is easy, otherwise
+ * we don't bother.
+ */
+ if (abs_ret == SomeType || ret_typ == SomeType || abs_ret == TypAny)
+ return;
+
+ /*
+ * Some return types match the generic "variable" type.
+ */
+ if (abs_ret == TypVar && ret_typ >= 0 && icontypes[ret_typ].deref != DrfNone)
+ return;
+
+ /*
+ * Otherwise the abstract return must match the real one.
+ */
+ if (abs_ret != ret_typ)
+ errt2(tok, tok->image, " is inconsistent with abstract return");
+ }
+
+/*
+ * just_type - strip non-type information from a type-qualifier list. Print
+ * it in the output file and if ilc is set, produce in-line C code.
+ */
+void just_type(typ, indent, ilc)
+struct node *typ;
+int indent;
+int ilc;
+ {
+ if (typ->nd_id == LstNd) {
+ /*
+ * Simple list of type-qualifier elements - concatenate them.
+ */
+ just_type(typ->u[0].child, indent, ilc);
+ just_type(typ->u[1].child, indent, ilc);
+ }
+ else if (typ->nd_id == PrimryNd) {
+ switch (typ->tok->tok_id) {
+ case Typedef:
+ case Extern:
+ case Static:
+ case Auto:
+ case TokRegister:
+ case Const:
+ case Volatile:
+ return; /* Don't output these declaration elements */
+ default:
+ c_walk(typ, indent, 0);
+ #ifndef Rttx
+ if (ilc)
+ ilc_walk(typ, 0, 0);
+ #endif /* Rttx */
+ }
+ }
+ else {
+ c_walk(typ, indent, 0);
+ #ifndef Rttx
+ if (ilc)
+ ilc_walk(typ, 0, 0);
+ #endif /* Rttx */
+ }
+ }