diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2013-01-27 23:51:56 +0000 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2013-01-27 23:51:56 +0000 |
commit | 6ab0c0f5bf14ed9c15370407b9ee7e0b4b089ae1 (patch) | |
tree | 926065cf45450116098db664e3c61dced9e1f21a /src/rtt | |
download | icon-6ab0c0f5bf14ed9c15370407b9ee7e0b4b089ae1.tar.gz |
Initial upstream version 9.4.3upstream/9.4.3
Diffstat (limited to 'src/rtt')
-rw-r--r-- | src/rtt/Makefile | 87 | ||||
-rw-r--r-- | src/rtt/ltoken.h | 117 | ||||
-rw-r--r-- | src/rtt/rtt.h | 2 | ||||
-rw-r--r-- | src/rtt/rtt1.h | 187 | ||||
-rw-r--r-- | src/rtt/rttdb.c | 1440 | ||||
-rw-r--r-- | src/rtt/rttgram.y | 1101 | ||||
-rw-r--r-- | src/rtt/rttilc.c | 1402 | ||||
-rw-r--r-- | src/rtt/rttinlin.c | 1950 | ||||
-rw-r--r-- | src/rtt/rttlex.c | 356 | ||||
-rw-r--r-- | src/rtt/rttmain.c | 402 | ||||
-rw-r--r-- | src/rtt/rttmisc.c | 114 | ||||
-rw-r--r-- | src/rtt/rttnode.c | 264 | ||||
-rw-r--r-- | src/rtt/rttout.c | 3821 | ||||
-rw-r--r-- | src/rtt/rttparse.c | 2992 | ||||
-rw-r--r-- | src/rtt/rttproto.h | 92 | ||||
-rw-r--r-- | src/rtt/rttsym.c | 722 |
16 files changed, 15049 insertions, 0 deletions
diff --git a/src/rtt/Makefile b/src/rtt/Makefile new file mode 100644 index 0000000..db6445e --- /dev/null +++ b/src/rtt/Makefile @@ -0,0 +1,87 @@ +# Makefile for the Icon run-time translator, rtt, +# which is used to build the Icon run-time system. + +include ../../Makedefs + + +ROBJS = rttparse.o rttmain.o rttlex.o rttsym.o rttnode.o rttout.o rttmisc.o\ + rttdb.o rttinlin.o rttilc.o + +PP_DIR = ../preproc/ +P_DOT_H = $(PP_DIR)preproc.h $(PP_DIR)pproto.h ltoken.h ../h/mproto.h\ + ../h/define.h ../h/config.h ../h/typedefs.h\ + ../h/cstructs.h ../h/cpuconf.h +POBJS = pout.o pchars.o perr.o pmem.o bldtok.o macro.o preproc.o\ + evaluate.o files.o gettok.o pinit.o + +COBJS = ../common/getopt.o ../common/time.o ../common/filepart.o \ + ../common/identify.o ../common/strtbl.o ../common/alloc.o \ + ../common/rtdb.o ../common/munix.o ../common/literals.o + +OBJ = $(ROBJS) $(POBJS) $(COBJS) + + +rtt: $(OBJ) + $(CC) $(LDFLAGS) -o rtt $(OBJ) + cp rtt ../../bin + strip ../../bin/rtt$(EXE) + +library: $(OBJ) + rm -rf rtt.a + ar qc rtt.a $(OBJ) + +$(COBJS): + cd ../common; $(MAKE) + +$(ROBJS): rtt.h rtt1.h rttproto.h $(P_DOT_H) + +rttdb.o: ../h/version.h +rttparse.o : ../h/gsupport.h ../h/config.h ../h/cstructs.h \ + ../h/mproto.h ../h/typedefs.h ../h/cpuconf.h ../h/define.h + +pout.o: $(PP_DIR)pout.c $(P_DOT_H) + $(CC) -c $(CFLAGS) $(PP_DIR)pout.c + +pchars.o: $(PP_DIR)pchars.c $(P_DOT_H) + $(CC) -c $(CFLAGS) $(PP_DIR)pchars.c + +perr.o: $(PP_DIR)perr.c $(P_DOT_H) + $(CC) -c $(CFLAGS) $(PP_DIR)perr.c + +pmem.o: $(PP_DIR)pmem.c $(P_DOT_H) + $(CC) -c $(CFLAGS) $(PP_DIR)pmem.c + +bldtok.o: $(PP_DIR)bldtok.c $(P_DOT_H) + $(CC) -c $(CFLAGS) $(PP_DIR)bldtok.c + +macro.o: $(PP_DIR)macro.c $(P_DOT_H) + $(CC) -c $(CFLAGS) $(PP_DIR)macro.c + +preproc.o: $(PP_DIR)preproc.c $(P_DOT_H) + $(CC) -c $(CFLAGS) $(PP_DIR)preproc.c + +evaluate.o: $(PP_DIR)evaluate.c $(P_DOT_H) + $(CC) -c $(CFLAGS) $(PP_DIR)evaluate.c + +files.o: $(PP_DIR)files.c $(P_DOT_H) + $(CC) -c $(CFLAGS) $(PP_DIR)files.c + +gettok.o: $(PP_DIR)gettok.c $(P_DOT_H) + $(CC) -c $(CFLAGS) $(PP_DIR)gettok.c + +pinit.o: $(PP_DIR)pinit.c $(P_DOT_H) + $(CC) -c $(CFLAGS) $(PP_DIR)pinit.c + +# +# The following entry is commented out because it is not normally +# necessary to recreate rttparse.c and ltoken.h unless the grammar +# in rttgram.y for the run-time langauge is changed. Recreating these +# files is not normally a part of the installation process. Note that +# on some systems, yacc may not have large enough internal tables to +# translate this grammar. +# +#rttparse.c ltoken.h: rttgram.y +# yacc -d rttgram.y +# fgrep -v -x "extern char *malloc(), *realloc();" y.tab.c > rttparse.c +# rm y.tab.c +# mv y.tab.h ltoken.h diff --git a/src/rtt/ltoken.h b/src/rtt/ltoken.h new file mode 100644 index 0000000..d426fcf --- /dev/null +++ b/src/rtt/ltoken.h @@ -0,0 +1,117 @@ + +typedef union { + struct token *t; + struct node *n; + long i; + } YYSTYPE; +extern YYSTYPE yylval; +# define Identifier 257 +# define StrLit 258 +# define LStrLit 259 +# define FltConst 260 +# define DblConst 261 +# define LDblConst 262 +# define CharConst 263 +# define LCharConst 264 +# define IntConst 265 +# define UIntConst 266 +# define LIntConst 267 +# define ULIntConst 268 +# define Arrow 269 +# define Incr 270 +# define Decr 271 +# define LShft 272 +# define RShft 273 +# define Leq 274 +# define Geq 275 +# define TokEqual 276 +# define Neq 277 +# define And 278 +# define Or 279 +# define MultAsgn 280 +# define DivAsgn 281 +# define ModAsgn 282 +# define PlusAsgn 283 +# define MinusAsgn 284 +# define LShftAsgn 285 +# define RShftAsgn 286 +# define AndAsgn 287 +# define XorAsgn 288 +# define OrAsgn 289 +# define Sizeof 290 +# define Intersect 291 +# define OpSym 292 +# define Typedef 293 +# define Extern 294 +# define Static 295 +# define Auto 296 +# define TokRegister 297 +# define Tended 298 +# define TokChar 299 +# define TokShort 300 +# define Int 301 +# define TokLong 302 +# define Signed 303 +# define Unsigned 304 +# define Float 305 +# define Doubl 306 +# define Const 307 +# define Volatile 308 +# define Void 309 +# define TypeDefName 310 +# define Struct 311 +# define Union 312 +# define TokEnum 313 +# define Ellipsis 314 +# define Case 315 +# define Default 316 +# define If 317 +# define Else 318 +# define Switch 319 +# define While 320 +# define Do 321 +# define For 322 +# define Goto 323 +# define Continue 324 +# define Break 325 +# define Return 326 +# define Runerr 327 +# define Is 328 +# define Cnv 329 +# define Def 330 +# define Exact 331 +# define Empty_type 332 +# define IconType 333 +# define Component 334 +# define Variable 335 +# define Any_value 336 +# define Named_var 337 +# define Struct_var 338 +# define C_Integer 339 +# define Arith_case 340 +# define C_Double 341 +# define C_String 342 +# define Tmp_string 343 +# define Tmp_cset 344 +# define Body 345 +# define End 346 +# define TokFunction 347 +# define Keyword 348 +# define Operator 349 +# define Underef 350 +# define Declare 351 +# define Suspend 352 +# define Fail 353 +# define Inline 354 +# define Abstract 355 +# define Store 356 +# define TokType 357 +# define New 358 +# define All_fields 359 +# define Then 360 +# define Type_case 361 +# define Of 362 +# define Len_case 363 +# define Constant 364 +# define Errorfail 365 +# define IfStmt 366 diff --git a/src/rtt/rtt.h b/src/rtt/rtt.h new file mode 100644 index 0000000..78ac812 --- /dev/null +++ b/src/rtt/rtt.h @@ -0,0 +1,2 @@ +#include "ltoken.h" +#include "rtt1.h" diff --git a/src/rtt/rtt1.h b/src/rtt/rtt1.h new file mode 100644 index 0000000..76779c7 --- /dev/null +++ b/src/rtt/rtt1.h @@ -0,0 +1,187 @@ +#include "../preproc/preproc.h" +#include "../preproc/pproto.h" + +#define IndentInc 3 +#define MaxCol 80 + +#define Max(x,y) ((x)>(y)?(x):(y)) + +/* + * cfile is used to create a list of cfiles created from a source file. + */ +struct cfile { + char *name; + struct cfile *next; + }; + +/* + * srcfile is an entry of dependants of a source file. + */ +struct srcfile { + char *name; + struct cfile *dependents; + struct srcfile *next; + }; + +#define ForceNl() nl = 1; +extern int nl; /* flag: a new-line is needed in the output */ + +/* + * The lexical analyzer recognizes 3 states. Operators are treated differently + * in each state. + */ +#define DfltLex 0 /* Covers most input. */ +#define OpHead 1 /* In head of an operator definition. */ +#define TypeComp 2 /* In abstract type computation */ + +extern int lex_state; /* state of operator recognition */ +extern char *compiler_def; /* #define for COMPILER */ +extern FILE *out_file; /* output file */ +extern int def_fnd; /* C input defines something concrete */ +extern char *inclname; /* include file to be included by C compiler */ +extern int iconx_flg; /* flag: indicate that iconx style code is needed */ +extern int enable_out; /* enable output of C code */ +extern char *largeints; /* "Largeints" or "NoLargeInts" */ + +/* + * The symbol table is used by the lexical analyser to decide whether an + * identifier is an ordinary identifier, a typedef name, or a reserved + * word. It is used by the parse tree builder to decide whether an + * identifier is an ordinary C variable, a tended variable, a parameter + * to a run-time routine, or the special variable "result". + */ +struct sym_entry { + int tok_id; /* Ident, TokType, or identification of reserved word */ + char *image; /* image of symbol */ + int id_type; /* OtherDcl, TndDesc, TndStr, TndBlk, Label, RtParm, + DrfPrm, RsltLoc */ + union { + struct { /* RtParm: */ + int param_num; /* parameter number */ + int cur_loc; /* PrmTend, PrmCStr, PrmInt, or PrmDbl */ + int non_tend; /* non-tended locations used */ + int parm_mod; /* something may have modified it */ + struct sym_entry *next; + } param_info; + struct { /* TndDesc, TndStr, TndBlk: */ + struct node *init; /* initial value from declaration */ + char *blk_name; /* TndBlk: struct name of block */ + struct sym_entry *next; + } tnd_var; + struct { /* OtherDcl from "declare {...}": */ + struct node *tqual; /* storage class, type qualifier list */ + struct node *dcltor; /* declarator */ + struct node *init; /* initial value from declaration */ + struct sym_entry *next; + } declare_var; + int typ_indx; /* index into arrays of type information */ + word lbl_num; /* label number used in in-line code */ + int referenced; /* RsltLoc: is referenced */ + } u; + int t_indx; /* index into tended array */ + int il_indx; /* index used in in-line code */ + int nest_lvl; /* 0 - reserved word, 1 - global, >= 2 - local */ + int may_mod; /* may be modified in particular piece of code */ + int ref_cnt; + struct sym_entry *next; + }; + +/* + * Path-specific parameter information must be saved and merged for + * branching and joining of paths. + */ +struct parminfo { + int cur_loc; + int parm_mod; + }; + +/* + * A list is maintained of information needed to initialize tended descriptors. + */ +struct init_tend { + int t_indx; /* index into tended array */ + int init_typ; /* TndDesc, TndStr, TndBlk */ + struct node *init; /* initial value from declaration */ + int nest_lvl; /* level of nesting of current use of tended slot */ + int in_use; /* tended slot is being used in current scope */ + struct init_tend *next; + }; + + +extern int op_type; /* Function, Keyword, Operator, or OrdFunc */ +extern char lc_letter; /* f = function, o = operator, k = keyword */ +extern char uc_letter; /* F = function, O = operator, K = keyword */ +extern char prfx1; /* 1st char of unique prefix for operation */ +extern char prfx2; /* 2nd char of unique prefix for operation */ +extern char *fname; /* current source file name */ +extern int line; /* current source line number */ +extern struct implement *cur_impl; /* data base entry for current operator */ +extern struct token *comment; /* descriptive comment for current oper */ +extern int n_tmp_str; /* total number of string buffers needed */ +extern int n_tmp_cset; /* total number of cset buffers needed */ +extern int nxt_sbuf; /* index of next string buffer */ +extern int nxt_cbuf; /* index of next cset buffer */ +extern struct sym_entry *params; /* current list of parameters */ +extern struct sym_entry *decl_lst; /* declarations from "declare {...}" */ +extern struct init_tend *tend_lst; /* list of allocated tended slots */ +extern char *str_rslt; /* string "result" in string table */ +extern word lbl_num; /* next unused label number */ +extern struct sym_entry *v_len; /* symbol entry for size of varargs */ +extern int il_indx; /* next index into data base symbol table */ + +/* + * lvl_entry keeps track of what is happening at a level of nested declarations. + */ +struct lvl_entry { + int nest_lvl; + int kind_dcl; /* IsTypedef, TndDesc, TndStr, TndBlk, or OtherDcl */ + char *blk_name; /* for TndBlk, the struct name of the block */ + int parms_done; /* level consists of parameter list which is complete */ + struct sym_entry *tended; /* symbol table entries for tended variables */ + struct lvl_entry *next; + }; + +extern struct lvl_entry *dcl_stk; /* stack of declaration contexts */ + +extern int fnc_ret; /* RetInt, RetDbl, RetNoVal, or RetSig for current func */ + +#define NoAbstr -1001 /* no abstract return statement has been encountered */ +#define SomeType -1002 /* assume returned value is consistent with abstr ret */ +extern int abs_ret; /* type from abstract return statement */ + +/* + * Definitions for use in parse tree nodes. + */ + +#define PrimryNd 1 /* simply a token */ +#define PrefxNd 2 /* a prefix expression */ +#define PstfxNd 3 /* a postfix expression */ +#define BinryNd 4 /* a binary expression (not necessarily infix) */ +#define TrnryNd 5 /* an expression with 3 subexpressions */ +#define QuadNd 6 /* an expression with 4 subexpressions */ +#define LstNd 7 /* list of declaration parts */ +#define CommaNd 8 /* arg lst, declarator lst, or init lst, not comma op */ +#define StrDclNd 9 /* structure field declaration */ +#define PreSpcNd 10 /* prefix expression that needs a space after it */ +#define ConCatNd 11 /* two ajacent pieces of code with no other syntax */ +#define SymNd 12 /* a symbol (identifier) node */ +#define ExactCnv 13 /* (exact)integer or (exact)C_integer conversion */ +#define CompNd 14 /* compound statement */ +#define AbstrNd 15 /* abstract type computation */ +#define IcnTypNd 16 /* name of an Icon type */ + +#define NewNode(size) (struct node *)alloc(\ + sizeof(struct node) + (size-1) * sizeof(union field)) + +union field { + struct node *child; + struct sym_entry *sym; /* used with SymNd & CompNd*/ + }; + +struct node { + int nd_id; + struct token *tok; + union field u[1]; /* actual size varies with node type */ + }; + +#include "rttproto.h" diff --git a/src/rtt/rttdb.c b/src/rtt/rttdb.c new file mode 100644 index 0000000..22368fe --- /dev/null +++ b/src/rtt/rttdb.c @@ -0,0 +1,1440 @@ +/* + * rttdb.c - routines to read, manipulate, and write the data base of + * information about run-time routines. + */ + +#include "rtt.h" +#include "../h/version.h" + +#define DHSize 47 +#define MaxLine 80 + +/* + * prototypes for static functions. + */ +static void max_pre (struct implement **tbl, char *pre); +static int name_cmp (char *p1, char *p2); +static int op_cmp (char *p1, char *p2); +static void prt_dpnd (FILE *db); +static void prt_impls (FILE *db, char *sect, struct implement **tbl, + int num, struct implement **sort_ary, int (*com)()); +static int prt_c_fl (FILE *db, struct cfile *clst, int line_left); +static int put_case (FILE *db, struct il_code *il); +static void put_ilc (FILE *db, struct il_c *ilc); +static void put_inlin (FILE *db, struct il_code *il); +static void put_ret (FILE *db, struct il_c *ilc); +static void put_typcd (FILE *db, int typcd); +static void put_var (FILE *db, int code, struct il_c *ilc); +static void ret_flag (FILE *db, int flag, int may_fthru); +static int set_impl (struct token *name, struct implement **tbl, + int num_impl, char *pre); +static void set_prms (struct implement *ptr); +static int src_cmp (char *p1, char *p2); + +static struct implement *bhash[IHSize]; /* hash area for built-in func table */ +static struct implement *ohash[IHSize]; /* hash area for operator table */ +static struct implement *khash[IHSize]; /* hash area for keyword table */ + +static struct srcfile *dhash[DHSize]; /* hash area for file dependencies */ + +static int num_fnc; /* number of function in data base */ +static int num_op = 0; /* number of operators in data base */ +static int num_key; /* number of keywords in data base */ +static int num_src = 0; /* number of source files in dependencies */ + +static char fnc_pre[2]; /* next prefix available for functions */ +static char op_pre[2]; /* next prefix available for operators */ +static char key_pre[2]; /* next prefix available for keywords */ + +static long min_rs; /* min result sequence of current operation */ +static long max_rs; /* max result sequence of current operation */ +static int rsm_rs; /* '+' at end of result sequencce of cur. oper. */ + +static int newdb = 0; /* flag: this is a new data base */ +struct token *comment; /* comment associated with current operation */ +struct implement *cur_impl; /* data base entry for current operation */ + +/* + * loaddb - load data base. + */ +void loaddb(dbname) +char *dbname; + { + char *op; + struct implement *ip; + unsigned hashval; + int i; + char *srcname; + char *c_name; + struct srcfile *sfile; + + + /* + * Initialize internal data base. + */ + for (i = 0; i < IHSize; i++) { + bhash[i] = NULL; /* built-in function table */ + ohash[i] = NULL; /* operator table */ + khash[i] = NULL; /* keyword table */ + } + for (i = 0; i < DHSize; i++) + dhash[i] = NULL; /* dependency table */ + + /* + * Determine if this is a new data base or an existing one. + */ + if (iconx_flg || !db_open(dbname, &largeints)) + newdb = 1; + else { + + /* + * Read information about built-in functions. + */ + num_fnc = db_tbl("functions", bhash); + + /* + * Read information about operators. + */ + db_chstr("", "operators"); /* verify and skip "operators" */ + + while ((op = db_string()) != NULL) { + /* + * Read header information for the operator. + */ + if ((ip = db_impl('O')) == NULL) + db_err2(1, "no implementation information for operator", op); + ip->op = op; + + /* + * Read the descriptive comment and in-line code for the operator, + * then put the entry in the hash table. + */ + db_code(ip); + hashval = (int)IHasher(op); + ip->blink = ohash[hashval]; + ohash[hashval] = ip; + db_chstr("", "end"); /* verify and skip "end" */ + ++num_op; + } + db_chstr("", "endsect"); /* verify and skip "endsect" */ + + /* + * Read information about keywords. + */ + num_key = db_tbl("keywords", khash); + + /* + * Read C file/source dependency information. + */ + db_chstr("", "dependencies"); /* verify and skip "dependencies" */ + + while ((srcname = db_string()) != NULL) { + sfile = src_lkup(srcname); + while ((c_name = db_string()) != NULL) + add_dpnd(sfile, c_name); + db_chstr("", "end"); /* verify and skip "end" */ + } + db_chstr("", "endsect"); /* verify and skip "endsect" */ + + db_close(); + } + + /* + * Determine the next available operation prefixes by finding the + * maximum prefixes currently in use. + */ + max_pre(bhash, fnc_pre); + max_pre(ohash, op_pre); + max_pre(khash, key_pre); + } + +/* + * max_pre - find the maximum prefix in an implemetation table and set the + * prefix array to the next value. + */ +static void max_pre(tbl, pre) +struct implement **tbl; +char *pre; + { + register struct implement *ptr; + unsigned hashval; + int empty = 1; + char dmy_pre[2]; + + pre[0] = '0'; + pre[1] = '0'; + for (hashval = 0; hashval < IHSize; ++hashval) + for (ptr = tbl[hashval]; ptr != NULL; ptr = ptr->blink) { + empty = 0; + /* + * Determine if this prefix is larger than any found so far. + */ + if (cmp_pre(ptr->prefix, pre) > 0) { + pre[0] = ptr->prefix[0]; + pre[1] = ptr->prefix[1]; + } + } + if (!empty) + nxt_pre(dmy_pre, pre, 2); + } + + +/* + * src_lkup - return pointer to dependency information for the given + * source file. + */ +struct srcfile *src_lkup(srcname) +char *srcname; + { + unsigned hashval; + struct srcfile *sfile; + + /* + * See if the source file is already in the dependancy section of + * the data base. + */ + hashval = (unsigned int)(unsigned long)srcname % DHSize; + for (sfile = dhash[hashval]; sfile != NULL && sfile->name != srcname; + sfile = sfile->next) + ; + + /* + * If an entry for the source file was not found, create one. + */ + if (sfile == NULL) { + sfile = NewStruct(srcfile); + sfile->name = srcname; + sfile->dependents = NULL; + sfile->next = dhash[hashval]; + dhash[hashval] = sfile; + ++num_src; + } + return sfile; + } + +/* + * add_dpnd - add the given source/dependency relation to the dependency + * table. + */ +void add_dpnd(sfile, c_name) +struct srcfile *sfile; +char *c_name; + { + struct cfile *cf; + + cf = NewStruct(cfile); + cf->name = c_name; + cf->next = sfile->dependents; + sfile->dependents = cf; + } + +/* + * clr_dpnd - delete all dependencies for the given source file. + */ +void clr_dpnd(srcname) +char *srcname; + { + src_lkup(srcname)->dependents = NULL; + } + +/* + * dumpdb - write the updated data base. + */ +void dumpdb(dbname) +char *dbname; + { + #ifdef Rttx + fprintf(stdout, + "rtt was compiled to only support the intepreter, use -x\n"); + exit(EXIT_FAILURE); + #else /* Rttx */ + FILE *db; + struct implement **sort_ary; + int ary_sz; + int i; + + db = fopen(dbname, "wb"); + if (db == NULL) + err2("cannot open data base for output:", dbname); + if(newdb) + fprintf(stdout, "creating new data base: %s\n", dbname); + + /* + * The data base starts with a version number associated with this + * version of rtt and an indication of whether LargeInts was + * defined during the build. + */ + fprintf(db, "%s %s\n\n", DVersion, largeints); + + fprintf(db, "\ntypes\n\n"); /* start of type code section */ + for (i = 0; i < num_typs; ++i) + fprintf(db, " T%d: %s\n", i, icontypes[i].id); + fprintf(db, "\n$endsect\n\n"); /* end of section for type codes */ + + fprintf(db, "\ncomponents\n\n"); /* start of component code section */ + for (i = 0; i < num_cmpnts; ++i) + fprintf(db, " C%d: %s\n", i, typecompnt[i].id); + fprintf(db, "\n$endsect\n\n"); /* end of section for component codes */ + + /* + * Allocate an array for sorting operation entries. It must be + * large enough to hold functions, operators, or keywords. + */ + ary_sz = Max(num_fnc, num_op); + ary_sz = Max(ary_sz, num_key); + if (ary_sz > 0) + sort_ary = alloc(ary_sz * sizeof(struct implement*)); + else + sort_ary = NULL; + + /* + * Sort and print to the data base the enties for each of the + * three operation sections. + */ + prt_impls(db, "functions", bhash, num_fnc, sort_ary, name_cmp); + prt_impls(db, "\noperators", ohash, num_op, sort_ary, op_cmp); + prt_impls(db, "\nkeywords", khash, num_key, sort_ary, name_cmp); + if (ary_sz > 0) + free((char *)sort_ary); + + /* + * Print the dependancy information to the data base. + */ + prt_dpnd(db); + if (fclose(db) != 0) + err2("cannot close ", dbname); + #endif /* Rttx */ + } + +#ifndef Rttx +/* + * prt_impl - sort and print to the data base the enties from one + * of the operation tables. + */ +static void prt_impls(db, sect, tbl, num, sort_ary, cmp) +FILE *db; +char *sect; +struct implement **tbl; +int num; +struct implement **sort_ary; +int (*cmp)(); + { + int i; + int j; + unsigned hashval; + struct implement *ip; + + /* + * Each operation section begins with the section name. + */ + fprintf(db, "%s\n\n", sect); + + /* + * Sort the table entries before printing. + */ + if (num > 0) { + i = 0; + for (hashval = 0; hashval < IHSize; ++hashval) + for (ip = tbl[hashval]; ip != NULL; ip = ip->blink) + sort_ary[i++] = ip; + qsort((char *)sort_ary, num, sizeof(struct implement *), cmp); + } + + /* + * Output each entry to the data base. + */ + for (i = 0; i < num; ++i) { + ip = sort_ary[i]; + + /* + * Operators have operator symbols. + */ + if (ip->op != NULL) + fprintf(db, "%s\t", ip->op); + + /* + * Print the operation name, the unique prefix used to generate + * C function names, and the number of parameters to the operation. + */ + fprintf(db, "%s\t%c%c %d(", ip->name, ip->prefix[0], ip->prefix[1], + ip->nargs); + + /* + * For each parameter, write and indication of whether a dereferenced + * value, 'd', and/or and undereferenced value, 'u', is needed. + */ + for (j = 0; j < ip->nargs; ++j) { + if (j > 0) + fprintf(db, ","); + if (ip->arg_flgs[j] & RtParm) + fprintf(db, "u"); + if (ip->arg_flgs[j] & DrfPrm) + fprintf(db, "d"); + } + + /* + * Indicate if the last parameter represents the tail of a + * variable length argument list. + */ + if (ip->nargs > 0 && ip->arg_flgs[ip->nargs - 1] & VarPrm) + fprintf(db, "v"); + fprintf(db, ")\t{"); + + /* + * Print the min and max result sequence length. + */ + if (ip->min_result != NoRsltSeq) { + fprintf(db, "%ld,", ip->min_result); + if (ip->max_result == UnbndSeq) + fprintf(db, "*"); + else + fprintf(db, "%ld", ip->max_result); + if (ip->resume) + fprintf(db, "+"); + } + fprintf(db, "} "); + + /* + * Print the return/suspend/fail/fall-through flag and an indication + * of whether the operation explicitly uses the result location + * (as opposed to an implicit use via return or suspend). + */ + ret_flag(db, ip->ret_flag, 0); + if (ip->use_rslt) + fprintf(db, "t "); + else + fprintf(db, "f "); + + /* + * Print the descriptive comment associated with the operation. + */ + fprintf(db, "\n\"%s\"\n", ip->comment); + + /* + * Print information about tended declarations from the declare + * statement. The number of tended variables is printed followed + * by an entry for each variable. Each entry consists of the + * type of the declaration + * + * struct descrip -> desc + * char * -> str + * struct b_xxx * -> blkptr b_xxx + * union block * -> blkptr * + * + * followed by the C code for the initializer (nil indicates none). + */ + fprintf(db, "%d ", ip->ntnds); + for (j = 0; j < ip->ntnds; ++j) { + switch (ip->tnds[j].var_type) { + case TndDesc: + fprintf(db, "desc "); + break; + case TndStr: + fprintf(db, "str "); + break; + case TndBlk: + fprintf(db, "blkptr "); + if (ip->tnds[j].blk_name == NULL) + fprintf(db, "* "); + else + fprintf(db, "%s ", ip->tnds[j].blk_name); + break; + } + put_ilc(db, ip->tnds[j].init); + } + + /* + * Print information about non-tended declarations from the declare + * statement. The number of variables is printed followed by an + * entry for each variable. Each entry consists of the variable + * name followed by the complete C code for the declaration. + */ + fprintf(db, "\n%d ", ip->nvars); + for (j = 0; j < ip->nvars; ++j) { + fprintf(db, "%s ", ip->vars[j].name); + put_ilc(db, ip->vars[j].dcl); + } + fprintf(db, "\n"); + + /* + * Output the "executable" code (includes abstract code) for the + * operation. + */ + put_inlin(db, ip->in_line); + fprintf(db, "\n$end\n\n"); /* end of operation entry */ + } + fprintf(db, "$endsect\n\n"); /* end of section for operation type */ + } + +/* + * put_inlin - put in-line code into the data base file. This is the + * code used by iconc to perform type infernence for the operation + * and to generate a tailored version of the operation. + */ +static void put_inlin(db, il) +FILE *db; +struct il_code *il; + { + int i; + int num_cases; + int indx; + + /* + * RTL statements are handled by this function. Other functions + * are called for C code. + */ + if (il == NULL) { + fprintf(db, "nil "); + return; + } + + switch (il->il_type) { + case IL_Const: + /* + * Constant keyword. + */ + fprintf(db, "const "); + put_typcd(db, il->u[0].n); /* type code */ + fputs(il->u[1].s, db); fputc(' ', db); /* literal */ + break; + case IL_If1: + /* + * if-then statment. + */ + fprintf(db, "if1 "); + put_inlin(db, il->u[0].fld); /* condition */ + fprintf(db, "\n"); + put_inlin(db, il->u[1].fld); /* then clause */ + break; + case IL_If2: + /* + * if-then-else statment. + */ + fprintf(db, "if2 "); + put_inlin(db, il->u[0].fld); /* condition */ + fprintf(db, "\n"); + put_inlin(db, il->u[1].fld); /* then clause */ + fprintf(db, "\n"); + put_inlin(db, il->u[2].fld); /* else clause */ + break; + case IL_Tcase1: + /* + * type_case statement with no default clause. + */ + fprintf(db, "tcase1 "); + put_case(db, il); + break; + case IL_Tcase2: + /* + * type_case statement with a default clause. + */ + fprintf(db, "tcase2 "); + indx = put_case(db, il); + fprintf(db, "\n"); + put_inlin(db, il->u[indx].fld); /* default */ + break; + case IL_Lcase: + /* + * len_case statement. + */ + fprintf(db, "lcase "); + num_cases = il->u[0].n; + fprintf(db, "%d ", num_cases); + indx = 1; + for (i = 0; i < num_cases; ++i) { + fprintf(db, "\n%d ", il->u[indx++].n); /* selection number */ + put_inlin(db, il->u[indx++].fld); /* action */ + } + fprintf(db, "\n"); + put_inlin(db, il->u[indx].fld); /* default */ + break; + case IL_Acase: + /* + * arith_case statement. + */ + fprintf(db, "acase "); + put_inlin(db, il->u[0].fld); /* first variable */ + put_inlin(db, il->u[1].fld); /* second variable */ + fprintf(db, "\n"); + put_inlin(db, il->u[2].fld); /* C_integer action */ + fprintf(db, "\n"); + put_inlin(db, il->u[3].fld); /* integer action */ + fprintf(db, "\n"); + put_inlin(db, il->u[4].fld); /* C_double action */ + break; + case IL_Err1: + /* + * runerr with no value argument. + */ + fprintf(db, "runerr1 "); + fprintf(db, "%d ", il->u[0].n); /* error number */ + break; + case IL_Err2: + /* + * runerr with a value argument. + */ + fprintf(db, "runerr2 "); + fprintf(db, "%d ", il->u[0].n); /* error number */ + put_inlin(db, il->u[1].fld); /* variable */ + break; + case IL_Lst: + /* + * "glue" to string statements together. + */ + fprintf(db, "lst "); + put_inlin(db, il->u[0].fld); + fprintf(db, "\n"); + put_inlin(db, il->u[1].fld); + break; + case IL_Bang: + /* + * ! operator from type checking. + */ + fprintf(db, "! "); + put_inlin(db, il->u[0].fld); + break; + case IL_And: + /* + * && operator from type checking. + */ + fprintf(db, "&& "); + put_inlin(db, il->u[0].fld); + put_inlin(db, il->u[1].fld); + break; + case IL_Cnv1: + /* + * cnv:<dest-type>(<source>) + */ + fprintf(db, "cnv1 "); + put_typcd(db, il->u[0].n); /* type code */ + put_inlin(db, il->u[1].fld); /* source */ + break; + case IL_Cnv2: + /* + * cnv:<dest-type>(<source>,<destination>) + */ + fprintf(db, "cnv2 "); + put_typcd(db, il->u[0].n); /* type code */ + put_inlin(db, il->u[1].fld); /* source */ + put_ilc(db, il->u[2].c_cd); /* destination */ + break; + case IL_Def1: + /* + * def:<dest-type>(<source>,<default-value>) + */ + fprintf(db, "def1 "); + put_typcd(db, il->u[0].n); /* type code */ + put_inlin(db, il->u[1].fld); /* source */ + put_ilc(db, il->u[2].c_cd); /* default value */ + break; + case IL_Def2: + /* + * def:<dest-type>(<source>,<default-value>,<destination>) + */ + fprintf(db, "def2 "); + put_typcd(db, il->u[0].n); /* type code */ + put_inlin(db, il->u[1].fld); /* source */ + put_ilc(db, il->u[2].c_cd); /* default value */ + put_ilc(db, il->u[3].c_cd); /* destination */ + break; + case IL_Is: + /* + * is:<type-name>(<variable>) + */ + fprintf(db, "is "); + put_typcd(db, il->u[0].n); /* type code */ + put_inlin(db, il->u[1].fld); /* variable */ + break; + case IL_Var: + /* + * A variable. + */ + fprintf(db, "%d ", il->u[0].n); /* symbol table index */ + break; + case IL_Subscr: + /* + * A subscripted variable. + */ + fprintf(db, "[ "); + fprintf(db, "%d ", il->u[0].n); /* symbol table index */ + fprintf(db, "%d ", il->u[1].n); /* subscripting index */ + break; + case IL_Block: + /* + * A block of in-line code. + */ + fprintf(db, "block "); + if (il->u[0].n) + fprintf(db, "t "); /* execution can fall through */ + else + fprintf(db, "_ "); /* execution cannot fall through */ + /* + * Output a symbol table of tended variables. + */ + fprintf(db, "%d ", il->u[1].n); /* number of local tended */ + for (i = 2; i - 2 < il->u[1].n; ++i) + switch (il->u[i].n) { + case TndDesc: + fprintf(db, "desc "); + break; + case TndStr: + fprintf(db, "str "); + break; + case TndBlk: + fprintf(db, "blkptr "); + break; + } + put_ilc(db, il->u[i].c_cd); /* body of block */ + break; + case IL_Call: + /* + * A call to a body function. + */ + fprintf(db, "call "); + + /* + * Each body function has a 3rd prefix character to distingish + * it from other functions for the operation. + */ + fprintf(db, "%c ", (char)il->u[1].n); + + /* + * A body function that would only return one possible signal + * need return none. In which case, it can directly return a + * C integer or double directly rather than using a result + * descriptor location. Indicate what it does. + */ + switch (il->u[2].n) { + case RetInt: + fprintf(db, "i "); /* directly return integer */ + break; + case RetDbl: + fprintf(db, "d "); /* directly return double */ + break; + case RetNoVal: + fprintf(db, "n "); /* return nothing directly */ + break; + case RetSig: + fprintf(db, "s "); /* return a signal */ + break; + } + + /* + * Output the return/suspend/fail/fall-through flag. + */ + ret_flag(db, il->u[3].n, 1); + + /* + * Indicate whether the body function expects to have + * an explicit result location passed to it. + */ + if (il->u[4].n) + fprintf(db, "t "); + else + fprintf(db, "f "); + + fprintf(db, "%d ", il->u[5].n); /* num string bufs */ + fprintf(db, "%d ", il->u[6].n); /* num cset bufs */ + i = il->u[7].n; + fprintf(db, "%d ", i); /* num args */ + indx = 8; + /* + * output prototype paramater declarations and actual arguments. + */ + i *= 2; + while (i--) + put_ilc(db, il->u[indx++].c_cd); + break; + case IL_Abstr: + /* + * Abstract type computation. + */ + fprintf(db, "abstr "); + put_inlin(db, il->u[0].fld); /* side effects */ + put_inlin(db, il->u[1].fld); /* return type */ + break; + case IL_VarTyp: + /* + * type(<parameter>) + */ + fprintf(db, "vartyp "); + put_inlin(db, il->u[0].fld); /* variable */ + break; + case IL_Store: + /* + * store[<type>] + */ + fprintf(db, "store "); + put_inlin(db, il->u[0].fld); /* type to be "dereferenced "*/ + break; + case IL_Compnt: + /* + * <type>.<component> + */ + fprintf(db, ". "); + put_inlin(db, il->u[0].fld); /* type */ + if (il->u[1].n == CM_Fields) + fprintf(db, "f "); /* special case record fields */ + else + fprintf(db, "C%d ", (int)il->u[1].n); /* component table index */ + break; + case IL_TpAsgn: + /* + * store[<variable-type>] = <value-type> + */ + fprintf(db, "= "); + put_inlin(db, il->u[0].fld); /* variable type */ + put_inlin(db, il->u[1].fld); /* value type */ + break; + case IL_Union: + /* + * <type 1> ++ <type 2> + */ + fprintf(db, "++ "); + put_inlin(db, il->u[0].fld); + put_inlin(db, il->u[1].fld); + break; + case IL_Inter: + /* + * <type 1> ** <type 2> + */ + fprintf(db, "** "); + put_inlin(db, il->u[0].fld); + put_inlin(db, il->u[1].fld); + break; + case IL_New: + /* + * new <type-name>(<type 1> , ...) + */ + fprintf(db, "new "); + put_typcd(db, il->u[0].n); /* type code */ + i = il->u[1].n; + fprintf(db, "%d ", i); /* num args */ + indx = 2; + while (i--) + put_inlin(db, il->u[indx++].fld); + break; + case IL_IcnTyp: + /* + * <type-name> + */ + fprintf(db, "typ "); + put_typcd(db, il->u[0].n); /* type code */ + break; + } + } + +/* + * put_case - put the cases of a type_case statement into the data base file. + */ +static int put_case(db, il) +FILE *db; +struct il_code *il; + { + int *typ_vect; + int i, j; + int num_cases; + int num_types; + int indx; + + put_inlin(db, il->u[0].fld); /* expression being checked */ + num_cases = il->u[1].n; /* number of cases */ + fprintf(db, "%d ", num_cases); + indx = 2; + for (i = 0; i < num_cases; ++i) { + num_types = il->u[indx++].n; /* number of types in case */ + fprintf(db, "\n%d ", num_types); + typ_vect = il->u[indx++].vect; /* vector of type codes */ + for (j = 0; j < num_types; ++j) + put_typcd(db, typ_vect[j]); /* type code */ + put_inlin(db, il->u[indx++].fld); /* action */ + } + return indx; + } + +/* + * put_typcd - convert a numeric type code into an alpha type code and + * put it in the data base file. + */ +static void put_typcd(db, typcd) +FILE *db; +int typcd; + { + if (typcd >= 0) + fprintf(db, "T%d ", typcd); + else { + switch (typcd) { + case TypAny: + fprintf(db, "a "); /* any_value */ + break; + case TypEmpty: + fprintf(db, "e "); /* empty_type */ + break; + case TypVar: + fprintf(db, "v "); /* variable */ + break; + case TypCInt: + fprintf(db, "ci "); /* C_integer */ + break; + case TypCDbl: + fprintf(db, "cd "); /* C_double */ + break; + case TypCStr: + fprintf(db, "cs "); /* C_string */ + break; + case TypEInt: + fprintf(db, "ei "); /* (exact)integer) */ + break; + case TypECInt: + fprintf(db, "eci "); /* (exact)C_integer */ + break; + case TypTStr: + fprintf(db, "ts "); /* tmp_string */ + break; + case TypTCset: + fprintf(db, "tc "); /* tmp_cset */ + break; + case RetDesc: + fprintf(db, "d "); /* plain descriptor on return/suspend */ + break; + case RetNVar: + fprintf(db, "nv "); /* named_var */ + break; + case RetSVar: + fprintf(db, "sv "); /* struct_var */ + break; + case RetNone: + fprintf(db, "rn "); /* preset result location on return/suspend */ + break; + } + } + } + +/* + * put_ilc - put in-line C code in the data base file. + */ +static void put_ilc(db, ilc) +FILE *db; +struct il_c *ilc; + { + /* + * In-line C code is either "nil" or code bracketed by $c $e. + * The bracketed code consists of text for C code plus special + * constructs starting with $. Control structures have been + * translated into gotos in the form of special constructs + * (note that case statements are not supported in in-line code). + */ + if (ilc == NULL) { + fprintf(db, "nil "); + return; + } + fprintf(db, "$c "); + while (ilc != NULL) { + switch(ilc->il_c_type) { + case ILC_Ref: + put_var(db, 'r', ilc); /* non-modifying reference to variable */ + break; + case ILC_Mod: + put_var(db, 'm', ilc); /* modifying reference to variable */ + break; + case ILC_Tend: + put_var(db, 't', ilc); /* variable declared tended */ + break; + case ILC_SBuf: + fprintf(db, "$sb "); /* string buffer for tmp_string */ + break; + case ILC_CBuf: + fprintf(db, "$cb "); /* cset buffer for tmp_cset */ + break; + case ILC_Ret: + fprintf(db, "$ret "); /* return statement */ + put_ret(db, ilc); + break; + case ILC_Susp: + fprintf(db, "$susp "); /* suspend statement */ + put_ret(db, ilc); + break; + case ILC_Fail: + fprintf(db, "$fail "); /* fail statement */ + break; + case ILC_EFail: + fprintf(db, "$efail "); /* errorfail statement */ + break; + case ILC_Goto: + fprintf(db, "$goto %d ", ilc->n); /* goto label */ + break; + case ILC_CGto: + fprintf(db, "$cgoto "); /* conditional goto */ + put_ilc(db, ilc->code[0]); /* condition (with $c $e) */ + fprintf(db, "%d ", ilc->n); /* label */ + break; + case ILC_Lbl: + fprintf(db, "$lbl %d ", ilc->n); /* label */ + break; + case ILC_LBrc: + fprintf(db, "${ "); /* start of C block with dcls */ + break; + case ILC_RBrc: + fprintf(db, "$} "); /* end of C block with dcls */ + break; + case ILC_Str: + fprintf(db, "%s", ilc->s); /* C code as plain text */ + break; + } + ilc = ilc->next; + } + fprintf(db, " $e "); + } + +/* + * put_var - output in-line C code for a variable. + */ +static void put_var(db, code, ilc) +FILE *db; +int code; +struct il_c *ilc; + { + fprintf(db, "$%c", code); /* 'r': non-mod ref, 'm': mod ref, 't': tended */ + if (ilc->s != NULL) + fprintf(db, "%s", ilc->s); /* access into descriptor */ + if (ilc->n == RsltIndx) + fprintf(db, "r "); /* this is "result" */ + else + fprintf(db, "%d ", ilc->n); /* offset into a symbol table */ + } + +/* + * ret_flag - put a return/suspend/fail/fall-through flag in the data base + * file. + */ +static void ret_flag(db, flag, may_fthru) +FILE *db; +int flag; +int may_fthru; + { + if (flag & DoesFail) + fprintf(db, "f"); /* can fail */ + else + fprintf(db, "_"); /* cannot fail */ + if (flag & DoesRet) + fprintf(db, "r"); /* can return */ + else + fprintf(db, "_"); /* cannot return */ + if (flag & DoesSusp) + fprintf(db, "s"); /* can suspend */ + else + fprintf(db, "_"); /* cannot suspend */ + if (flag & DoesEFail) + fprintf(db, "e"); /* can do error conversion */ + else + fprintf(db, "_"); /* cannot do error conversion */ + if (may_fthru) /* body functions only: */ + if (flag & DoesFThru) + fprintf(db, "t"); /* can fall through */ + else + fprintf(db, "_"); /* cannot fall through */ + fprintf(db, " "); + } + +/* + * put_ret - put the body of a return/suspend statement in the data base. + */ +static void put_ret(db, ilc) +FILE *db; +struct il_c *ilc; + { + int i; + + /* + * Output the type of descriptor constructor on the return/suspend, + * then output the the number of arguments to the constructor, and + * the arguments themselves. + */ + put_typcd(db, ilc->n); + for (i = 0; i < 3 && ilc->code[i] != NULL; ++i) + ; + fprintf(db, "%d ", i); + for (i = 0; i < 3 && ilc->code[i] != NULL; ++i) + put_ilc(db, ilc->code[i]); + } + +/* + * name_cmp - compare implementation structs by name; function used as + * an argument to qsort(). + */ +static int name_cmp(p1, p2) +char *p1; +char *p2; + { + register struct implement *ip1; + register struct implement *ip2; + + ip1 = *(struct implement **)p1; + ip2 = *(struct implement **)p2; + return strcmp(ip1->name, ip2->name); + } + +/* + * op_cmp - compare implementation structs by operator and number of args; + * function used as an argument to qsort(). + */ +static int op_cmp(p1, p2) +char *p1; +char *p2; + { + register int cmp; + register struct implement *ip1; + register struct implement *ip2; + + ip1 = *(struct implement **)p1; + ip2 = *(struct implement **)p2; + + cmp = strcmp(ip1->op, ip2->op); + if (cmp == 0) + return ip1->nargs - ip2->nargs; + else + return cmp; + } + +/* + * prt_dpnd - print dependency information to the data base. + */ +static void prt_dpnd(db) +FILE *db; + { + struct srcfile **sort_ary; + struct srcfile *sfile; + unsigned hashval; + int line_left; + int num; + int i; + + fprintf(db, "\ndependencies\n\n"); /* start of dependency section */ + + /* + * sort the dependency information by source file name. + */ + num = 0; + if (num_src > 0) { + sort_ary = alloc(num_src * sizeof(struct srcfile *)); + for (hashval = 0; hashval < DHSize; ++hashval) + for (sfile = dhash[hashval]; sfile != NULL; sfile = sfile->next) + sort_ary[num++] = sfile; + qsort((char *)sort_ary, num, sizeof(struct srcfile *), + (int (*)())src_cmp); + } + + /* + * For each source file with dependents, output the source file + * name followed by the list of dependent files. The list is + * terminated with "end". + */ + for (i = 0; i < num; ++i) { + sfile = sort_ary[i]; + if (sfile->dependents != NULL) { + fprintf(db, "%-12s ", sfile->name); + line_left = prt_c_fl(db, sfile->dependents, MaxLine - 14); + if (line_left - 4 < 0) + fprintf(db, "\n "); + fprintf(db, "$end\n"); + } + } + fprintf(db, "\n$endsect\n"); /* end of dependency section */ + if (num_src > 0) + free((char *)sort_ary); + } + +/* + * src_cmp - compare srcfile structs; function used as an argument to qsort(). + */ +static int src_cmp(p1, p2) +char *p1; +char *p2; + { + register struct srcfile *sp1; + register struct srcfile *sp2; + + sp1 = *(struct srcfile **)p1; + sp2 = *(struct srcfile **)p2; + return strcmp(sp1->name, sp2->name); + } + +/* + * prt_c_fl - print list of C files in reverse order. + */ +static int prt_c_fl(db, clst, line_left) +FILE *db; +struct cfile *clst; +int line_left; + { + int len; + + if (clst == NULL) + return line_left; + line_left = prt_c_fl(db, clst->next, line_left); + + /* + * If this will exceed the line length, print a new-line and some + * leading white space. + */ + len = strlen(clst->name) + 1; + if (line_left - len < 0) { + fprintf(db, "\n "); + line_left = MaxLine - 14; + } + fprintf(db, "%s ", clst->name); + return line_left - len; + } +#endif /* Rttx */ + +/* + * full_lst - print a full list of all files produced by translations + * as represented in the dependencies section of the data base. + */ +void full_lst(fname) +char *fname; + { + unsigned hashval; + struct srcfile *sfile; + struct cfile *clst; + struct fileparts *fp; + FILE *f; + + f = fopen(fname, "w"); + if (f == NULL) + err2("cannot open ", fname); + for (hashval = 0; hashval < DHSize; ++hashval) + for (sfile = dhash[hashval]; sfile != NULL; sfile = sfile->next) + for (clst = sfile->dependents; clst != NULL; clst = clst->next) { + /* + * Remove the suffix from the name before printing. + */ + fp = fparse(clst->name); + fprintf(f, "%s\n", fp->name); + } + if (fclose(f) != 0) + err2("cannot close ", fname); + } + +/* + * impl_fnc - find or create implementation struct for function currently + * being parsed. + */ +void impl_fnc(name) +struct token *name; + { + /* + * Set the global operation type for later use. If this is a + * new function update the number of them. + */ + op_type = TokFunction; + num_fnc = set_impl(name, bhash, num_fnc, fnc_pre); + } + +/* + * impl_key - find or create implementation struct for keyword currently + * being parsed. + */ +void impl_key(name) +struct token *name; + { + /* + * Set the global operation type for later use. If this is a + * new keyword update the number of them. + */ + op_type = Keyword; + num_key = set_impl(name, khash, num_key, key_pre); + } + +/* + * set_impl - lookup a function or keyword in a hash table and update the + * entry, creating the entry if needed. + */ +static int set_impl(name, tbl, num_impl, pre) +struct token *name; +struct implement **tbl; +int num_impl; +char *pre; + { + register struct implement *ptr; + char *name_s; + unsigned hashval; + + /* + * we only need the operation name and not the entire token. + */ + name_s = name->image; + free_t(name); + + /* + * If the operation is not in the hash table, put it there. + */ + if ((ptr = db_ilkup(name_s, tbl)) == NULL) { + ptr = NewStruct(implement); + hashval = IHasher(name_s); + ptr->blink = tbl[hashval]; + ptr->oper_typ = ((op_type == TokFunction) ? 'F' : 'K'); + nxt_pre(ptr->prefix, pre, 2); /* allocate a unique prefix */ + ptr->name = name_s; + ptr->op = NULL; + tbl[hashval] = ptr; + ++num_impl; + } + + cur_impl = ptr; /* put entry in global variable for later access */ + + /* + * initialize the entry based on global information set during parsing. + */ + set_prms(ptr); + ptr->min_result = min_rs; + ptr->max_result = max_rs; + ptr->resume = rsm_rs; + ptr->ret_flag = 0; + if (comment == NULL) + ptr->comment = ""; + else { + ptr->comment = comment->image; + free_t(comment); + comment = NULL; + } + ptr->ntnds = 0; + ptr->tnds = NULL; + ptr->nvars = 0; + ptr->vars = NULL; + ptr->in_line = NULL; + ptr->iconc_flgs = 0; + return num_impl; + } + +/* + * set_prms - set the parameter information of an implementation based on + * the params list constructed during parsing. + */ +static void set_prms(ptr) +struct implement *ptr; + { + struct sym_entry *sym; + int nargs; + int i; + + /* + * Create an array of parameter flags for the operation. The flag + * indicates the deref/underef and varargs status for each parameter. + */ + if (params == NULL) { + ptr->nargs = 0; + ptr->arg_flgs = NULL; + } + else { + /* + * The parameters are in reverse order, so the number of the parameters + * can be determined by the number assigned to the first one on the + * list. + */ + nargs = params->u.param_info.param_num + 1; + ptr->nargs = nargs; + ptr->arg_flgs = alloc(nargs * sizeof(int)); + for (i = 0; i < nargs; ++i) + ptr->arg_flgs[i] = 0; + for (sym = params; sym != NULL; sym = sym->u.param_info.next) + ptr->arg_flgs[sym->u.param_info.param_num] |= sym->id_type; + } + } + +/* + * impl_op - find or create implementation struct for operator currently + * being parsed. + */ +void impl_op(op_sym, name) +struct token *op_sym; +struct token *name; + { + register struct implement *ptr; + char *op; + int nargs; + unsigned hashval; + + /* + * The operator symbol is needed but not the entire token. + */ + op = op_sym->image; + free_t(op_sym); + + /* + * The parameters are in reverse order, so the number of the parameters + * can be determined by the number assigned to the first one on the + * list. + */ + if (params == NULL) + nargs = 0; + else + nargs = params->u.param_info.param_num + 1; + + /* + * Locate the operator in the hash table; it must match both the + * operator symbol and the number of arguments. If the operator is + * not there, create an entry. + */ + hashval = IHasher(op); + ptr = ohash[hashval]; + while (ptr != NULL && (ptr->op != op || ptr->nargs != nargs)) + ptr = ptr->blink; + if (ptr == NULL) { + ptr = NewStruct(implement); + ptr->blink = ohash[hashval]; + ptr->oper_typ = 'O'; + nxt_pre(ptr->prefix, op_pre, 2); /* allocate a unique prefix */ + ptr->op = op; + ohash[hashval] = ptr; + ++num_op; + } + + /* + * Put the entry and operation type in global variables for + * later access. + */ + cur_impl = ptr; + op_type = Operator; + + /* + * initialize the entry based on global information set during parsing. + */ + ptr->name = name->image; + free_t(name); + set_prms(ptr); + ptr->min_result = min_rs; + ptr->max_result = max_rs; + ptr->resume = rsm_rs; + ptr->ret_flag = 0; + if (comment == NULL) + ptr->comment = ""; + else { + ptr->comment = comment->image; + free_t(comment); + comment = NULL; + } + ptr->ntnds = 0; + ptr->tnds = NULL; + ptr->nvars = 0; + ptr->vars = NULL; + ptr->in_line = NULL; + ptr->iconc_flgs = 0; + } + +/* + * set_r_seq - save result sequence information for updating the + * operation entry. + */ +void set_r_seq(min, max, resume) +long min; +long max; +int resume; + { + if (min == UnbndSeq) + min = 0; + min_rs = min; + max_rs = max; + rsm_rs = resume; + } + diff --git a/src/rtt/rttgram.y b/src/rtt/rttgram.y new file mode 100644 index 0000000..bf47752 --- /dev/null +++ b/src/rtt/rttgram.y @@ -0,0 +1,1101 @@ +/* + * Grammar for RTL. The C portion of the grammar is based on + * the ANSI Draft Standard - 3rd review. + */ + +%{ +#include "rtt1.h" +#define YYMAXDEPTH 250 +%} + +%union { + struct token *t; + struct node *n; + long i; + } + +%token <t> Identifier StrLit LStrLit FltConst DblConst LDblConst +%token <t> CharConst LCharConst IntConst UIntConst LIntConst ULIntConst +%token <t> Arrow Incr Decr LShft RShft Leq Geq Equal Neq +%token <t> And Or MultAsgn DivAsgn ModAsgn PlusAsgn +%token <t> MinusAsgn LShftAsgn RShftAsgn AndAsgn +%token <t> XorAsgn OrAsgn Sizeof Intersect OpSym + +%token <t> Typedef Extern Static Auto Register Tended +%token <t> Char Short Int Long Signed Unsigned Float Doubl Const Volatile +%token <t> Void TypeDefName Struct Union Enum Ellipsis + +%token <t> Case Default If Else Switch While Do For Goto Continue Break Return + +%token <t> '%' '&' '(' ')' '*' '+' ',' '-' '.' '/' '{' '|' '}' '~' '[' ']' +%token <t> '^' ':' ';' '<' '=' '>' '?' '!' '@' '\\' + +%token <t> Runerr Is Cnv Def Exact Empty_type IconType Component Variable +%token <t> Any_value Named_var Struct_var C_Integer Arith_case +%token <t> C_Double C_String Tmp_string Tmp_cset Body End Function Keyword +%token <t> Operator Underef Declare Suspend Fail Inline Abstract Store +%token <t> Type New All_fields Then Type_case Of Len_case Constant Errorfail + +%type <t> unary_op assign_op struct_or_union typedefname +%type <t> identifier op_name key_const union attrb_name + +%type <n> any_ident storage_class_spec type_qual +%type <n> primary_expr postfix_expr arg_expr_lst unary_expr cast_expr +%type <n> multiplicative_expr additive_expr shift_expr relational_expr +%type <n> equality_expr and_expr exclusive_or_expr inclusive_or_expr +%type <n> logical_and_expr logical_or_expr conditional_expr assign_expr +%type <n> expr opt_expr constant_expr opt_constant_expr dcltion +%type <n> typ_dcltion_specs dcltion_specs type_ind type_storcl_tqual_lst +%type <n> storcl_tqual_lst init_dcltor_lst no_tdn_init_dcltor_lst init_dcltor +%type <n> no_tdn_init_dcltor type_spec stnd_type struct_or_union_spec +%type <n> struct_dcltion_lst struct_dcltion struct_dcltion_specs struct_type_ind +%type <n> struct_type_lst struct_dcltor_lst struct_dcltor +%type <n> struct_no_tdn_dcltor_lst struct_no_tdn_dcltor enum_spec enumerator_lst +%type <n> enumerator dcltor no_tdn_dcltor direct_dcltor no_tdn_direct_dcltor +%type <n> pointer opt_pointer tqual_lst param_type_lst opt_param_type_lst +%type <n> param_lst param_dcltion ident_lst type_tqual_lst type_name +%type <n> abstract_dcltor direct_abstract_dcltor initializer initializer_lst +%type <n> stmt labeled_stmt compound_stmt dcltion_lst opt_dcltion_lst stmt_lst +%type <n> expr_stmt selection_stmt iteration_stmt jump_stmt parm_dcls_or_ids +%type <n> func_head opt_stmt_lst local_dcls local_dcl +%type <n> dest_type i_type_name opt_actions actions action ret_val detail_code +%type <n> runerr variable checking_conversions label +%type <n> type_check type_select_lst opt_default type_select selector_lst +%type <n> c_opt_default c_type_select c_type_select_lst non_lbl_stmt +%type <n> simple_check_conj simple_check len_select_lst len_select +%type <n> type_computations side_effect_lst side_effect +%type <n> type basic_type type_lst + +%type <i> opt_plus length + +/* Get rid of shift/reduce conflict on Else. Use precedence to force shift of + Else rather than reduction of if-cond-expr. This insures that the Else + is always paired with innermost If. Note, IfStmt is a dummy token. */ +%nonassoc IfStmt +%nonassoc Else + +%start translation_unit +%% + +primary_expr + : identifier {$$ = sym_node($1);} + | StrLit {$$ = node0(PrimryNd, $1);} + | LStrLit {$$ = node0(PrimryNd, $1);} + | FltConst {$$ = node0(PrimryNd, $1);} + | DblConst {$$ = node0(PrimryNd, $1);} + | LDblConst {$$ = node0(PrimryNd, $1);} + | CharConst {$$ = node0(PrimryNd, $1);} + | LCharConst {$$ = node0(PrimryNd, $1);} + | IntConst {$$ = node0(PrimryNd, $1);} + | UIntConst {$$ = node0(PrimryNd, $1);} + | LIntConst {$$ = node0(PrimryNd, $1);} + | ULIntConst {$$ = node0(PrimryNd, $1);} + | '(' expr ')' {$$ = node1(PrefxNd, $1, $2); free_t($3);} + ; + +postfix_expr + : primary_expr + | postfix_expr '[' expr ']' {$$ = node2(BinryNd, $2, $1, $3); + free_t($4);} + | postfix_expr '(' ')' {$$ = node2(BinryNd, $3, $1, NULL); + free_t($2);} + | postfix_expr '(' arg_expr_lst ')' {$$ = node2(BinryNd, $4, $1, $3); + free_t($2);} + | postfix_expr '.' any_ident {$$ = node2(BinryNd, $2, $1, $3);} + | postfix_expr Arrow any_ident {$$ = node2(BinryNd, $2, $1, $3);} + | postfix_expr Incr {$$ = node1(PstfxNd, $2, $1);} + | postfix_expr Decr {$$ = node1(PstfxNd, $2, $1);} + | Is ':' i_type_name '(' assign_expr ')' + {$$ = node2(BinryNd, $1, $3, $5); free_t($2); free_t($4); free_t($6);} + | Cnv ':' dest_type '(' assign_expr ',' assign_expr ')' + {$$ = node3(TrnryNd, $1, $3, $5, $7), free_t($2); free_t($4); free_t($6); + free_t($8);} + | Def ':' dest_type '(' assign_expr ',' assign_expr ',' assign_expr ')' + {$$ = node4(QuadNd, $1, $3, $5, $7, $9), free_t($2); free_t($4); + free_t($6); free_t($8); free_t($10);} + ; + +arg_expr_lst + : assign_expr + | arg_expr_lst ',' assign_expr {$$ = node2(CommaNd, $2, $1, $3);} + ; + +unary_expr + : postfix_expr + | Incr unary_expr {$$ = node1(PrefxNd, $1, $2);} + | Decr unary_expr {$$ = node1(PrefxNd, $1, $2);} + | unary_op cast_expr {$$ = node1(PrefxNd, $1, $2);} + | Sizeof unary_expr {$$ = node1(PrefxNd, $1, $2);} + | Sizeof '(' type_name ')' {$$ = node1(PrefxNd, $1, $3); + free_t($2); free_t($4);} + ; + +unary_op + : '&' + | '*' + | '+' + | '-' + | '~' + | '!' + ; + +cast_expr + : unary_expr + | '(' type_name ')' cast_expr {$$ = node2(BinryNd, $1, $2, $4); free_t($3);} + ; + +multiplicative_expr + : cast_expr + | multiplicative_expr '*' cast_expr {$$ = node2(BinryNd, $2, $1, $3);} + | multiplicative_expr '/' cast_expr {$$ = node2(BinryNd, $2, $1, $3);} + | multiplicative_expr '%' cast_expr {$$ = node2(BinryNd, $2, $1, $3);} + ; + +additive_expr + : multiplicative_expr + | additive_expr '+' multiplicative_expr {$$ = node2(BinryNd, $2, $1, $3);} + | additive_expr '-' multiplicative_expr {$$ = node2(BinryNd, $2, $1, $3);} + ; + +shift_expr + : additive_expr + | shift_expr LShft additive_expr {$$ = node2(BinryNd, $2, $1, $3);} + | shift_expr RShft additive_expr {$$ = node2(BinryNd, $2, $1, $3);} + ; + +relational_expr + : shift_expr + | relational_expr '<' shift_expr {$$ = node2(BinryNd, $2, $1, $3);} + | relational_expr '>' shift_expr {$$ = node2(BinryNd, $2, $1, $3);} + | relational_expr Leq shift_expr {$$ = node2(BinryNd, $2, $1, $3);} + | relational_expr Geq shift_expr {$$ = node2(BinryNd, $2, $1, $3);} + ; + +equality_expr + : relational_expr + | equality_expr Equal relational_expr {$$ = node2(BinryNd, $2, $1, $3);} + | equality_expr Neq relational_expr {$$ = node2(BinryNd, $2, $1, $3);} + ; + +and_expr + : equality_expr + | and_expr '&' equality_expr {$$ = node2(BinryNd, $2, $1, $3);} + ; + +exclusive_or_expr + : and_expr + | exclusive_or_expr '^' and_expr {$$ = node2(BinryNd, $2, $1, $3);} + ; + +inclusive_or_expr + : exclusive_or_expr + | inclusive_or_expr '|' exclusive_or_expr {$$ = node2(BinryNd, $2, $1, $3);} + ; + +logical_and_expr + : inclusive_or_expr + | logical_and_expr And inclusive_or_expr {$$ = node2(BinryNd, $2, $1, $3);} + ; + +logical_or_expr + : logical_and_expr + | logical_or_expr Or logical_and_expr {$$ = node2(BinryNd, $2, $1, $3);} + ; + +conditional_expr + : logical_or_expr + | logical_or_expr '?' expr ':' conditional_expr + {$$ = node3(TrnryNd, $2, $1, $3, $5); + free_t($4);} + ; + +assign_expr + : conditional_expr + | unary_expr assign_op assign_expr {$$ = node2(BinryNd, $2, $1, $3);} + ; + +assign_op + : '=' + | MultAsgn + | DivAsgn + | ModAsgn + | PlusAsgn + | MinusAsgn + | LShftAsgn + | RShftAsgn + | AndAsgn + | XorAsgn + | OrAsgn + ; + +expr + : assign_expr + | expr ',' assign_expr {$$ = node2(BinryNd, $2, $1, $3);} + ; + +opt_expr + : {$$ = NULL;} + | expr + ; + +constant_expr + : conditional_expr + ; + +opt_constant_expr + : {$$ = NULL;} + | constant_expr + ; + +dcltion + : typ_dcltion_specs ';' {$$ = node2(BinryNd, $2, $1, NULL); + dcl_stk->kind_dcl = OtherDcl;} + | typ_dcltion_specs init_dcltor_lst ';' {$$ = node2(BinryNd, $3, $1, $2); + dcl_stk->kind_dcl = OtherDcl;} + | storcl_tqual_lst no_tdn_init_dcltor_lst ';' + {$$ = node2(BinryNd, $3, $1, $2); + dcl_stk->kind_dcl = OtherDcl;} + ; + +typ_dcltion_specs + : type_ind + | storcl_tqual_lst type_ind {$$ = node2(LstNd, NULL, $1, $2);} + ; + +dcltion_specs + : typ_dcltion_specs + | storcl_tqual_lst + ; + +type_ind + : typedefname {$$ = node0(PrimryNd, $1);} + | typedefname storcl_tqual_lst + {$$ = node2(LstNd, NULL, node0(PrimryNd, $1), $2);} + | type_storcl_tqual_lst + ; + +type_storcl_tqual_lst + : stnd_type + | type_storcl_tqual_lst stnd_type {$$ = node2(LstNd, NULL, $1, $2);} + | type_storcl_tqual_lst storage_class_spec {$$ = node2(LstNd, NULL, $1, $2);} + | type_storcl_tqual_lst type_qual {$$ = node2(LstNd, NULL, $1, $2);} + ; + +storcl_tqual_lst + : storage_class_spec + | type_qual + | storcl_tqual_lst storage_class_spec {$$ = node2(LstNd, NULL, $1, $2);} + | storcl_tqual_lst type_qual {$$ = node2(LstNd, NULL, $1, $2);} + ; + +init_dcltor_lst + : init_dcltor + | init_dcltor_lst ',' init_dcltor {$$ = node2(CommaNd, $2, $1, $3);} + ; + +no_tdn_init_dcltor_lst + : no_tdn_init_dcltor + | no_tdn_init_dcltor_lst ',' no_tdn_init_dcltor + {$$ = node2(CommaNd, $2, $1, $3);} + ; + +init_dcltor + : dcltor {$$ = $1; id_def($1, NULL);} + | dcltor '=' initializer {$$ = node2(BinryNd, $2, $1, $3); id_def($1, $3);} + ; + +no_tdn_init_dcltor + : no_tdn_dcltor {$$ = $1; id_def($1, NULL);} + | no_tdn_dcltor '=' initializer + {$$ = node2(BinryNd, $2, $1, $3); id_def($1, $3);} + ; + +storage_class_spec + : Typedef {$$ = node0(PrimryNd, $1); dcl_stk->kind_dcl = IsTypedef;} + | Extern {$$ = node0(PrimryNd, $1);} + | Static {$$ = node0(PrimryNd, $1);} + | Auto {$$ = node0(PrimryNd, $1);} + | Register {$$ = node0(PrimryNd, $1);} + ; + +type_spec + : stnd_type + | typedefname {$$ = node0(PrimryNd, $1);} + ; + +stnd_type + : Void {$$ = node0(PrimryNd, $1);} + | Char {$$ = node0(PrimryNd, $1);} + | Short {$$ = node0(PrimryNd, $1);} + | Int {$$ = node0(PrimryNd, $1);} + | Long {$$ = node0(PrimryNd, $1);} + | Float {$$ = node0(PrimryNd, $1);} + | Doubl {$$ = node0(PrimryNd, $1);} + | Signed {$$ = node0(PrimryNd, $1);} + | Unsigned {$$ = node0(PrimryNd, $1);} + | struct_or_union_spec + | enum_spec + ; + +struct_or_union_spec + : struct_or_union any_ident '{' struct_dcltion_lst '}' + {$$ = node2(BinryNd, $1, $2, $4); + free_t($3); free_t($5);} + | struct_or_union '{' struct_dcltion_lst '}' + {$$ = node2(BinryNd, $1, NULL, $3); + free_t($2); free_t($4);} + | struct_or_union any_ident {$$ = node2(BinryNd, $1, $2, NULL);} + ; + +struct_or_union + : Struct + | Union + ; + +struct_dcltion_lst + : struct_dcltion + | struct_dcltion_lst struct_dcltion {$$ = node2(LstNd, NULL, $1, $2);} + ; + +struct_dcltion + : struct_dcltion_specs struct_dcltor_lst ';' + {$$ = node2(BinryNd, $3, $1, $2);} + | tqual_lst struct_no_tdn_dcltor_lst ';' {$$ = node2(BinryNd, $3, $1, $2);} + ; + +struct_dcltion_specs + : struct_type_ind + | tqual_lst struct_type_ind {$$ = node2(LstNd, NULL, $1, $2);} + ; + +struct_type_ind + : typedefname {$$ = node0(PrimryNd, $1);} + | typedefname tqual_lst {$$ = node2(LstNd, NULL, node0(PrimryNd, $1), $2);} + | struct_type_lst + ; + +struct_type_lst + : stnd_type + | struct_type_lst stnd_type {$$ = node2(LstNd, NULL, $1, $2);} + | struct_type_lst type_qual {$$ = node2(LstNd, NULL, $1, $2);} ; + +struct_dcltor_lst + : struct_dcltor + | struct_dcltor_lst ',' struct_dcltor {$$ = node2(CommaNd, $2, $1, $3);} + ; + +struct_dcltor + : dcltor {$$ = node2(StrDclNd, NULL, $1, NULL); + if (dcl_stk->parms_done) pop_cntxt();} + | ':' constant_expr {$$ = node2(StrDclNd, $1, NULL, $2);} + | dcltor ':' {if (dcl_stk->parms_done) pop_cntxt();} constant_expr + {$$ = node2(StrDclNd, $2, $1, $4);} + ; + +struct_no_tdn_dcltor_lst + : struct_no_tdn_dcltor + | struct_no_tdn_dcltor_lst ',' struct_no_tdn_dcltor + {$$ = node2(CommaNd, $2, $1, $3);} + ; + +struct_no_tdn_dcltor + : no_tdn_dcltor {$$ = node2(StrDclNd, NULL, $1, NULL); + if (dcl_stk->parms_done) pop_cntxt();} + | ':' constant_expr {$$ = node2(StrDclNd, $1, NULL, $2);} + | no_tdn_dcltor ':' {if (dcl_stk->parms_done) pop_cntxt();} constant_expr + {$$ = node2(StrDclNd, $2, $1, $4);} + ; + +enum_spec + : Enum {push_cntxt(0);} '{' enumerator_lst '}' + {$$ = node2(BinryNd, $1, NULL, $4); pop_cntxt(); free_t($3); free_t($5);} + | Enum any_ident {push_cntxt(0);} '{' enumerator_lst '}' + {$$ = node2(BinryNd, $1, $2, $5); pop_cntxt(); free_t($4); free_t($6);} + | Enum any_ident {$$ = node2(BinryNd, $1, $2, NULL);} + ; + +enumerator_lst + : enumerator + | enumerator_lst ',' enumerator {$$ = node2(CommaNd, $2, $1, $3);} + ; + +enumerator + : any_ident {$$ = $1; id_def($1, NULL);} + | any_ident '=' constant_expr + {$$ = node2(BinryNd, $2, $1, $3); id_def($1, $3);} + ; + +type_qual + : Const {$$ = node0(PrimryNd, $1);} + | Volatile {$$ = node0(PrimryNd, $1);} + ; + + +dcltor + : opt_pointer direct_dcltor {$$ = node2(ConCatNd, NULL, $1, $2);} + ; + +no_tdn_dcltor + : opt_pointer no_tdn_direct_dcltor {$$ = node2(ConCatNd, NULL, $1, $2);} + ; + +direct_dcltor + : any_ident + | '(' dcltor ')' {$$ = node1(PrefxNd, $1, $2); + free_t($3);} + | direct_dcltor '[' opt_constant_expr ']' {$$ = node2(BinryNd, $2, $1, $3); + free_t($4);} + | direct_dcltor '(' {push_cntxt(1);} parm_dcls_or_ids ')' + {$$ = node2(BinryNd, $5, $1, $4); + if (dcl_stk->nest_lvl == 2) + dcl_stk->parms_done = 1; + else + pop_cntxt(); + free_t($2);} + ; + +no_tdn_direct_dcltor + : identifier {$$ = node0(PrimryNd, $1);} + | '(' no_tdn_dcltor ')' {$$ = node1(PrefxNd, $1, $2); + free_t($3);} + | no_tdn_direct_dcltor '[' opt_constant_expr ']' + {$$ = node2(BinryNd, $2, $1, $3); + free_t($4);} + | no_tdn_direct_dcltor '(' {push_cntxt(1);} parm_dcls_or_ids ')' + {$$ = node2(BinryNd, $5, $1, $4); + if (dcl_stk->nest_lvl == 2) + dcl_stk->parms_done = 1; + else + pop_cntxt(); + free_t($2);} + ; + +parm_dcls_or_ids + : opt_param_type_lst + | ident_lst + ; + +pointer + : '*' {$$ = node0(PrimryNd, $1);} + | '*' tqual_lst {$$ = node1(PreSpcNd, $1, $2);} + | '*' pointer {$$ = node1(PrefxNd, $1, $2);} + | '*' tqual_lst pointer {$$ = node1(PrefxNd, $1, node2(LstNd, NULL, $2,$3));} + ; + +opt_pointer + : {$$ = NULL;} + | pointer + ; + +tqual_lst + : type_qual + | tqual_lst type_qual {$$ = node2(LstNd, NULL, $1, $2);} + ; + +param_type_lst + : param_lst + | param_lst ',' Ellipsis {$$ = node2(CommaNd, $2, $1, node0(PrimryNd, $3));} + ; + +opt_param_type_lst + : {$$ = NULL;} + | param_type_lst + ; + +param_lst + : param_dcltion + | param_lst ',' param_dcltion {$$ = node2(CommaNd, $2, $1, $3);} + ; + +param_dcltion + : dcltion_specs no_tdn_dcltor {$$ = node2(LstNd, NULL, $1, $2); + id_def($2, NULL);} + | dcltion_specs + | dcltion_specs abstract_dcltor {$$ = node2(LstNd, NULL, $1, $2);} + ; + +ident_lst + : identifier {$$ = node0(PrimryNd, $1);} + | ident_lst ',' identifier {$$ = node2(CommaNd, $2, $1, node0(PrimryNd,$3));} + ; + +type_tqual_lst + : type_spec + | type_qual + | type_spec type_tqual_lst {$$ = node2(LstNd, NULL, $1, $2);} + | type_qual type_tqual_lst {$$ = node2(LstNd, NULL, $1, $2);} + ; + +type_name + : type_tqual_lst + | type_tqual_lst abstract_dcltor {$$ = node2(LstNd, NULL, $1, $2);} + ; + +abstract_dcltor + : pointer + | opt_pointer direct_abstract_dcltor {$$ = node2(ConCatNd, NULL, $1, $2);} + ; + +direct_abstract_dcltor + : '(' abstract_dcltor ')' {$$ = node1(PrefxNd, $1, $2); + free_t($3);} + | '[' opt_constant_expr ']' + {$$ = node2(BinryNd, $1, NULL, $2); + free_t($3);} + | direct_abstract_dcltor '[' opt_constant_expr ']' + {$$ = node2(BinryNd, $2, $1, $3); + free_t($4);} + | '(' {push_cntxt(1);} opt_param_type_lst ')' + {$$ = node2(BinryNd, $4, NULL, $3); + pop_cntxt(); + free_t($1);} + | direct_abstract_dcltor '(' {push_cntxt(1);} opt_param_type_lst ')' + {$$ = node2(BinryNd, $5, $1, $4); + pop_cntxt(); + free_t($2);} + ; + +initializer + : assign_expr + | '{' initializer_lst '}' + {$$ = node1(PrefxNd, $1, $2); free_t($3);} + | '{' initializer_lst ',' '}' + {$$ = node1(PrefxNd, $1, node2(CommaNd, $3, $2, NULL)); + free_t($4);} + ; + +initializer_lst + : initializer + | initializer_lst ',' initializer {$$ = node2(CommaNd, $2, $1, $3);} + ; + +stmt + : labeled_stmt + | non_lbl_stmt + ; + +non_lbl_stmt + : {push_cntxt(1);} compound_stmt {$$ = $2; pop_cntxt();} + | expr_stmt + | selection_stmt + | iteration_stmt + | jump_stmt + | Runerr '(' assign_expr ')' ';' + {$$ = node2(BinryNd, $1, $3, NULL); free_t($2); free_t($4);} + | Runerr '(' assign_expr ',' assign_expr ')' ';' + {$$ = node2(BinryNd, $1, $3, $5); free_t($2); free_t($4); free_t($6);} + ; + +labeled_stmt + : label ':' stmt {$$ = node2(BinryNd, $2, $1, $3);} + | Case constant_expr ':' stmt {$$ = node2(BinryNd, $1, $2, $4); free_t($3);} + | Default ':' stmt {$$ = node1(PrefxNd, $1, $3); free_t($2);} + ; + +compound_stmt + : '{' opt_stmt_lst '}' {$$ = comp_nd($1, NULL, $2); free_t($3);} + | '{' local_dcls opt_stmt_lst '}' {$$ = comp_nd($1, $2, $3); free_t($4);} + ; + +dcltion_lst + : dcltion + | dcltion_lst dcltion {$$ = node2(LstNd, NULL, $1, $2);} + ; + +opt_dcltion_lst + : {$$ = NULL;} + | dcltion_lst + ; + +local_dcls + : local_dcl + | local_dcls local_dcl {$$ = ($2 == NULL ? $1 : node2(LstNd, NULL, $1, $2));} + ; + +local_dcl + : dcltion + | Tended tended_type init_dcltor_lst ';' + {$$ = NULL; free_t($1); free_t($4); dcl_stk->kind_dcl = OtherDcl;} + ; + +tended_type + : Char {tnd_char(); free_t($1);} + | Struct identifier {tnd_strct($2); free_t($1);} + | Struct TypeDefName {tnd_strct($2); free_t($1);} + | Union identifier {tnd_union($2); free_t($1);} + ; + +stmt_lst + : stmt + | stmt_lst stmt {$$ = node2(ConCatNd, NULL, $1, $2);} + ; + +opt_stmt_lst + : {$$ = NULL;} + | stmt_lst + ; +expr_stmt + : opt_expr ';' {$$ = node1(PstfxNd, $2, $1);} + ; + +selection_stmt + : If '(' expr ')' stmt %prec IfStmt {$$ = node3(TrnryNd, $1, $3, $5,NULL); + free_t($2); free_t($4);} + | If '(' expr ')' stmt Else stmt {$$ = node3(TrnryNd, $1, $3, $5, $7); + free_t($2); free_t($4); free_t($6);} + | Switch '(' expr ')' stmt {$$ = node2(BinryNd, $1, $3, $5); + free_t($2); free_t($4);} + | Type_case expr Of '{' c_type_select_lst c_opt_default '}' + {$$ = node3(TrnryNd, $1, $2, $5, $6); free_t($3); free_t($4); free_t($7);} + ; + +c_type_select_lst + : c_type_select {$$ = node2(ConCatNd, NULL, NULL, $1);} + | c_type_select_lst c_type_select {$$ = node2(ConCatNd, NULL, $1, $2);} + ; + +c_type_select + : selector_lst non_lbl_stmt {$$ = node2(ConCatNd, NULL, $1, $2);} + ; + +c_opt_default + : {$$ = NULL;} + | Default ':' non_lbl_stmt {$$ = $3; free_t($1); free_t($2);} + ; + +iteration_stmt + : While '(' expr ')' stmt {$$ = node2(BinryNd, $1, $3, $5); + free_t($2); free_t($4);} + | Do stmt While '(' expr ')' ';' {$$ = node2(BinryNd, $1, $2, $5); + free_t($3); free_t($4); free_t($6); + free_t($7);} + | For '(' opt_expr ';' opt_expr ';' opt_expr ')' stmt + {$$ = node4(QuadNd, $1, $3, $5, $7, $9); + free_t($2); free_t($4); free_t($6); + free_t($8);} + ; + +jump_stmt + : Goto label';' {$$ = node1(PrefxNd, $1, $2); free_t($3);} + | Continue ';' {$$ = node0(PrimryNd, $1); free_t($2);} + | Break ';' {$$ = node0(PrimryNd, $1); free_t($2);} + | Return ret_val ';' {$$ = node1(PrefxNd, $1, $2); free_t($3);} + | Suspend ret_val ';' {$$ = node1(PrefxNd, $1, $2); free_t($3);} + | Fail ';' {$$ = node0(PrimryNd, $1); free_t($2);} + | Errorfail ';' {$$ = node0(PrimryNd, $1); free_t($2);} + ; + +translation_unit + : + | extrn_decltn_lst + ; + +extrn_decltn_lst + : external_dcltion + | extrn_decltn_lst external_dcltion + ; + +external_dcltion + : function_definition + | dcltion {dclout($1);} + | definition + ; + +function_definition + : func_head {func_def($1);} opt_dcltion_lst compound_stmt + {fncout($1, $3, $4);} + ; + +func_head + : no_tdn_dcltor {$$ = node2(LstNd, NULL, NULL, $1);} + | storcl_tqual_lst no_tdn_dcltor {$$ = node2(LstNd, NULL, $1, $2);} + | typ_dcltion_specs dcltor {$$ = node2(LstNd, NULL, $1, $2);} + ; + +any_ident + : identifier {$$ = node0(PrimryNd, $1);} + | typedefname {$$ = node0(PrimryNd, $1);} + ; + +label + : identifier {$$ = lbl($1);} + | typedefname {$$ = lbl($1);} + ; + +typedefname + : TypeDefName + | C_Integer /* hack to allow C_integer to be defined with typedef */ + | C_Double /* for consistency with C_integer */ + | C_String /* for consistency with C_integer */ + ; + +/* + * The rest of the grammar implements the interface portion of the language. + */ + +definition + : {strt_def();} description operation + ; + +operation + : fnc_oper op_declare actions End {defout($3); free_t($4);} + | keyword actions End {defout($2); free_t($3);} + | keyword Constant key_const End {keyconst($3); free_t($2); free_t($4);} + ; + +description + : {comment = NULL;} + | StrLit {comment = $1;} + ; + +fnc_oper + : Function '{' result_seq '}' op_name '(' opt_s_parm_lst ')' + {impl_fnc($5); free_t($1); free_t($2); free_t($4); free_t($6); + free_t($8);} + | Operator '{' result_seq {lex_state = OpHead;} '}' OpSym + {lex_state = DfltLex;} op_name '(' opt_s_parm_lst ')' + {impl_op($6, $8); free_t($1); free_t($2); free_t($5); free_t($9); + free_t($11);} + +keyword + : Keyword '{' result_seq '}' op_name + {impl_key($5); free_t($1); free_t($2); free_t($4);} + ; + +key_const + : StrLit + | CharConst + | DblConst + | IntConst + ; + +/* + * Allow as many special names to be identifiers as possible + */ +identifier + : Abstract + | All_fields + | Any_value + | Body + | Component + | Declare + | Empty_type + | End + | Exact + | IconType + | Identifier + | Inline + | Named_var + | New + | Of + | Store + | Struct_var + | Then + | Tmp_cset + | Tmp_string + | Type + | Underef + | Variable + ; + +/* + * an operation may be given any name. + */ +op_name + : identifier + | typedefname + | Auto + | Break + | Case + | Char + | Cnv + | Const + | Continue + | Def + | Default + | Do + | Doubl + | Else + | Enum + | Errorfail + | Extern + | Fail + | Float + | For + | Function + | Goto + | If + | Int + | Is + | Keyword + | Long + | Operator + | Register + | Return + | Runerr + | Short + | Signed + | Sizeof + | Static + | Struct + | Suspend + | Switch + | Tended + | Typedef + | Union + | Unsigned + | Void + | Volatile + | While + ; + +result_seq + : {set_r_seq(NoRsltSeq, NoRsltSeq, 0);} + | length opt_plus {set_r_seq($1, $1, (int)$2);} + | length ',' length opt_plus {set_r_seq($1, $3, (int)$4); free_t($2);} + ; + +length + : IntConst {$$ = ttol($1); free_t($1);} + | '*' {$$ = UnbndSeq; free_t($1);} + ; + +opt_plus + : {$$ = 0;} + | '+' {$$ = 1; free_t($1);} + ; + +opt_s_parm_lst + : + | s_parm_lst + | s_parm_lst '[' identifier ']' {var_args($3); free_t($2); free_t($4);} + ; + +s_parm_lst + : s_parm + | s_parm_lst ',' s_parm {free_t($2);} + ; + +s_parm + : identifier {s_prm_def(NULL, $1);} + | Underef identifier {s_prm_def($2, NULL); free_t($1);} + | Underef identifier Arrow identifier {s_prm_def($2, $4); free_t($1); + free_t($3);} + ; + +op_declare + : {} + | Declare '{' local_dcls '}' {d_lst_typ($3); free_t($1); free_t($2); + free_t($4);} + ; + +opt_actions + : {$$ = NULL;} + | actions + ; + +actions + : action + | actions action {$$ = node2(ConCatNd, NULL, $1, $2);} + ; + +action + : checking_conversions + | detail_code + | runerr + | '{' opt_actions '}' {$$ = node1(PrefxNd, $1, $2); free_t($3);} + | Abstract {lex_state = TypeComp;} '{' type_computations + {lex_state = DfltLex;} '}' + {$$ = $4; free_t($1); free_t($3); free_t($6);} + ; + +checking_conversions + : If type_check Then action %prec IfStmt + {$$ = node3(TrnryNd, $1, $2, $4, NULL); free_t($3);} + | If type_check Then action Else action + {$$ = node3(TrnryNd, $1, $2, $4, $6); free_t($3); free_t($5);} + | Type_case variable Of '{' type_select_lst opt_default '}' + {$$ = node3(TrnryNd, $1, $2, $5, $6); free_t($3); free_t($4); free_t($7);} + | Len_case identifier Of '{' len_select_lst Default ':' action '}' + {$$ = node3(TrnryNd, $1, sym_node($2), $5, $8); free_t($3), free_t($4); + free_t($6); free_t($7); free_t($9);} + | Arith_case '(' variable ',' variable ')' Of '{' + dest_type ':' action dest_type ':' action dest_type ':' action '}' + {$$ = arith_nd($1, $3, $5, $9, $11, $12, $14, $15, $17); free_t($2); + free_t($4), free_t($6); free_t($7); free_t($8); free_t($10); + free_t($13); free_t($16); free_t($18);} + ; + +type_select_lst + : type_select {$$ = node2(ConCatNd, NULL, NULL, $1);} + | type_select_lst type_select {$$ = node2(ConCatNd, NULL, $1, $2);} + ; + +type_select + : selector_lst action {$$ = node2(ConCatNd, NULL, $1, $2);} + ; + +opt_default + : {$$ = NULL;} + | Default ':' action {$$ = $3; free_t($1); free_t($2);} + ; + +selector_lst + : i_type_name ':' {$$ = node2(ConCatNd, NULL, NULL, $1); + free_t($2);} + | selector_lst i_type_name ':' {$$ = node2(ConCatNd, NULL, $1, $2); + free_t($3);} + ; + +len_select_lst + : len_select + | len_select_lst len_select {$$ = node2(ConCatNd, NULL, $1, $2);} + ; + +len_select + : IntConst ':' action {$$ = node1(PrefxNd, $1, $3); free_t($2);} + ; + +type_check + : simple_check_conj + | '!' simple_check {$$ = node1(PrefxNd, $1, $2);} + ; + +simple_check_conj + : simple_check + | simple_check_conj And simple_check {$$ = node2(BinryNd, $2, $1, $3);} + ; + +simple_check + : Is ':' i_type_name '(' variable ')' + {$$ = node2(BinryNd, $1, $3, $5); free_t($2); free_t($4); free_t($6);} + | Cnv ':' dest_type '(' variable ')' + {$$ = node3(TrnryNd, $1, $3, $5, NULL), dst_alloc($3, $5); free_t($2); + free_t($4); free_t($6);} + | Cnv ':' dest_type '(' variable ',' assign_expr ')' + {$$ = node3(TrnryNd, $1, $3, $5, $7), free_t($2); free_t($4); free_t($6); + free_t($8);} + | Def ':' dest_type '(' variable ',' assign_expr ')' + {$$ = node4(QuadNd, $1, $3, $5, $7, NULL), dst_alloc($3, $5); free_t($2); + free_t($4); free_t($6); free_t($8);} + | Def ':' dest_type '(' variable ',' assign_expr ',' assign_expr ')' + {$$ = node4(QuadNd, $1, $3, $5, $7, $9), free_t($2); free_t($4); + free_t($6); free_t($8); free_t($10);} + ; + +detail_code + : Body {push_cntxt(1);} compound_stmt + {$$ = node1(PrefxNd, $1, $3); pop_cntxt();} + | Inline {push_cntxt(1);} compound_stmt + {$$ = node1(PrefxNd, $1, $3); pop_cntxt();} + ; + +runerr + : Runerr '(' IntConst ')' opt_semi + {$$ = node2(BinryNd, $1, node0(PrimryNd, $3), NULL); + free_t($2); free_t($4);} + | Runerr '(' IntConst ',' variable ')' opt_semi + {$$ = node2(BinryNd, $1, node0(PrimryNd, $3), $5); + free_t($2); free_t($4); free_t($6);} + ; + +opt_semi + : + | ';' {free_t($1);} + ; + +variable + : identifier {$$ = sym_node($1);} + | identifier '[' IntConst ']' {$$ = node2(BinryNd, $2, sym_node($1), + node0(PrimryNd, $3)); + free_t($4);} + +dest_type + : IconType {$$ = dest_node($1);} + | C_Integer {$$ = node0(PrimryNd, $1);} + | C_Double {$$ = node0(PrimryNd, $1);} + | C_String {$$ = node0(PrimryNd, $1);} + | Tmp_string {$$ = node0(PrimryNd, $1); ++n_tmp_str;} + | Tmp_cset {$$ = node0(PrimryNd, $1); ++n_tmp_cset;} + | '(' Exact ')' IconType {$$ = node0(ExactCnv, chk_exct($4)); free_t($1); + free_t($2); free_t($3);} + | '(' Exact ')' C_Integer {$$ = node0(ExactCnv, $4); free_t($1); free_t($2); + free_t($3);} + ; + +i_type_name + : Any_value {$$ = node0(PrimryNd, $1);} + | Empty_type {$$ = node0(PrimryNd, $1);} + | IconType {$$ = sym_node($1);} + | Variable {$$ = node0(PrimryNd, $1);} + ; + +ret_val + : opt_expr + | C_Integer assign_expr {$$ = node1(PrefxNd, $1, $2);} + | C_Double assign_expr {$$ = node1(PrefxNd, $1, $2);} + | C_String assign_expr {$$ = node1(PrefxNd, $1, $2);} + ; + +type_computations + : side_effect_lst Return type opt_semi {$$ = node2(AbstrNd, $2, $1, $3);} + | Return type opt_semi {$$ = node2(AbstrNd, $1, NULL, $2);} + | side_effect_lst {$$ = node2(AbstrNd, NULL, $1, NULL);} + ; + +side_effect_lst + : side_effect + | side_effect_lst side_effect {$$ = node2(ConCatNd, NULL, $1, $2);} + ; + +side_effect + : Store '[' type ']' '=' type opt_semi {$$ = node2(BinryNd, $5, $3, $6); + free_t($1); free_t($2); free_t($4);} + ; + +type + : basic_type + | type union basic_type {$$ = node2(BinryNd, $2, $1, $3);} + | type Intersect basic_type {$$ = node2(BinryNd, $2, $1, $3);} + +basic_type + : i_type_name {$$ = node1(IcnTypNd, + copy_t($1->tok), $1);} + | Type '(' variable ')' {$$ = node1(PrefxNd, $1, $3); + free_t($2); free_t($4);} + | New i_type_name '(' type_lst ')' {$$ = node2(BinryNd, $1, $2, $4); + free_t($3); free_t($5);} + | Store '[' type ']' {$$ = node1(PrefxNd, $1, $3); + free_t($2); free_t($4);} + | basic_type '.' attrb_name {$$ = node1(PstfxNd, $3, $1); + free_t($2);} + | '(' type ')' {$$ = $2; free_t($1); free_t($3);} + ; + +union + : Incr + ; + +type_lst + : type + | type_lst ',' type {$$ = node2(CommaNd, $2, $1, $3);} + ; + +attrb_name + : Component + | All_fields + ; + +%% + +/* + * xfree(p) -- used with free(p) macro to avoid compiler errors from + * miscast free calls generated by Yacc. + */ +static void xfree(p) +char *p; +{ + free(p); +} + +#define free(p) xfree((char*)p) 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 */ + } + } diff --git a/src/rtt/rttinlin.c b/src/rtt/rttinlin.c new file mode 100644 index 0000000..660c604 --- /dev/null +++ b/src/rtt/rttinlin.c @@ -0,0 +1,1950 @@ +/* + * rttinlin.c contains routines which produce the in-line version of an + * operation and put it in the data base. + */ +#include "rtt.h" + +/* + * prototypes for static functions. + */ +static struct il_code *abstrcomp (struct node *n, int indx_stor, + int chng_stor, int escapes); +static void abstrsnty (struct token *t, int typcd, + int indx_stor, int chng_stor); +static int body_anlz (struct node *n, int *does_break, + int may_mod, int const_cast, int all); +static struct il_code *body_fnc (struct node *n); +static void chkrettyp (struct node *n); +static void chng_ploc (int typcd, struct node *src); +static void cnt_bufs (struct node *cnv_typ); +static struct il_code *il_walk (struct node *n); +static struct il_code *il_var (struct node *n); +static int is_addr (struct node *dcltor, int modifier); +static void lcl_tend (struct node *n); +static int mrg_abstr (int sum, int typ); +static int strct_typ (struct node *typ, int *is_reg); + +static int body_ret; /* RetInt, RetDbl, and/or RetOther for current body */ +static int ret_flag; /* DoesFail, DoesRet, and/or DoesSusp for current body */ +int fnc_ret; /* RetInt, RetDbl, RetNoVal, or RetSig for current func */ + +#ifndef Rttx + +/* + * body_prms is a list of symbol table entries for identifiers that must + * be passed as parameters to the function implementing the current + * body statement. The id_type of an identifier may be changed in the + * symbol table while the body function is being produced; for example, + * a tended descriptor is accessed through a parameter that is a pointer + * to a descriptor, rather than being accessed as an element of a descriptor + * array in a struct. + */ +struct var_lst { + struct sym_entry *sym; + int id_type; /* saved value of id_type from sym */ + struct var_lst *next; + }; +struct var_lst *body_prms; +int n_bdy_prms; /* number of entries in body_prms list */ +int rslt_loc; /* flag: function passed addr of result descriptor */ + +char prfx3; /* 3rd prefix char; used for unique body func names */ + +/* + * in_line - place in the data base in-line code for an operation and + * produce C functions for body statements. + */ +void in_line(n) +struct node *n; + { + struct sym_entry *sym; + int i; + int nvars; + int ntend; + + prfx3 = ' '; /* reset 3rd prefix char for body functions */ + + /* + * Set up the local symbol table in the data base for the in-line code. + * This symbol table has an array of entries for the tended variables + * in the declare statement, if there is one. Determine how large the + * array must be and create it. + */ + ntend = 0; + for (sym = dcl_stk->tended; sym != NULL; sym = sym->u.tnd_var.next) + ++ntend; + if (ntend == 0) + cur_impl->tnds = NULL; + else + cur_impl->tnds = alloc(ntend * sizeof(struct tend_var)); + cur_impl->ntnds = ntend; + i = 0; + + /* + * Go back through the declarations and fill in the array for the + * tended part of the data base symbol table. Array entries contain + * an indication of the type of tended declaration, the C code to + * initialize the variable if there is any, and, for block pointer + * declarations, the type of block. rtt's symbol table is updated to + * contain the variable's offset into the data base's symbol table. + * Note that parameters are considered part of the data base's symbol + * table when computing the offset and il_indx initially contains + * their number. + */ + for (sym = dcl_stk->tended; sym != NULL; sym = sym->u.tnd_var.next) { + cur_impl->tnds[i].var_type = sym->id_type; + cur_impl->tnds[i].init = inlin_c(sym->u.tnd_var.init, 0); + cur_impl->tnds[i].blk_name = sym->u.tnd_var.blk_name; + sym->il_indx = il_indx++; + ++i; + } + + /* + * The data base's symbol table also has entries for non-tended + * variables from the declare statement. Each entry has the + * identifier for the variable and the declaration (redundantly + * including the identifier). Once again the offset for the data + * base symbol table is stored in rtt's symbol table. + */ + nvars = -il_indx; /* pre-subtract preceding number of entries */ + for (sym = decl_lst; sym != NULL; sym = sym->u.declare_var.next) + sym->il_indx = il_indx++; + nvars += il_indx; /* compute number of entries in this part of table */ + cur_impl->nvars = nvars; + if (nvars > 0) { + cur_impl->vars = alloc(nvars * sizeof(struct ord_var)); + i = 0; + for (sym = decl_lst; sym != NULL; sym = sym->u.declare_var.next) { + cur_impl->vars[i].name = sym->image; + cur_impl->vars[i].dcl = ilc_dcl(sym->u.declare_var.tqual, + sym->u.declare_var.dcltor, sym->u.declare_var.init); + ++i; + } + } + + abs_ret = NoAbstr; /* abstract clause not encountered yet */ + cur_impl->in_line = il_walk(n); /* produce in-line code for operation */ + } + +/* + * il_walk - walk the syntax tree producing in-line code. + */ +static struct il_code *il_walk(n) +struct node *n; + { + struct token *t; + struct node *n1; + struct node *n2; + struct il_code *il; + struct il_code *il1; + struct sym_entry *sym; + struct init_tend *tnd; + int dummy_int; + int ntend; + int typcd; + + if (n == NULL) + return NULL; + + t = n->tok; + + switch (n->nd_id) { + case PrefxNd: + switch (t->tok_id) { + case '{': + /* + * RTL code: { <actions> } + */ + il = il_walk(n->u[0].child); + break; + case '!': + /* + * RTL type-checking and conversions: ! <simple-type-check> + */ + il = new_il(IL_Bang, 1); + il->u[0].fld = il_walk(n->u[0].child); + break; + case Body: + /* + * RTL code: body { <c-code> } + */ + il = body_fnc(n); + break; + case Inline: + /* + * RTL code: inline { <c-code> } + * + * An in-line code "block" in the data base starts off + * with an indication of whether execution falls through + * the code and a list of tended descriptors needed by the + * in-line C code. The list indicates the kind of tended + * descriptor. The list is determined by walking to the + * syntax tree for the C code; tend_lst points to its + * beginning. The last item in the block is the C code itself. + */ + free_tend(); + lcl_tend(n); + if (tend_lst == NULL) + ntend = 0; + else + ntend = tend_lst->t_indx + 1; + il = new_il(IL_Block, 3 + ntend); + /* + * Only need "fall through" info from body_anlz(). + */ + il->u[0].n = body_anlz(n->u[0].child, &dummy_int, 0, 0, 0); + il->u[1].n = ntend; + for (tnd = tend_lst; tnd != NULL; tnd = tnd->next) + il->u[2 + tnd->t_indx].n = tnd->init_typ; + il->u[ntend + 2].c_cd = inlin_c(n->u[0].child, 0); + if (!il->u[0].n) + clr_prmloc(); /* execution does not continue */ + break; + } + break; + case BinryNd: + switch (t->tok_id) { + case Runerr: + /* + * RTL code: runerr( <message-number> ) + * runerr( <message-number>, <descriptor> ) + */ + if (n->u[1].child == NULL) + il = new_il(IL_Err1, 1); + else { + il = new_il(IL_Err2, 2); + il->u[1].fld = il_var(n->u[1].child); + } + il->u[0].n = atol(n->u[0].child->tok->image); + /* + * Execution cannot continue on this execution path. + */ + clr_prmloc(); + break; + case And: + /* + * RTL type-checking and conversions: + * <type-check> && <type_check> + */ + il = new_il(IL_And, 2); + il->u[0].fld = il_walk(n->u[0].child); + il->u[1].fld = il_walk(n->u[1].child); + break; + case Is: + /* + * RTL type-checking and conversions: + * is: <icon-type> ( <variable> ) + */ + il = new_il(IL_Is, 2); + il->u[0].n = icn_typ(n->u[0].child); + il->u[1].fld = il_var(n->u[1].child); + break; + } + break; + case ConCatNd: + /* + * "Glue" for two constructs. + */ + il = new_il(IL_Lst, 2); + il->u[0].fld = il_walk(n->u[0].child); + il->u[1].fld = il_walk(n->u[1].child); + break; + case AbstrNd: + /* + * RTL code: abstract { <type-computations> } + * + * Remember the return statement if there is one. It is used for + * type checking when types are easily determined. + */ + il = new_il(IL_Abstr, 2); + il->u[0].fld = abstrcomp(n->u[0].child, 0, 0, 0); + il1 = abstrcomp(n->u[1].child, 0, 0, 1); + il->u[1].fld = il1; + if (il1 != NULL) { + if (abs_ret != NoAbstr) + errt1(t,"only one abstract return may be on any execution path"); + if (il1->il_type == IL_IcnTyp || il1->il_type == IL_New) + abs_ret = il1->u[0].n; + else + abs_ret = SomeType; + } + break; + 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 parameter + * types and locations along success and failure paths of + * these conversions. The "then" and "else" actions may + * also establish new scopes (if a parameter is used within + * a overlapping scopes that conflict, it has already been + * detected). + * + * The "then" and "else" actions may contain abstract return + * statements. The types of these must be "merged" in case + * type checking must be done on real return or suspend + * statements following the "if". + */ + struct parminfo *then_prms = NULL; + struct parminfo *else_prms; + struct node *cond; + struct node *else_nd; + int sav_absret; + int new_absret; + + /* + * Save the current parameter locations. These are in + * effect on the failure path of any type conversions + * in the condition of the "if". Also remember any + * information from abstract returns. + */ + else_prms = new_prmloc(); + sv_prmloc(else_prms); + sav_absret = new_absret = abs_ret; + + cond = n->u[0].child; + else_nd = n->u[2].child; + + if (else_nd == NULL) + il = new_il(IL_If1, 2); + else + il = new_il(IL_If2, 3); + il->u[0].fld = il_walk(cond); + /* + * If the condition is negated, the failure path is to the "then" + * and the success path is to the "else". + */ + if (cond->nd_id == PrefxNd && cond->tok->tok_id == '!') { + then_prms = else_prms; + else_prms = new_prmloc(); + sv_prmloc(else_prms); + ld_prmloc(then_prms); + } + il->u[1].fld = il_walk(n->u[1].child); /* then ... */ + if (else_nd == NULL) { + mrg_prmloc(else_prms); + ld_prmloc(else_prms); + } + else { + if (then_prms == NULL) + then_prms = new_prmloc(); + sv_prmloc(then_prms); + ld_prmloc(else_prms); + new_absret = mrg_abstr(new_absret, abs_ret); + abs_ret = sav_absret; + il->u[2].fld = il_walk(else_nd); + mrg_prmloc(then_prms); + ld_prmloc(then_prms); + } + abs_ret = mrg_abstr(new_absret, abs_ret); + if (then_prms != NULL) + free((char *)then_prms); + if (else_prms != NULL) + free((char *)else_prms); + } + break; + case Len_case: { + /* + * RTL code: + * len_case <variable> of { + * <integer>: <action> + * ... + * default: <action> + * } + */ + struct parminfo *strt_prms; + struct parminfo *end_prms; + int n_cases; + int indx; + int sav_absret; + int new_absret; + + /* + * A case may contain parameter conversions that create new + * scopes. Remember the parameter locations at the start + * of the len_case statement. Also remember information + * about abstract type returns. + */ + strt_prms = new_prmloc(); + sv_prmloc(strt_prms); + end_prms = new_prmloc(); + sav_absret = new_absret = abs_ret; + + /* + * Count the number of cases; there is at least one. + */ + n_cases = 1; + for (n1 = n->u[1].child; n1->nd_id == ConCatNd; + n1 = n1->u[0].child) + ++n_cases; + + /* + * The data base entry has one slot for the number of cases, + * one for the default clause, and two for each case. A + * case includes a selection integer and an action. + */ + il = new_il(IL_Lcase, 2 + 2 * n_cases); + il->u[0].n = n_cases; + + /* + * Go through the cases, adding them to the data base entry. + * Merge resulting parameter locations and information + * about abstract type returns, then restore the starting + * information for the next case. + */ + indx = 2 * n_cases; + for (n1 = n->u[1].child; n1->nd_id == ConCatNd; + n1 = n1->u[0].child) { + il->u[indx--].fld = il_walk(n1->u[1].child->u[0].child); + il->u[indx--].n = atol(n1->u[1].child->tok->image); + mrg_prmloc(end_prms); + ld_prmloc(strt_prms); + new_absret = mrg_abstr(new_absret, abs_ret); + abs_ret = sav_absret; + } + /* + * Last case. + */ + il->u[indx--].fld = il_walk(n1->u[0].child); + il->u[indx].n = atol(n1->tok->image); + mrg_prmloc(end_prms); + ld_prmloc(strt_prms); + new_absret = mrg_abstr(new_absret, abs_ret); + abs_ret = sav_absret; + /* + * Default clause. + */ + il->u[1 + 2 * n_cases].fld = il_walk(n->u[2].child); + mrg_prmloc(end_prms); + ld_prmloc(end_prms); + abs_ret = mrg_abstr(new_absret, abs_ret); + if (strt_prms != NULL) + free((char *)strt_prms); + if (end_prms != NULL) + free((char *)end_prms); + } + break; + case Type_case: { + /* + * RTL code: + * type_case <variable> of { + * <icon_type> : ... <icon_type> : <action> + * ... + * } + * + * last clause may be: default: <action> + */ + struct node *sel; + struct parminfo *strt_prms; + struct parminfo *end_prms; + int *typ_vect; + int n_case; + int n_typ; + int n_fld; + int sav_absret; + int new_absret; + + /* + * A case may contain parameter conversions that create new + * scopes. Remember the parameter locations at the start + * of the type_case statement. Also remember information + * about abstract type returns. + */ + strt_prms = new_prmloc(); + sv_prmloc(strt_prms); + end_prms = new_prmloc(); + sav_absret = new_absret = abs_ret; + + /* + * Count the number of cases. + */ + n_case = 0; + for (n1 = n->u[1].child; n1 != NULL; n1 = n1->u[0].child) + ++n_case; + + /* + * The data base entry has one slot for the variable whose + * type is being tested, one for the number cases, three + * for each case, and, if there is default clause, one + * for it. Each case includes the number of types selected + * by the case, a vectors of those types, and the action + * for the case. + */ + if (n->u[2].child == NULL) { + il = new_il(IL_Tcase1, 3 * n_case + 2); + il->u[0].fld = il_var(n->u[0].child); + } + else { + /* + * There is a default clause. + */ + il = new_il(IL_Tcase2, 3 * n_case + 3); + il->u[0].fld = il_var(n->u[0].child); + il->u[3 * n_case + 2].fld = il_walk(n->u[2].child); + mrg_prmloc(end_prms); + ld_prmloc(strt_prms); + } + il->u[1].n = n_case; + + /* + * Go through the cases, adding them to the data base entry. + * Merge resulting parameter locations and information + * about abstract type returns, then restore the starting + * information for the next case. + */ + n_fld = 2; + for (n1 = n->u[1].child; n1 != NULL; n1 = n1->u[0].child) { + /* + * Determine the number types selected by the case and + * put the types in a vector. + */ + sel = n1->u[1].child; + n_typ = 0; + for (n2 = sel->u[0].child; n2 != NULL; n2 = n2->u[0].child) + n_typ++; + il->u[n_fld++].n = n_typ; + typ_vect = alloc(n_typ * sizeof(int)); + il->u[n_fld++].vect = typ_vect; + n_typ = 0; + for (n2 = sel->u[0].child; n2 != NULL; n2 = n2->u[0].child) + typ_vect[n_typ++] = icn_typ(n2->u[1].child); + /* + * Add code for the case to the data base entry. + */ + new_absret = mrg_abstr(new_absret, abs_ret); + abs_ret = sav_absret; + il->u[n_fld++].fld = il_walk(sel->u[1].child); + mrg_prmloc(end_prms); + ld_prmloc(strt_prms); + } + ld_prmloc(end_prms); + abs_ret = mrg_abstr(new_absret, abs_ret); + if (strt_prms != NULL) + free((char *)strt_prms); + if (end_prms != NULL) + free((char *)end_prms); + } + break; + case Cnv: { + /* + * RTL code: cnv: <type> ( <source> ) + * cnv: <type> ( <source> , <destination> ) + */ + struct node *typ; + struct node *src; + struct node *dst; + + typ = n->u[0].child; + src = n->u[1].child; + dst = n->u[2].child; + typcd = icn_typ(typ); + if (src->nd_id == SymNd) + sym = src->u[0].sym; + else if (src->nd_id == BinryNd) + sym = src->u[0].child->u[0].sym; /* subscripted variable */ + else + errt2(src->tok, "undeclared identifier: ", src->tok->image); + if (sym->u.param_info.parm_mod) { + fprintf(stderr, "%s: file %s, line %d, warning: ", + progname, src->tok->fname, src->tok->line); + fprintf(stderr, "%s may be modified\n", sym->image); + fprintf(stderr, + "\ticonc does not handle conversion of modified parameter\n"); + } + + + if (dst == NULL) { + il = new_il(IL_Cnv1, 2); + il->u[0].n = typcd; + il->u[1].fld = il_var(src); + /* + * This "in-place" conversion may create a new scope for the + * source parameter. + */ + chng_ploc(typcd, src); + sym->u.param_info.parm_mod |= 1; + } + else { + il = new_il(IL_Cnv2, 3); + il->u[0].n = typcd; + il->u[1].fld = il_var(src); + il->u[2].c_cd = inlin_c(dst, 1); + } + } + break; + 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 node *var1; + struct node *var2; + struct parminfo *strt_prms; + struct parminfo *end_prms; + int sav_absret; + int new_absret; + + strt_prms = new_prmloc(); + sv_prmloc(strt_prms); + end_prms = new_prmloc(); + sav_absret = new_absret = abs_ret; + + var1 = n->u[0].child; + var2 = n->u[1].child; + n1 = n->u[2].child; /* contains actions for the 3 cases */ + + /* + * The data base entry has a slot for each of the two variables + * and one for each of the three cases. + */ + il = new_il(IL_Acase, 5); + il->u[0].fld = il_var(var1); + il->u[1].fld = il_var(var2); + + /* + * The "in-place" conversions to C_integer creates new scopes. + */ + chng_ploc(TypECInt, var1); + chng_ploc(TypECInt, var2); + il->u[2].fld = il_walk(n1->u[0].child); + mrg_prmloc(end_prms); + new_absret = mrg_abstr(new_absret, abs_ret); + + + /* + * Conversion to integer (applicable to large integers only). + */ + ld_prmloc(strt_prms); + abs_ret = sav_absret; + il->u[3].fld = il_walk(n1->u[1].child); + mrg_prmloc(end_prms); + new_absret = mrg_abstr(new_absret, abs_ret); + + /* + * The "in-place" conversions to C_double creates new scopes. + */ + ld_prmloc(strt_prms); + abs_ret = sav_absret; + chng_ploc(TypCDbl, var1); + chng_ploc(TypCDbl, var2); + il->u[4].fld = il_walk(n1->u[2].child); + mrg_prmloc(end_prms); + + ld_prmloc(end_prms); + abs_ret = mrg_abstr(new_absret, abs_ret); + free((char *)strt_prms); + free((char *)end_prms); + } + break; + } + break; + case QuadNd: { + /* + * RTL code: def: <type> ( <source> , <default>) + * def: <type> ( <source> , <default> , <destination> ) + */ + struct node *typ; + struct node *src; + struct node *dflt; + struct node *dst; + + typ = n->u[0].child; + src = n->u[1].child; + dflt = n->u[2].child; + dst = n->u[3].child; + typcd = icn_typ(typ); + if (dst == NULL) { + il = new_il(IL_Def1, 3); + il->u[0].n = typcd; + il->u[1].fld = il_var(src); + il->u[2].c_cd = inlin_c(dflt, 0); + /* + * This "in-place" conversion may create a new scope for the + * source parameter. + */ + chng_ploc(typcd, src); + } + else { + il = new_il(IL_Def2, 4); + il->u[0].n = typcd; + il->u[1].fld = il_var(src); + il->u[2].c_cd = inlin_c(dflt, 0); + il->u[3].c_cd = inlin_c(dst, 1); + } + } + break; + } + return il; + } + +/* + * il_var - produce in-line code in the data base for varibel references. + * These include both simple identifiers and subscripted identifiers. + */ +static struct il_code *il_var(n) +struct node *n; + { + struct il_code *il; + + if (n->nd_id == SymNd) { + il = new_il(IL_Var, 1); + il->u[0].n = n->u[0].sym->il_indx; /* offset into data base sym. tab. */ + } + else if (n->nd_id == BinryNd) { + /* + * A subscripted variable. + */ + il = new_il(IL_Subscr, 2); + il->u[0].n = n->u[0].child->u[0].sym->il_indx; /* sym. tab. offset */ + il->u[1].n = atol(n->u[1].child->tok->image); /* subscript */ + } + else + errt2(n->tok, "undeclared identifier: ", n->tok->image); + return il; + } + +/* + * abstrcomp - produce data base code for RTL abstract type computations. + * In the process, do a few sanity checks where they are easy to do. + */ +static struct il_code *abstrcomp(n, indx_stor, chng_stor, escapes) +struct node *n; +int indx_stor; +int chng_stor; +int escapes; + { + struct token *t; + struct il_code *il; + int typcd; + int cmpntcd; + + if (n == NULL) + return NULL; + + t = n->tok; + + switch (n->nd_id) { + case PrefxNd: + switch (t->tok_id) { + case TokType: + /* + * type( <variable> ) + */ + il = new_il(IL_VarTyp, 1); + il->u[0].fld = il_var(n->u[0].child); + break; + case Store: + /* + * store[ <type> ] + */ + il = new_il(IL_Store, 1); + il->u[0].fld = abstrcomp(n->u[0].child, 1, 0, 0); + break; + } + break; + case PstfxNd: + /* + * <type> . <attrb_name> + */ + il = new_il(IL_Compnt, 2); + il->u[0].fld = abstrcomp(n->u[0].child, 0, 0, 0); + switch (t->tok_id) { + case Component: + cmpntcd = sym_lkup(t->image)->u.typ_indx; + il->u[1].n = cmpntcd; + if (escapes && !typecompnt[cmpntcd].var) + errt3(t, typecompnt[cmpntcd].id, + " component is an internal reference type.\n", + "\t\tuse store[<type>.<component>] to \"dereference\" it"); + break; + case All_fields: + il->u[1].n = CM_Fields; + break; + } + break; + case IcnTypNd: + /* + * <icon-type> + */ + il = new_il(IL_IcnTyp, 1); + typcd = icn_typ(n->u[0].child); + abstrsnty(t, typcd, indx_stor, chng_stor); + il->u[0].n = typcd; + break; + case BinryNd: + switch (t->tok_id) { + case '=': + /* + * store[ <type> ] = <type> + */ + il = new_il(IL_TpAsgn, 2); + il->u[0].fld = abstrcomp(n->u[0].child, 1, 1, 0); + il->u[1].fld = abstrcomp(n->u[1].child, 0, 0, 1); + break; + case Incr: /* union */ + /* + * <type> ++ <type> + */ + il = new_il(IL_Union, 2); + il->u[0].fld = abstrcomp(n->u[0].child, indx_stor, chng_stor, + escapes); + il->u[1].fld = abstrcomp(n->u[1].child, indx_stor, chng_stor, + escapes); + break; + case Intersect: + /* + * <type> ** <type> + */ + il = new_il(IL_Inter, 2); + il->u[0].fld = abstrcomp(n->u[0].child, indx_stor, chng_stor, + escapes); + il->u[1].fld = abstrcomp(n->u[1].child, indx_stor, chng_stor, + escapes); + break; + case New: { + /* + * new <icon-type> ( <type> , ... ) + */ + struct node *typ; + struct node *args; + int nargs; + + typ = n->u[0].child; + args = n->u[1].child; + + typcd = icn_typ(typ); + abstrsnty(typ->tok, typcd, indx_stor, chng_stor); + + /* + * Determine the number of arguments expected for this + * structure type. + */ + if (typcd >= 0) + nargs = icontypes[typcd].num_comps; + else + nargs = 0; + if (nargs == 0) + errt2(typ->tok,typ->tok->image," is not an aggregate type."); + + /* + * Create the "new" construct for the data base with its type + * code and arguments. + */ + il = new_il(IL_New, 2 + nargs); + il->u[0].n = typcd; + il->u[1].n = nargs; + while (nargs > 1) { + if (args->nd_id == CommaNd) + il->u[1 + nargs].fld = abstrcomp(args->u[1].child, 0,0,1); + else + errt2(typ->tok, "too few arguments for new", + typ->tok->image); + args = args->u[0].child; + --nargs; + } + if (args->nd_id == CommaNd) + errt2(typ->tok, "too many arguments for new",typ->tok->image); + il->u[2].fld = abstrcomp(args, 0, 0, 1); + } + break; + } + break; + case ConCatNd: + /* + * "Glue" for several side effects. + */ + il = new_il(IL_Lst, 2); + il->u[0].fld = abstrcomp(n->u[0].child, 0, 0, 0); + il->u[1].fld = abstrcomp(n->u[1].child, 0, 0, 0); + break; + } + return il; + } + +/* + * abstrsnty - do some sanity checks on how this type is being used in + * an abstract type computation. + */ +static void abstrsnty(t, typcd, indx_stor, chng_stor) +struct token *t; +int typcd; +int indx_stor; +int chng_stor; + { + struct icon_type *itp; + + if ((typcd < 0) || (!indx_stor)) + return; + + itp = &icontypes[typcd]; + + /* + * This type is being used to index the store; make sure this it + * is a variable. + */ + if (itp->deref == DrfNone) + errt2(t, itp->id, " is not a variable type"); + + if (chng_stor && itp->deref == DrfCnst) + errt2(t, itp->id, " has an associated type that may not be changed"); + } + +/* + * body_anlz - walk the syntax tree for the C code in a body statment, + * analyzing the code to determine the interface needed by the C function + * which will implement it. Also determine how many buffers are needed. + * The value returned indicates whether it is possible for execution + * to fall through the the code. + */ +static int body_anlz(n, does_break, may_mod, const_cast, all) +struct node *n; /* subtree being analyzed */ +int *does_break; /* output flag: subtree contains "break;" */ +int may_mod; /* input flag: this subtree might be assigned to */ +int const_cast; /* input flag: expression is cast to (const ...) */ +int all; /* input flag: need all information about operation */ + { + struct token *t; + struct node *n1, *n2, *n3; + struct sym_entry *sym; + struct var_lst *var_ref; + int break_chk = 0; + int fall_thru; + static int may_brnchto; + + if (n == NULL) + return 1; + + t = n->tok; + + switch (n->nd_id) { + case PrimryNd: + switch (t->tok_id) { + case Fail: + if (all) + ret_flag |= DoesFail; + return 0; + case Errorfail: + if (all) + ret_flag |= DoesEFail; + return 0; + case Break: + *does_break = 1; + return 0; + default: /* do nothing special */ + return 1; + } + case PrefxNd: + switch (t->tok_id) { + case Return: + if (all) { + ret_flag |= DoesRet; + chkrettyp(n->u[0].child); /* check for returning of C value */ + } + body_anlz(n->u[0].child, does_break, 0, 0, all); + return 0; + case Suspend: + if (all) { + ret_flag |= DoesSusp; + chkrettyp(n->u[0].child); /* check for returning of C value */ + } + body_anlz(n->u[0].child, does_break, 0, 0, all); + return 1; + case '(': + /* + * parenthesized expression: pass along may_mod and const_cast. + */ + return body_anlz(n->u[0].child, does_break, may_mod, const_cast, + all); + case Incr: /* ++ */ + case Decr: /* -- */ + /* + * Operand may be modified. + */ + body_anlz(n->u[0].child, does_break, 1, 0, all); + return 1; + case '&': + /* + * Unless the address is cast to a const pointer, this + * might be a modifiying reference. + */ + if (const_cast) + body_anlz(n->u[0].child, does_break, 0, 0, all); + else + body_anlz(n->u[0].child, does_break, 1, 0, all); + return 1; + case Default: + fall_thru = body_anlz(n->u[0].child, does_break, 0, 0, all); + may_brnchto = 1; + return fall_thru; + case Goto: + body_anlz(n->u[0].child, does_break, 0, 0, all); + return 0; + default: /* unary operations the need nothing special */ + body_anlz(n->u[0].child, does_break, 0, 0, all); + return 1; + } + case PstfxNd: + if (t->tok_id == ';') + return body_anlz(n->u[0].child, does_break, 0, 0, all); + else { + /* + * C expressions: <expr> ++ + * <expr> -- + * + * modify operand + */ + return body_anlz(n->u[0].child, does_break, 1, 0, all); + } + case PreSpcNd: + body_anlz(n->u[0].child, does_break, 0, 0, all); + return 1; + case SymNd: + /* + * This is an identifier. + */ + if (!all) + return 1; + sym = n->u[0].sym; + if (sym->id_type == RsltLoc) { + /* + * Note that this body code explicitly references the result + * location of the operation. + */ + rslt_loc = 1; + } + else if (sym->nest_lvl == 2) { + /* + * This variable is local to the operation, but declared outside + * the body. It must passed as a parameter to the function. + * See if it is in the parameter list yet. + */ + if (!(sym->id_type & PrmMark)) { + sym->id_type |= PrmMark; + var_ref = NewStruct(var_lst); + var_ref->sym = sym; + var_ref->next = body_prms; + body_prms = var_ref; + ++n_bdy_prms; + } + + /* + * Note if the variable might be assigned to. + */ + sym->may_mod |= may_mod; + } + return 1; + case BinryNd: + switch (t->tok_id) { + case '[': /* subscripting */ + case '.': + /* + * Assignments will modify left operand. + */ + body_anlz(n->u[0].child, does_break, may_mod, 0, all); + body_anlz(n->u[1].child, does_break, 0, 0, all); + return 1; + case '(': + /* + * ( <type> ) expr + */ + body_anlz(n->u[0].child, does_break, 0, 0, all); + /* + * 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) + body_anlz(n->u[1].child, does_break, 0, 1, all); + else + body_anlz(n->u[1].child, does_break, 0, 0, all); + return 1; + case ')': + /* + * function call or declaration: <expr> ( <expr-list> ) + */ + body_anlz(n->u[0].child, does_break, 0, 0, all); + body_anlz(n->u[1].child, does_break, 0, 0, all); + return call_ret(n->u[0].child); + case ':': + case Case: + body_anlz(n->u[0].child, does_break, 0, 0, all); + fall_thru = body_anlz(n->u[1].child, does_break, 0, 0, all); + may_brnchto = 1; + return fall_thru; + case Switch: + body_anlz(n->u[0].child, does_break, 0, 0, all); + fall_thru = body_anlz(n->u[1].child, &break_chk, 0, 0, all); + return fall_thru | break_chk; + case While: { + struct node *n0 = n->u[0].child; + body_anlz(n0, does_break, 0, 0, all); + body_anlz(n->u[1].child, &break_chk, 0, 0, all); + /* + * 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") && !break_chk) + return 0; + return 1; + } + case Do: + /* + * Any "break;" statements in the body do not effect + * outer loops so pass along a new flag for does_break. + */ + body_anlz(n->u[0].child, &break_chk, 0, 0, all); + body_anlz(n->u[1].child, does_break, 0, 0, all); + return 1; + case Runerr: + body_anlz(n->u[0].child, does_break, 0, 0, all); + body_anlz(n->u[1].child, does_break, 0, 0, all); + if (all) + ret_flag |= DoesEFail; /* possibler error failure */ + return 0; + case '=': + case MultAsgn: /* *= */ + case DivAsgn: /* /= */ + case ModAsgn: /* %= */ + case PlusAsgn: /* += */ + case MinusAsgn: /* -= */ + case LShftAsgn: /* <<= */ + case RShftAsgn: /* >>= */ + case AndAsgn: /* &= */ + case XorAsgn: /* ^= */ + case OrAsgn: /* |= */ + /* + * Left operand is modified. + */ + body_anlz(n->u[0].child, does_break, 1, 0, all); + body_anlz(n->u[1].child, does_break, 0, 0, all); + return 1; + default: /* binary operations that need nothing special */ + body_anlz(n->u[0].child, does_break, 0, 0, all); + body_anlz(n->u[1].child, does_break, 0, 0, all); + return 1; + } + case LstNd: + case StrDclNd: + /* + * Some declaration code. + */ + body_anlz(n->u[0].child, does_break, 0, 0, all); + body_anlz(n->u[1].child, does_break, 0, 0, all); + return 1; + case ConCatNd: + /* + * <some-code> <some-code> + */ + if (body_anlz(n->u[0].child, does_break, 0, 0, all)) + return body_anlz(n->u[1].child, does_break, 0, 0, all); + else { + /* + * Cannot directly reach the second piece of code, see if + * it is possible to branch into it. + */ + may_brnchto = 0; + fall_thru = body_anlz(n->u[1].child, does_break, 0, 0, all); + return may_brnchto & fall_thru; + } + case CommaNd: + /* + * <expr> , <expr> + */ + fall_thru = body_anlz(n->u[0].child, does_break, 0, 0, all); + return fall_thru & body_anlz(n->u[1].child, does_break, 0, 0, all); + case CompNd: + /* + * Compound statement, look only at executable code. + * + * First traverse declaration list looking for initializers. + */ + n1 = n->u[0].child; + while (n1 != NULL) { + if (n1->nd_id == LstNd) { + n2 = n1->u[1].child; + n1 = n1->u[0].child; + } + else { + n2 = n1; + n1 = NULL; + } + + /* + * Get declarator list from declaration and traverse it. + */ + n2 = n2->u[1].child; + while (n2 != NULL) { + if (n2->nd_id == CommaNd) { + n3 = n2->u[1].child; + n2 = n2->u[0].child; + } + else { + n3 = n2; + n2 = NULL; + } + if (n3->nd_id == BinryNd && n3->tok->tok_id == '=') + body_anlz(n3->u[1].child, does_break, 0, 0, all); + } + } + + /* + * Check initializers on tended declarations. + */ + for (sym = n->u[1].sym; sym != NULL; sym = sym->u.tnd_var.next) + body_anlz(sym->u.tnd_var.init, does_break, 0, 0, all); + + /* + * Do the statement list. + */ + return body_anlz(n->u[2].child, does_break, 0, 0, all); + case TrnryNd: + switch (t->tok_id) { + case Cnv: + /* + * extended C code: cnv: <type> ( <source> ) + * cnv: <type> ( <source> , <destination> ) + * + * For some conversions, buffers may have to be allocated. + * An explicit destination must be marked as modified. + */ + if (all) + cnt_bufs(n->u[0].child); + body_anlz(n->u[1].child, does_break, 0, 0, all); + body_anlz(n->u[2].child, does_break, 1, 0, all); + return 1; + case If: + /* + * Execution falls through an if statement if it falls + * through either branch. A null "else" branch always + * falls through. + */ + body_anlz(n->u[0].child, does_break, 0, 0, all); + return body_anlz(n->u[1].child, does_break, 0, 0, all) | + body_anlz(n->u[2].child, does_break, 0, 0, all); + case Type_case: + /* + * type_case <expr> of { <section-list> } + * type_case <expr> of { <section-list> <default-clause> } + */ + + body_anlz(n->u[0].child, does_break, 0, 0, all); + /* + * Loop through the case clauses. + */ + fall_thru = 0; + for (n1 = n->u[1].child; n1 != NULL; n1 = n1->u[0].child) { + n2 = n1->u[1].child->u[1].child; + fall_thru |= body_anlz(n2, does_break, 0, 0, all); + } + return fall_thru | body_anlz(n->u[2].child, does_break, 0, 0, + all); + default: /* nothing special is needed for these ternary nodes */ + body_anlz(n->u[0].child, does_break, 0, 0, all); + body_anlz(n->u[1].child, does_break, 0, 0, all); + body_anlz(n->u[2].child, does_break, 0, 0, all); + return 1; + } + case QuadNd: + if (t->tok_id == Def) { + /* + * extended C code: + * def: <type> ( <source> , <default> ) + * def: <type> ( <source> , <default> , <destination> ) + * + * For some conversions, buffers may have to be allocated. + * An explicit destination must be marked as modified. + */ + if (all) + cnt_bufs(n->u[0].child); + body_anlz(n->u[1].child, does_break, 0, 0, all); + body_anlz(n->u[2].child, does_break, 0, 0, all); + body_anlz(n->u[3].child, does_break, 1, 0, all); + return 1; + } + else { /* for */ + /* + * Check for an infinite loop: for (<expr>; ; <expr> ) ... + * + * No ending condition and no breaks in the body. + */ + body_anlz(n->u[0].child, does_break, 0, 0, all); + body_anlz(n->u[1].child, does_break, 0, 0, all); + body_anlz(n->u[2].child, does_break, 0, 0, all); + body_anlz(n->u[3].child, &break_chk, 0, 0, all); + if (n->u[1].child == NULL && !break_chk) + return 0; + else + return 1; + } + } + err1("rtt internal error detected in function body_anlz()"); + /* NOTREACHED */ + return 0; /* avoid gcc warning */ + } + +/* + * lcl_tend - allocate any tended variables needed in this body or inline + * statement. + */ +static void lcl_tend(n) +struct node *n; + { + struct sym_entry *sym; + + if (n == NULL) + return; + + /* + * Walk the syntax tree until a block with declarations is found. + */ + switch (n->nd_id) { + case PrefxNd: + case PstfxNd: + case PreSpcNd: + lcl_tend(n->u[0].child); + break; + case BinryNd: + case LstNd: + case ConCatNd: + case CommaNd: + case StrDclNd: + lcl_tend(n->u[0].child); + lcl_tend(n->u[1].child); + break; + case CompNd: + /* + * Allocate the tended variables in this block, noting that the + * level of nesting in this C function is one less than in the + * operation as a whole. Then mark the tended slots as free for + * use in the next block. + */ + for (sym = n->u[1].sym; sym != NULL; sym = sym->u.tnd_var.next) { + sym->t_indx = alloc_tnd(sym->id_type, sym->u.tnd_var.init, + sym->nest_lvl - 1); + } + lcl_tend(n->u[2].child); + sym = n->u[1].sym; + if (sym != NULL) + unuse(tend_lst, sym->nest_lvl - 1); + break; + case TrnryNd: + lcl_tend(n->u[0].child); + lcl_tend(n->u[1].child); + lcl_tend(n->u[2].child); + break; + case QuadNd: + lcl_tend(n->u[0].child); + lcl_tend(n->u[1].child); + lcl_tend(n->u[2].child); + lcl_tend(n->u[3].child); + break; + } + } + +/* + * chkrettyp - check type of return to see if it is a C integer or a + * C double and make note of what is found. + */ +static void chkrettyp(n) +struct node *n; + { + if (n->nd_id == PrefxNd && n->tok != NULL) { + switch (n->tok->tok_id) { + case C_Integer: + body_ret |= RetInt; + return; + case C_Double: + body_ret |= RetDbl; + return; + } + } + body_ret |= RetOther; + } + +/* + * body_fnc - produce the function which implements a body statement. + */ +static struct il_code *body_fnc(n) +struct node *n; + { + struct node *compound; + struct node *dcls; + struct node *stmts; + struct var_lst *var_ref; + struct sym_entry *sym; + struct il_code *il; + int fall_thru; /* flag: control can fall through end of body */ + int num_sigs; /* number of different signals function may return */ + int bprm_indx; + int first; + int is_reg; + int strct; + int addr; + int by_ref; + int just_desc; + int dummy_int; + char buf1[6]; + + char *cname; + char buf[MaxPath]; + + /* + * Figure out the next character to use as the 3rd prefix for the + * name of this body function. + */ + if (prfx3 == ' ') + prfx3 = '0'; + else if (prfx3 == '9') + prfx3 = 'a'; + else if (prfx3 == 'z') + errt2(n->tok, "more than 26 body statements in", cur_impl->name); + else + ++prfx3; + + /* + * Free any old body parameters and tended locations. + */ + while (body_prms != NULL) { + var_ref = body_prms; + body_prms = body_prms->next; + free((char *)var_ref); + } + free_tend(); + + /* + * Locate the outer declarations and statements from the body clause. + */ + compound = n->u[0].child; + dcls = compound->u[0].child; + stmts = compound->u[2].child; + + /* + * Analyze the body code to determine what the function's interface + * needs. body_anlz() does the work after the counters and flags + * are initialized. + */ + n_tmp_str = 0; /* number of temporary string buffers neeeded */ + n_tmp_cset = 0; /* number of temporary cset buffers needed */ + nxt_sbuf = 0; /* next string buffer index; used in code generation */ + nxt_cbuf = 0; /* next cset buffer index; used in code generation */ + n_bdy_prms = 0; /* number of variables needed as body function parameters */ + body_ret = 0; /* flag: C values and/or non-C values returned */ + ret_flag = 0; /* flag: return, suspend, fail, error fail */ + rslt_loc = 0; /* flag: body code needs operations result location */ + fall_thru = body_anlz(compound, &dummy_int, 0, 0, 1); + lcl_tend(n); /* allocate tended descriptors needed */ + + + /* + * Use the letter indicating operation type along with body function + * prefixes to construct the name of the file to hold the C code. + */ + sprintf(buf1, "%c_%c%c%c", lc_letter, prfx1, prfx2, prfx3); + 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 */ + + /* + * If the function produces a unique signal, the function need not actually + * return it, and we may be able to use the return value for something + * else. See if this is true. + */ + num_sigs = 0; + if (ret_flag & DoesRet) + ++num_sigs; + if (ret_flag & (DoesFail | DoesEFail)) + ++num_sigs; + if (ret_flag & DoesSusp) + num_sigs += 2; /* something > 1 (success cont. may return anything) */ + if (fall_thru) { + ret_flag |= DoesFThru; + ++num_sigs; + } + + if (num_sigs > 1) + fnc_ret = RetSig; /* Function must return a signal */ + else { + /* + * If the body returns a C_integer or a C_double, we can make the + * function directly return the C value and the compiler can decide + * whether to construct a descriptor. + */ + if (body_ret == RetInt || body_ret == RetDbl) + fnc_ret = body_ret; + else + fnc_ret = RetNoVal; /* Function returns nothing directly */ + } + + /* + * Decide whether the function needs to to be passed an explicit result + * location (the case where "result" is explicitly referenced is handled + * while analyzing the body). suspend always uses the result location. + * return uses the result location unless the function directly + * returns a C value. + */ + if (ret_flag & DoesSusp) + rslt_loc = 1; + else if ((ret_flag & DoesRet) && (fnc_ret != RetInt && fnc_ret != RetDbl)) + rslt_loc = 1; + + /* + * The data base entry for the call to the body function has 8 slots + * for standard interface information and 2 slots for each parameter. + */ + il = new_il(IL_Call, 8 + 2 * n_bdy_prms); + il->u[0].n = 0; /* reserved for internal use by compiler */ + il->u[1].n = prfx3; + il->u[2].n = fnc_ret; + il->u[3].n = ret_flag; + il->u[4].n = rslt_loc; + il->u[5].n = 0; /* number of string buffers to pass in: set below */ + il->u[6].n = 0; /* number of cset buffers to pass in: set below */ + il->u[7].n = n_bdy_prms; + bprm_indx = 8; + + /* + * Write the C function header for the body function. + */ + switch (fnc_ret) { + case RetSig: + fprintf(out_file, "int "); + break; + case RetInt: + fprintf(out_file, "C_integer "); + break; + case RetDbl: + fprintf(out_file, "double "); + break; + case RetNoVal: + fprintf(out_file, "void "); + break; + } + fprintf(out_file, " %c%c%c%c_%s(", uc_letter, prfx1, prfx2, prfx3, + cur_impl->name); + fname = cname; + line = 7; + + /* + * Write parameter list, first the parenthesized list of names. Start + * with names of RLT variables that must be passed in. + */ + first = 1; + for (var_ref = body_prms; var_ref != NULL; var_ref = var_ref->next) { + sym = var_ref->sym; + sym->id_type &= ~PrmMark; /* unmark entry */ + if (first) + first = 0; + else + prt_str(", ", IndentInc); + prt_str(sym->image, IndentInc); + } + + if (fall_thru) { + /* + * We cannot allocate string and cset buffers locally, so any + * that are needed must be parameters. + */ + if (n_tmp_str > 0) { + if (first) + first = 0; + else + prt_str(", ", IndentInc); + prt_str("r_sbuf", IndentInc); + } + if (n_tmp_cset > 0) { + if (first) + first = 0; + else + prt_str(", ", IndentInc); + prt_str("r_cbuf", IndentInc); + } + } + + /* + * If the result location is needed it is passed as the next parameter. + */ + if (rslt_loc) { + if (first) + first = 0; + else + prt_str(", ", IndentInc); + prt_str("r_rslt", IndentInc); + } + + /* + * If a success continuation is needed, it goes last. + */ + if (ret_flag & DoesSusp) { + if (!first) + prt_str(", ", IndentInc); + prt_str("r_s_cont", IndentInc); + } + prt_str(")", IndentInc); + ForceNl(); + + /* + * Go through the parameters to this function writing out declarations + * and filling in rest of data base entry. Start with RLT variables. + */ + for (var_ref = body_prms; var_ref != NULL; var_ref = var_ref->next) { + /* + * Each parameters has two slots in the data base entry. One + * is the declaration for use by iconc in producing function + * prototypes. The other is the argument that must be passed as + * part of the call generated by iconc. + * + * Determine whether the parameter is passed by reference or by + * value (flag by_ref). Tended variables that refer to just the + * vword of a descriptor require special handling. They must + * be passed to the body function as a pointer to the entire + * descriptor and not just the vword. Within the function the + * parameter is then accessed as x->vword... This is indicated + * by the parameter flag just_desc. + */ + sym = var_ref->sym; + var_ref->id_type = sym->id_type; /* save old id_type */ + by_ref = 0; + just_desc = 0; + switch (sym->id_type) { + case TndDesc: /* tended struct descrip x */ + by_ref = 1; + il->u[bprm_indx++].c_cd = simpl_dcl("dptr ", 0, sym); + break; + case TndStr: /* tended char *x */ + case TndBlk: /* tended struct b_??? *x or tended union block *x */ + by_ref = 1; + just_desc = 1; + il->u[bprm_indx++].c_cd = simpl_dcl("dptr ", 0, sym); + break; + case RtParm: /* undereferenced RTL parameter */ + case DrfPrm: /* dereferenced RTL parameter */ + switch (sym->u.param_info.cur_loc) { + case PrmTend: /* plain parameter: descriptor */ + by_ref = 1; + il->u[bprm_indx++].c_cd = simpl_dcl("dptr ", 0, sym); + break; + case PrmCStr: /* parameter converted to a tended C string */ + by_ref = 1; + just_desc = 1; + il->u[bprm_indx++].c_cd = simpl_dcl("dptr ", 0, sym); + break; + case PrmInt: /* parameter converted to a C integer */ + sym->id_type = OtherDcl; + if (var_ref->sym->may_mod && fall_thru) + by_ref = 1; + il->u[bprm_indx++].c_cd = simpl_dcl("C_integer ", by_ref, + sym); + break; + case PrmDbl: /* parameter converted to a C double */ + sym->id_type = OtherDcl; + if (var_ref->sym->may_mod && fall_thru) + by_ref = 1; + il->u[bprm_indx++].c_cd = simpl_dcl("double ", by_ref, sym); + break; + } + break; + case RtParm | VarPrm: + case DrfPrm | VarPrm: + /* + * Variable part of RTL parameter list: already descriptor pointer. + */ + sym->id_type = OtherDcl; + il->u[bprm_indx++].c_cd = simpl_dcl("dptr ", 0, sym); + break; + case VArgLen: + /* + * Number of elements in variable part of RTL parameter list: + * integer but not a true variable. + */ + sym->id_type = OtherDcl; + il->u[bprm_indx++].c_cd = simpl_dcl("int ", 0, sym); + break; + case OtherDcl: + is_reg = 0; + /* + * Pass by reference if it is a structure or union type (but + * not if it is a pointer to one) or if the variable is + * modified and it is possible to execute more code after the + * body. WARNING: crude assumptions are made for typedef + * types. + */ + strct = strct_typ(sym->u.declare_var.tqual, &is_reg); + addr = is_addr(sym->u.declare_var.dcltor, '\0'); + if ((strct && !addr) || (var_ref->sym->may_mod && fall_thru)) + by_ref = 1; + if (is_reg && by_ref) + errt2(sym->u.declare_var.dcltor->u[1].child->tok, sym->image, + " may not be declared 'register'"); + + il->u[bprm_indx++].c_cd = parm_dcl(by_ref, sym); + break; + } + + /* + * Determine what the iconc generated argument in a function + * call should look like. + */ + il->u[bprm_indx++].c_cd = bdy_prm(by_ref, just_desc, sym, + var_ref->sym->may_mod); + + /* + * If it a call-by-reference parameter, indicate that the level + * of indirection must be taken into account within the function + * body. + */ + if (by_ref) + sym->id_type |= ByRef; + } + + if (fall_thru) { + /* + * Write declarations for any needed buffer parameters. + */ + if (n_tmp_str > 0) { + prt_str("char (*r_sbuf)[MaxCvtLen];", 0); + ForceNl(); + } + if (n_tmp_cset > 0) { + prt_str("struct b_cset *r_cbuf;", 0); + ForceNl(); + } + /* + * Indicate that buffers must be allocated by compiler and not + * within the function. + */ + il->u[5].n = n_tmp_str; + il->u[6].n = n_tmp_cset; + n_tmp_str = 0; + n_tmp_cset = 0; + } + + /* + * Write declarations for result location and success continuation + * parameters if they are needed. + */ + if (rslt_loc) { + prt_str("dptr r_rslt;", 0); + ForceNl(); + } + if (ret_flag & DoesSusp) { + prt_str("continuation r_s_cont;", 0); + ForceNl(); + } + + /* + * Output the code for the function including ordinary declaration, + * special declarations, and executable code. + */ + prt_str("{", IndentInc); + ForceNl(); + c_walk(dcls, IndentInc, 0); + spcl_dcls(NULL); + c_walk(stmts, IndentInc, 0); + ForceNl(); + /* + * If it is possible for excution to fall through to the end of + * the body function, and it does so, return an A_FallThru signal. + */ + if (fall_thru) { + if (tend_lst != NULL) { + prt_str("tend = tend->previous;", IndentInc); + ForceNl(); + } + if (fnc_ret == RetSig) { + prt_str("return A_FallThru;", IndentInc); + ForceNl(); + } + } + prt_str("}\n", IndentInc); + if (fclose(out_file) != 0) + err2("cannot close ", cname); + put_c_fl(cname, 1); + + /* + * Restore the symbol table to its previous state. Note any parameters + * that were modified by the body code. + */ + for (var_ref = body_prms; var_ref != NULL; var_ref = var_ref->next) { + sym = var_ref->sym; + sym->id_type = var_ref->id_type; + if (sym->id_type & DrfPrm) + sym->u.param_info.parm_mod |= sym->may_mod; + sym->may_mod = 0; + } + + if (!fall_thru) + clr_prmloc(); + return il; + } + +/* + * strct_typ - determine if the declaration may be for a structured type + * and look for register declarations. + */ +static int strct_typ(typ, is_reg) +struct node *typ; +int *is_reg; + { + if (typ->nd_id == LstNd) { + return strct_typ(typ->u[0].child, is_reg) | + strct_typ(typ->u[1].child, is_reg); + } + else if (typ->nd_id == PrimryNd) { + switch (typ->tok->tok_id) { + case Typedef: + case Extern: + errt2(typ->tok, "declare {...} should not contain ", + typ->tok->image); + case TokRegister: + *is_reg = 1; + return 0; + case TypeDefName: + if (strcmp(typ->tok->image, "word") == 0 || + strcmp(typ->tok->image, "uword") == 0 || + strcmp(typ->tok->image, "dptr") == 0) + return 0; /* assume non-structure type */ + else + return 1; /* might be a structure (is not C_integer) */ + default: + return 0; + } + } + else { + /* + * struct, union, or enum. + */ + return 1; + } + } + +/* + * determine if the variable being declared evaluates to an address. + */ +static int is_addr(dcltor, modifier) +struct node *dcltor; +int modifier; + { + switch (dcltor->nd_id) { + case ConCatNd: + /* + * pointer? + */ + if (dcltor->u[0].child != NULL) + modifier = '*'; + return is_addr(dcltor->u[1].child, modifier); + case PrimryNd: + /* + * We have reached the name. + */ + switch (modifier) { + case '\0': + return 0; + case '*': + case '[': + return 1; + case ')': + errt1(dcltor->tok, + "declare {...} should not contain a prototype"); + } + case PrefxNd: + /* + * (...) + */ + return is_addr(dcltor->u[0].child, modifier); + case BinryNd: + /* + * function or array. + */ + return is_addr(dcltor->u[0].child, dcltor->tok->tok_id); + } + err1("rtt internal error detected in function is_addr()"); + /* NOTREACHED */ + return 0; /* avoid gcc warning */ + } + +/* + * chgn_ploc - if this is an "in-place" conversion to a C value, change + * the "location" of the parameter being converted. + */ +static void chng_ploc(typcd, src) +int typcd; +struct node *src; + { + int loc; + + /* + * Note, we know this is a valid conversion, because it got through + * pass 1. + */ + loc = PrmTend; + switch (typcd) { + case TypCInt: + case TypECInt: + loc = PrmInt; + break; + case TypCDbl: + loc = PrmDbl; + break; + case TypCStr: + loc = PrmCStr; + break; + } + if (loc != PrmTend) + src->u[0].sym->u.param_info.cur_loc = loc; + } + +/* + * cnt_bufs - See if we need to allocate a string or cset buffer for + * this conversion. + */ +static void cnt_bufs(cnv_typ) +struct node *cnv_typ; + { + if (cnv_typ->nd_id == PrimryNd) + switch (cnv_typ->tok->tok_id) { + case Tmp_string: + ++n_tmp_str; + break; + case Tmp_cset: + ++n_tmp_cset; + break; + } + } + +/* + * mrg_abstr - merge (join) types of abstract returns on two execution paths. + * The type lattice has three levels: NoAbstr is bottom, SomeType is top, + * and individual types form the middle level. + */ +static int mrg_abstr(sum, typ) +int sum; +int typ; + { + if (sum == NoAbstr) + return typ; + else if (typ == NoAbstr) + return sum; + else if (sum == typ) + return sum; + else + return SomeType; + } +#endif /* Rttx */ diff --git a/src/rtt/rttlex.c b/src/rtt/rttlex.c new file mode 100644 index 0000000..3e100bc --- /dev/null +++ b/src/rtt/rttlex.c @@ -0,0 +1,356 @@ +/* + * This lexical analyzer uses the preprocessor to convert text into tokens. + * The lexical anayser discards white space, checks to see if identifiers + * are reserved words or typedef names, makes sure single characters + * are valid tokens, and converts preprocessor constants into the + * various C constants. + */ +#include "rtt.h" + +/* + * Prototype for static function. + */ +static int int_suffix (char *s); + +int lex_state = DfltLex; + +char *ident = "ident"; + +/* + * Characters are used as token id's for single character tokens. The + * following table indicates which ones can be valid for RTL. + */ + +#define GoodChar(c) ((c) < 127 && good_char[c]) +static int good_char[128] = { + 0 /* \000 */, 0 /* \001 */, 0 /* \002 */, 0 /* \003 */, + 0 /* \004 */, 0 /* \005 */, 0 /* \006 */, 0 /* \007 */, + 0 /* \b */, 0 /* \t */, 0 /* \n */, 0 /* \v */, + 0 /* \f */, 0 /* \r */, 0 /* \016 */, 0 /* \017 */, + 0 /* \020 */, 0 /* \021 */, 0 /* \022 */, 0 /* \023 */, + 0 /* \024 */, 0 /* \025 */, 0 /* \026 */, 0 /* \027 */, + 0 /* \030 */, 0 /* \031 */, 0 /* \032 */, 0 /* \e */, + 0 /* \034 */, 0 /* \035 */, 0 /* \036 */, 0 /* \037 */, + 0 /* */, 1 /* ! */, 0 /* \ */, 0 /* # */, + 0 /* $ */, 1 /* % */, 1 /* & */, 0 /* ' */, + 1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */, + 1 /* , */, 1 /* - */, 1 /* . */, 1 /* / */, + 0 /* 0 */, 0 /* 1 */, 0 /* 2 */, 0 /* 3 */, + 0 /* 4 */, 0 /* 5 */, 0 /* 6 */, 0 /* 7 */, + 0 /* 8 */, 0 /* 9 */, 1 /* : */, 1 /* ; */, + 1 /* < */, 1 /* = */, 1 /* > */, 1 /* ? */, + 0 /* @ */, 0 /* A */, 0 /* B */, 0 /* C */, + 0 /* D */, 0 /* E */, 0 /* F */, 0 /* G */, + 0 /* H */, 0 /* I */, 0 /* J */, 0 /* K */, + 0 /* L */, 0 /* M */, 0 /* N */, 0 /* O */, + 0 /* P */, 0 /* Q */, 0 /* R */, 0 /* S */, + 0 /* T */, 0 /* U */, 0 /* V */, 0 /* W */, + 0 /* X */, 0 /* Y */, 0 /* Z */, 1 /* [ */, + 1 /* \\ */, 1 /* ] */, 1 /* ^ */, 0 /* _ */, + 0 /* ` */, 0 /* a */, 0 /* b */, 0 /* c */, + 0 /* d */, 0 /* e */, 0 /* f */, 0 /* g */, + 0 /* h */, 0 /* i */, 0 /* j */, 0 /* k */, + 0 /* l */, 0 /* m */, 0 /* n */, 0 /* o */, + 0 /* p */, 0 /* q */, 0 /* r */, 0 /* s */, + 0 /* t */, 0 /* u */, 0 /* v */, 0 /* w */, + 0 /* x */, 0 /* y */, 0 /* z */, 1 /* { */, + 1 /* | */, 1 /* } */, 1 /* ~ */, 0 /* \d */ + }; + +/* + * init_lex - initialize lexical analyzer. + */ +void init_lex() + { + struct sym_entry *sym; + int i; + static int first_time = 1; + + if (first_time) { + first_time = 0; + ident = spec_str(ident); /* install ident in string table */ + /* + * install C keywords into the symbol table + */ + sym_add(Auto, spec_str("auto"), OtherDcl, 0); + sym_add(Break, spec_str("break"), OtherDcl, 0); + sym_add(Case, spec_str("case"), OtherDcl, 0); + sym_add(TokChar, spec_str("char"), OtherDcl, 0); + sym_add(Const, spec_str("const"), OtherDcl, 0); + sym_add(Continue, spec_str("continue"), OtherDcl, 0); + sym_add(Default, spec_str("default"), OtherDcl, 0); + sym_add(Do, spec_str("do"), OtherDcl, 0); + sym_add(Doubl, spec_str("double"), OtherDcl, 0); + sym_add(Else, spec_str("else"), OtherDcl, 0); + sym_add(TokEnum, spec_str("enum"), OtherDcl, 0); + sym_add(Extern, spec_str("extern"), OtherDcl, 0); + sym_add(Float, spec_str("float"), OtherDcl, 0); + sym_add(For, spec_str("for"), OtherDcl, 0); + sym_add(Goto, spec_str("goto"), OtherDcl, 0); + sym_add(If, spec_str("if"), OtherDcl, 0); + sym_add(Int, spec_str("int"), OtherDcl, 0); + sym_add(TokLong, spec_str("long"), OtherDcl, 0); + sym_add(TokRegister, spec_str("register"), OtherDcl, 0); + sym_add(Return, spec_str("return"), OtherDcl, 0); + sym_add(TokShort, spec_str("short"), OtherDcl, 0); + sym_add(Signed, spec_str("signed"), OtherDcl, 0); + sym_add(Sizeof, spec_str("sizeof"), OtherDcl, 0); + sym_add(Static, spec_str("static"), OtherDcl, 0); + sym_add(Struct, spec_str("struct"), OtherDcl, 0); + sym_add(Switch, spec_str("switch"), OtherDcl, 0); + sym_add(Typedef, spec_str("typedef"), OtherDcl, 0); + sym_add(Union, spec_str("union"), OtherDcl, 0); + sym_add(Unsigned, spec_str("unsigned"), OtherDcl, 0); + sym_add(Void, spec_str("void"), OtherDcl, 0); + sym_add(Volatile, spec_str("volatile"), OtherDcl, 0); + sym_add(While, spec_str("while"), OtherDcl, 0); + + /* + * Install keywords from run-time interface language. + */ + sym_add(Abstract, spec_str("abstract"), OtherDcl, 0); + sym_add(All_fields, spec_str("all_fields"), OtherDcl, 0); + sym_add(Any_value, spec_str("any_value"), OtherDcl, 0); + sym_add(Arith_case, spec_str("arith_case"), OtherDcl, 0); + sym_add(Body, spec_str("body"), OtherDcl, 0); + sym_add(C_Double, spec_str("C_double"), OtherDcl, 0); + sym_add(C_Integer, spec_str("C_integer"), OtherDcl, 0); + sym_add(C_String, spec_str("C_string"), OtherDcl, 0); + sym_add(Cnv, spec_str("cnv"), OtherDcl, 0); + sym_add(Constant, spec_str("constant"), OtherDcl, 0); + sym_add(Declare, spec_str("declare"), OtherDcl, 0); + sym_add(Def, spec_str("def"), OtherDcl, 0); + sym_add(Empty_type, spec_str("empty_type"), OtherDcl, 0); + sym_add(End, spec_str("end"), OtherDcl, 0); + sym_add(Errorfail, spec_str("errorfail"), OtherDcl, 0); + sym_add(Exact, spec_str("exact"), OtherDcl, 0); + sym_add(Fail, spec_str("fail"), OtherDcl, 0); + sym_add(TokFunction, spec_str("function"), OtherDcl, 0); + sym_add(Inline, spec_str("inline"), OtherDcl, 0); + sym_add(Is, spec_str("is"), OtherDcl, 0); + sym_add(Keyword, spec_str("keyword"), OtherDcl, 0); + sym_add(Len_case, spec_str("len_case"), OtherDcl, 0); + sym_add(Named_var, spec_str("named_var"), OtherDcl, 0); + sym_add(New, spec_str("new"), OtherDcl, 0); + sym_add(Of, spec_str("of"), OtherDcl, 0); + sym_add(Operator, spec_str("operator"), OtherDcl, 0); + str_rslt = spec_str("result"); + sym_add(Runerr, spec_str("runerr"), OtherDcl, 0); + sym_add(Store, spec_str("store"), OtherDcl, 0); + sym_add(Struct_var, spec_str("struct_var"), OtherDcl, 0); + sym_add(Suspend, spec_str("suspend"), OtherDcl, 0); + sym_add(Tended, spec_str("tended"), OtherDcl, 0); + sym_add(Then, spec_str("then"), OtherDcl, 0); + sym_add(Tmp_cset, spec_str("tmp_cset"), OtherDcl, 0); + sym_add(Tmp_string, spec_str("tmp_string"), OtherDcl, 0); + sym_add(TokType, spec_str("type"), OtherDcl, 0); + sym_add(Type_case, spec_str("type_case"), OtherDcl, 0); + sym_add(Underef, spec_str("underef"), OtherDcl, 0); + sym_add(Variable, spec_str("variable"), OtherDcl, 0); + + for (i = 0; i < num_typs; ++i) { + icontypes[i].id = spec_str(icontypes[i].id); + sym = sym_add(IconType, icontypes[i].id, OtherDcl, 0); + sym->u.typ_indx = i; + } + + for (i = 0; i < num_cmpnts; ++i) { + typecompnt[i].id = spec_str(typecompnt[i].id); + sym = sym_add(Component, typecompnt[i].id, OtherDcl, 0); + sym->u.typ_indx = i; + } + } + } + +/* + * int_suffix - we have reached the end of what seems to be an integer + * constant. check for a valid suffix. + */ +static int int_suffix(s) +char *s; + { + int tok_id; + + if (*s == 'u' || *s == 'U') { + ++s; + if (*s == 'l' || *s == 'L') { + ++s; + tok_id = ULIntConst; /* unsigned long */ + } + else + tok_id = UIntConst; /* unsigned */ + } + else if (*s == 'l' || *s == 'L') { + ++s; + if (*s == 'u' || *s == 'U') { + ++s; + tok_id = ULIntConst; /* unsigned long */ + } + else + tok_id = LIntConst; /* long */ + } + else + tok_id = IntConst; /* plain int */ + if (*s != '\0') + errt2(yylval.t, "invalid integer constant: ", yylval.t->image); + return tok_id; + } + +/* + * yylex - lexical analyzer, called by yacc-generated parser. + */ +int yylex() + { + register char *s; + struct sym_entry *sym; + struct token *lk_ahead = NULL; + int is_float; + struct str_buf *sbuf; + + /* + * See if the last call to yylex() left a token from looking ahead. + */ + if (lk_ahead == NULL) + yylval.t = preproc(); + else { + yylval.t = lk_ahead; + lk_ahead = NULL; + } + + /* + * Skip white space, then check for end-of-input. + */ + while (yylval.t != NULL && yylval.t->tok_id == WhiteSpace) { + free_t(yylval.t); + yylval.t = preproc(); + } + if (yylval.t == NULL) + return 0; + + /* + * The rtt recognizes ** as an operator in abstract type computations. + * The parsing context is indicated by lex_state. + */ + if (lex_state == TypeComp && yylval.t->tok_id == '*') { + lk_ahead = preproc(); + if (lk_ahead != NULL && lk_ahead->tok_id == '*') { + free_t(lk_ahead); + lk_ahead = NULL; + yylval.t->tok_id = Intersect; + yylval.t->image = spec_str("**"); + } + } + + /* + * Some tokens are passed along without change, but some need special + * processing: identifiers, numbers, PpKeep tokens, and single + * character tokens. + */ + if (yylval.t->tok_id == Identifier) { + /* + * See if this is an identifier, a reserved word, or typedef name. + */ + sym = sym_lkup(yylval.t->image); + if (sym != NULL) + yylval.t->tok_id = sym->tok_id; + } + else if (yylval.t->tok_id == PpNumber) { + /* + * Determine what kind of numeric constant this is. + */ + s = yylval.t->image; + if (*s == '0' && (*++s == 'x' || *s == 'X')) { + /* + * Hex integer constant. + */ + ++s; + while (isxdigit(*s)) + ++s; + yylval.t->tok_id = int_suffix(s); + } + else { + is_float = 0; + while (isdigit(*s)) + ++s; + if (*s == '.') { + is_float = 1; + ++s; + while (isdigit(*s)) + ++s; + } + if (*s == 'e' || *s == 'E') { + is_float = 1; + ++s; + if (*s == '+' || *s == '-') + ++s; + while (isdigit(*s)) + ++s; + } + if (is_float) { + switch (*s) { + case '\0': + yylval.t->tok_id = DblConst; /* double */ + break; + case 'f': case 'F': + yylval.t->tok_id = FltConst; /* float */ + break; + case 'l': case 'L': + yylval.t->tok_id = LDblConst; /* long double */ + break; + default: + errt2(yylval.t, "invalid float constant: ", yylval.t->image); + } + } + else { + /* + * This appears to be an integer constant. If it starts + * with '0', it should be an octal constant. + */ + if (yylval.t->image[0] == '0') { + s = yylval.t->image; + while (*s >= '0' && *s <= '7') + ++s; + } + yylval.t->tok_id = int_suffix(s); + } + } + } + else if (yylval.t->tok_id == PpKeep) { + /* + * This is a non-standard preprocessor directive that must be + * passed on to the output. + */ + keepdir(yylval.t); + return yylex(); + } + else if (lex_state == OpHead && yylval.t->tok_id != '}' && + GoodChar((int)yylval.t->image[0])) { + /* + * This should be the operator symbol in the header of an operation + * declaration. Concatenate all operator symbols into one token + * of type OpSym. + */ + sbuf = get_sbuf(); + for (s = yylval.t->image; *s != '\0'; ++s) + AppChar(*sbuf, *s); + lk_ahead = preproc(); + while (lk_ahead != NULL && GoodChar((int)lk_ahead->image[0])) { + for (s = lk_ahead->image; *s != '\0'; ++s) + AppChar(*sbuf, *s); + free_t(lk_ahead); + lk_ahead = preproc(); + } + yylval.t->tok_id = OpSym; + yylval.t->image = str_install(sbuf); + rel_sbuf(sbuf); + } + else if (yylval.t->tok_id < 256) { + /* + * This is a one-character token, make sure it is valid. + */ + if (!GoodChar(yylval.t->tok_id)) + errt2(yylval.t, "invalid character: ", yylval.t->image); + } + + return yylval.t->tok_id; + } diff --git a/src/rtt/rttmain.c b/src/rtt/rttmain.c new file mode 100644 index 0000000..2099c2f --- /dev/null +++ b/src/rtt/rttmain.c @@ -0,0 +1,402 @@ +#include "rtt.h" + +/* + * prototypes for static functions. + */ +static void add_tdef (char *name); + +/* + * refpath is used to locate the standard include files for the Icon + * run-time system. If patchpath has been patched in the binary of rtt, + * the string that was patched in is used for refpath. + */ +char *refpath; +char patchpath[MaxPath+18] = "%PatchStringHere->"; + +static char *ostr = "+ECPD:I:U:d:cir:st:x"; + +static char *options = + "[-E] [-C] [-P] [-Dname[=[text]]] [-Uname] [-Ipath] [-dfile]\n \ +[-rpath] [-tname] [-x] [files]"; + +/* + * The relative path to grttin.h and rt.h depends on whether they are + * interpreted as relative to where rtt.exe is or where rtt.exe is + * invoked. + */ + char *grttin_path = "../src/h/grttin.h"; + char *rt_path = "../src/h/rt.h"; + +/* + * Note: rtt presently does not process system include files. If this + * is needed, it may be necessary to add other options that set + * manifest constants in such include files. See pmain.c for the + * stand-alone preprocessor for examples of what's needed. + */ + +char *progname = "rtt"; +char *compiler_def; +FILE *out_file; +char *inclname; +int def_fnd; +char *largeints = NULL; + +int iconx_flg = 0; +int enable_out = 0; + +static char *curlst_nm = "rttcur.lst"; +static FILE *curlst; +static char *cur_src; + +extern int line_cntrl; + +/* + * tdefnm is used to construct a list of identifiers that + * must be treated by rtt as typedef names. + */ +struct tdefnm { + char *name; + struct tdefnm *next; + }; + +static char *dbname = "rt.db"; +static int pp_only = 0; +static char *opt_lst; +static char **opt_args; +static char *in_header; +static struct tdefnm *tdefnm_lst = NULL; + +/* + * getopt() variables + */ +extern int optind; /* index into parent argv vector */ +extern int optopt; /* character checked for validity */ +extern char *optarg; /* argument associated with option */ + +int main(argc, argv) +int argc; +char **argv; + { + int c; + int nopts; + char buf[MaxPath]; /* file name construction buffer */ + struct fileparts *fp; + + /* + * See if the location of include files has been patched into the + * rtt executable. + */ + if ((int)strlen(patchpath) > 18) + refpath = patchpath+18; + else + refpath = relfile(argv[0], "/../"); + + /* + * Initialize the string table and indicate that File must be treated + * as a typedef name. + */ + init_str(); + add_tdef("FILE"); + + /* + * By default, the spelling of white space in unimportant (it can + * only be significant with the -E option) and #line directives + * are required in the output. + */ + whsp_image = NoSpelling; + line_cntrl = 1; + + /* + * opt_lst and opt_args are the options and corresponding arguments + * that are passed along to the preprocessor initialization routine. + * Their number is at most the number of arguments to rtt. + */ + opt_lst = alloc(argc); + opt_args = alloc(argc * sizeof (char *)); + nopts = 0; + + /* + * Process options. + */ + while ((c = getopt(argc, argv, ostr)) != EOF) + switch (c) { + case 'E': /* run preprocessor only */ + pp_only = 1; + if (whsp_image == NoSpelling) + whsp_image = NoComment; + break; + case 'C': /* retain spelling of white space, only effective with -E */ + whsp_image = FullImage; + break; + case 'P': /* do not produce #line directives in output */ + line_cntrl = 0; + break; + case 'd': /* -d name: name of data base */ + dbname = optarg; + break; + case 'r': /* -r path: location of include files */ + refpath = optarg; + break; + case 't': /* -t ident : treat ident as a typedef name */ + add_tdef(optarg); + break; + case 'x': /* produce code for interpreter rather than compiler */ + iconx_flg = 1; + break; + + case 'D': /* define preprocessor symbol */ + case 'I': /* path to search for preprocessor includes */ + case 'U': /* undefine preprocessor symbol */ + /* + * Save these options for the preprocessor initialization routine. + */ + opt_lst[nopts] = c; + opt_args[nopts] = optarg; + ++nopts; + break; + default: + show_usage(); + } + + #ifdef Rttx + if (!iconx_flg) { + fprintf(stdout, + "rtt was compiled to only support the intepreter, use -x\n"); + exit(EXIT_FAILURE); + } + #endif /* Rttx */ + + if (iconx_flg) + compiler_def = "#define COMPILER 0\n"; + else + compiler_def = "#define COMPILER 1\n"; + in_header = alloc(strlen(refpath) + strlen(grttin_path) + 1); + strcpy(in_header, refpath); + strcat(in_header, grttin_path); + inclname = alloc(strlen(refpath) + strlen(rt_path) + 1); + strcpy(inclname, refpath); + strcat(inclname, rt_path); + + opt_lst[nopts] = '\0'; + + /* + * At least one file name must be given on the command line. + */ + if (optind == argc) + show_usage(); + + /* + * When creating the compiler run-time system, rtt outputs a list + * of names of C files created, because most of the file names are + * not derived from the names of the input files. + */ + if (!iconx_flg) { + curlst = fopen(curlst_nm, "w"); + if (curlst == NULL) + err2("cannot open ", curlst_nm); + } + + /* + * Unless the input is only being preprocessed, set up the in-memory data + * base (possibly loading it from a file). + */ + if (!pp_only) { + fp = fparse(dbname); + if (*fp->ext == '\0') + dbname = salloc(makename(buf, SourceDir, dbname, DBSuffix)); + else if (!smatch(fp->ext, DBSuffix)) + err2("bad data base name:", dbname); + loaddb(dbname); + } + + /* + * Scan file name arguments, and translate the files. + */ + while (optind < argc) { + trans(argv[optind]); + optind++; + } + + #ifndef Rttx + /* + * Unless the user just requested the preprocessor be run, we + * have created C files and updated the in-memory data base. + * If this is the compiler's run-time system, we must dump + * to data base to a file and create a list of all output files + * produced in all runs of rtt that created the data base. + */ + if (!(pp_only || iconx_flg)) { + if (fclose(curlst) != 0) + err2("cannot close ", curlst_nm); + dumpdb(dbname); + full_lst("rttfull.lst"); + } + #endif /* Rttx */ + + return EXIT_SUCCESS; + } + +/* + * trans - translate a source file. + */ +void trans(src_file) +char *src_file; + { + char *cname; + char buf[MaxPath]; /* file name construction buffer */ + char *buf_ptr; + char *s; + struct fileparts *fp; + struct tdefnm *td; + struct token *t; + static char *test_largeints = "#ifdef LargeInts\nyes\n#endif\n"; + static int first_time = 1; + + cur_src = src_file; + + /* + * Read standard header file for preprocessor directives and + * typedefs, but don't write anything to output. + */ + enable_out = 0; + init_preproc(in_header, opt_lst, opt_args); + str_src("<rtt initialization>", compiler_def, (int)strlen(compiler_def)); + init_sym(); + for (td = tdefnm_lst; td != NULL; td = td->next) + sym_add(TypeDefName, td->name, OtherDcl, 1); + init_lex(); + yyparse(); + if (first_time) { + first_time = 0; + /* + * Now that the standard include files have been processed, see if + * Largeints is defined and make sure it matches what's in the data base. + */ + s = "NoLargeInts"; + str_src("<rtt initialization>", test_largeints, + (int)strlen(test_largeints)); + while ((t = preproc()) != NULL) + if (strcmp(t->image, "yes")) + s = "LargeInts"; + if (largeints == NULL) + largeints = s; + else if (strcmp(largeints, s) != 0) + err2("header file definition of LargeInts/NoLargeInts does not match ", + dbname); + } + enable_out = 1; + + /* + * Make sure we have a .r file or standard input. + */ + if (strcmp(cur_src, "-") == 0) { + source("-"); /* tell preprocessor to read standard input */ + cname = salloc(makename(buf, TargetDir, "stdin", CSuffix)); + } + else { + fp = fparse(cur_src); + if (*fp->ext == '\0') + cur_src = salloc(makename(buf, SourceDir, cur_src, RttSuffix)); + else if (!smatch(fp->ext, RttSuffix)) + err2("unknown file suffix ", cur_src); + cur_src = spec_str(cur_src); + + /* + * For the compiler, remove from the data base the list of + * files produced from this input file. + */ + if (!iconx_flg) + clr_dpnd(cur_src); + source(cur_src); /* tell preprocessor to read source file */ + + /* + * For the interpreter prepend "x" to the file name for the .c file. + */ + buf_ptr = buf; + if (iconx_flg) + *buf_ptr++ = 'x'; + makename(buf_ptr, TargetDir, cur_src, CSuffix); + cname = salloc(buf); + } + + if (pp_only) + output(stdout); /* invoke standard preprocessor output routine */ + else { + /* + * For the compiler, non-RTL code is put in a file whose name + * is derived from input file name. The flag def_fnd indicates + * if anything interesting is put in the file. + */ + def_fnd = 0; + 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 */ + yyparse(); /* translate the input */ + fprintf(out_file, "\n"); + if (fclose(out_file) != 0) + err2("cannot close ", cname); + + /* + * For the Compiler, note the name of the "primary" output file + * in the data base and list of created files. + */ + if (!iconx_flg) + put_c_fl(cname, def_fnd); + } + } + +/* + * add_tdef - add identifier to list of typedef names. + */ +static void add_tdef(name) +char *name; + { + struct tdefnm *td; + + td = NewStruct(tdefnm); + td->name = spec_str(name); + td->next = tdefnm_lst; + tdefnm_lst = td; + } + +/* + * Add name of file to the output list, and if it contains "interesting" + * code, add it to the dependency list in the data base. + */ +void put_c_fl(fname, keep) +char *fname; +int keep; + { + struct fileparts *fp; + + fp = fparse(fname); + fprintf(curlst, "%s\n", fp->name); + if (keep) + add_dpnd(src_lkup(cur_src), fname); + } + +/* + * Print an error message if called incorrectly. + */ +void show_usage() + { + fprintf(stderr, "usage: %s %s\n", progname, options); + exit(EXIT_FAILURE); + } + +/* + * yyerror - error routine called by yacc. + */ +void yyerror(s) +char *s; + { + struct token *t; + + t = yylval.t; + if (t == NULL) + err2(s, " at end of file"); + else + errt1(t, s); + } diff --git a/src/rtt/rttmisc.c b/src/rtt/rttmisc.c new file mode 100644 index 0000000..822970f --- /dev/null +++ b/src/rtt/rttmisc.c @@ -0,0 +1,114 @@ +#include "rtt.h" + +int n_tmp_str = 0; +int n_tmp_cset = 0; +struct sym_entry *params = NULL; + +/* + * clr_def - clear any information related to definitions. + */ +void clr_def() + { + struct sym_entry *sym; + + n_tmp_str = 0; + n_tmp_cset = 0; + while (params != NULL) { + sym = params; + params = params->u.param_info.next; + free_sym(sym); + } + free_tend(); + if (v_len != NULL) + free_sym(v_len); + v_len = NULL; + il_indx = 0; + lbl_num = 0; + abs_ret = SomeType; + } + +/* + * ttol - convert a token representing an integer constant into a long + * integer value. + */ +long ttol(t) +struct token *t; +{ + register long i; + register char *s; + int base; + + s = t->image; + i = 0; + base = 10; + + if (*s == '0') { + base = 8; + ++s; + if (*s == 'x') { + base = 16; + ++s; + } + } + while (*s != '\0') { + i *= base; + if (*s >= '0' && *s <= '9') + i += *s++ - '0'; + else if (*s >= 'a' && *s <= 'f') + i += *s++ - 'a' + 10; + else if (*s >= 'A' && *s <= 'F') + i += *s++ - 'A' + 10; + } + return i; + } + +struct token *chk_exct(tok) +struct token *tok; + { + struct sym_entry *sym; + + sym = sym_lkup(tok->image); + if (sym->u.typ_indx != int_typ) + errt2(tok, "exact conversions do not apply to ", tok->image); + return tok; + } + +/* + * icn_typ - convert a type node into a type code for the internal + * representation of the data base. + */ +int icn_typ(typ) +struct node *typ; + { + switch (typ->nd_id) { + case PrimryNd: + switch (typ->tok->tok_id) { + case Any_value: + return TypAny; + case Empty_type: + return TypEmpty; + case Variable: + return TypVar; + case C_Integer: + return TypCInt; + case C_Double: + return TypCDbl; + case C_String: + return TypCStr; + case Tmp_string: + return TypTStr; + case Tmp_cset: + return TypTCset; + } + + case SymNd: + return typ->u[0].sym->u.typ_indx; + + default: /* must be exact conversion */ + if (typ->tok->tok_id == C_Integer) + return TypECInt; + else /* integer */ + return TypEInt; + } + } + diff --git a/src/rtt/rttnode.c b/src/rtt/rttnode.c new file mode 100644 index 0000000..6064b7e --- /dev/null +++ b/src/rtt/rttnode.c @@ -0,0 +1,264 @@ +#include "rtt.h" + +/* + * node0 - create a syntax tree leaf node. + */ +struct node *node0(id, tok) +int id; +struct token *tok; + { + struct node *n; + + n = NewNode(0); + n->nd_id = id; + n->tok = tok; + return n; + } + +/* + * node1 - create a syntax tree node with one child. + */ +struct node *node1(id, tok, n1) +int id; +struct token *tok; +struct node *n1; + { + struct node *n; + + n = NewNode(1); + n->nd_id = id; + n->tok = tok; + n->u[0].child = n1; + return n; + } + +/* + * node2 - create a syntax tree node with two children. + */ +struct node *node2(id, tok, n1, n2) +int id; +struct token *tok; +struct node *n1; +struct node *n2; + { + struct node *n; + + n = NewNode(2); + n->nd_id = id; + n->tok = tok; + n->u[0].child = n1; + n->u[1].child = n2; + return n; + } + +/* + * node3 - create a syntax tree node with three children. + */ +struct node *node3(id, tok, n1, n2, n3) +int id; +struct token *tok; +struct node *n1; +struct node *n2; +struct node *n3; + { + struct node *n; + + n = NewNode(3); + n->nd_id = id; + n->tok = tok; + n->u[0].child = n1; + n->u[1].child = n2; + n->u[2].child = n3; + return n; + } + +/* + * node4 - create a syntax tree node with four children. + */ +struct node *node4(id, tok, n1, n2, n3, n4) +int id; +struct token *tok; +struct node *n1; +struct node *n2; +struct node *n3; +struct node *n4; + { + struct node *n; + + n = NewNode(4); + n->nd_id = id; + n->tok = tok; + n->u[0].child = n1; + n->u[1].child = n2; + n->u[2].child = n3; + n->u[3].child = n4; + return n; + } + +/* + * sym_node - create a syntax tree node for a variable. If the identifier + * is in the symbol table, create a node that references the entry, + * otherwise create a simple leaf node. + */ +struct node *sym_node(tok) +struct token *tok; + { + struct sym_entry *sym; + struct node *n; + + sym = sym_lkup(tok->image); + if (sym != NULL) { + n = NewNode(1); + n->nd_id = SymNd; + n->tok = tok; + n->u[0].sym = sym; + ++sym->ref_cnt; + /* + * If this is the result location of an operation, note that it + * is explicitly referenced. + */ + if (sym->id_type == RsltLoc) + sym->u.referenced = 1; + return n; + } + else + return node0(PrimryNd, tok); + } + +/* + * comp_nd - create a node for a compound statement. + */ +struct node *comp_nd(tok, dcls, stmts) +struct token *tok; +struct node *dcls; +struct node *stmts; + { + struct node *n; + + n = NewNode(3); + n->nd_id = CompNd; + n->tok = tok; + n->u[0].child = dcls; + n->u[1].sym = dcl_stk->tended; /* tended declarations are not in dcls */ + n->u[2].child = stmts; + return n; + } + +/* + * arith_nd - create a node for an arith_case statement. + */ +struct node *arith_nd(tok, p1, p2, c_int, ci_act, intgr, i_act, dbl, d_act) +struct token *tok; +struct node *p1; +struct node *p2; +struct node *c_int; +struct node *ci_act; +struct node *intgr; +struct node *i_act; +struct node *dbl; +struct node *d_act; + { + struct node *n; + + /* + * Insure the cases are what we expect. + */ + if (c_int->tok->tok_id != C_Integer) + errt3(c_int->tok, "expected \"C_integer\", found \"", c_int->tok->image, + "\""); + if (intgr->tok->image != icontypes[int_typ].id) + errt3(intgr->tok, "expected \"integer\", found \"", intgr->tok->image, + "\""); + if (dbl->tok->tok_id != C_Double) + errt3(dbl->tok, "expected \"C_double\", found \"", dbl->tok->image, + "\""); + + /* + * Indicate in the symbol table that the arguments are converted to C + * values. + */ + dst_alloc(c_int, p1); + dst_alloc(c_int, p2); + dst_alloc(dbl, p1); + dst_alloc(dbl, p2); + + free_tree(c_int); + free_tree(intgr); + free_tree(dbl); + + n = node3(TrnryNd, NULL, ci_act, i_act, d_act); + return node3(TrnryNd, tok, p1, p2, n); + } + +struct node *dest_node(tok) +struct token *tok; + { + struct node *n; + int typcd; + + n = sym_node(tok); + typcd = n->u[0].sym->u.typ_indx; + if (typcd != int_typ && typcd != str_typ && typcd != cset_typ && + typcd != real_typ) + errt2(tok, "cannot convert to ", tok->image); + return n; + } + + +/* + * free_tree - free storage for a syntax tree. + */ +void free_tree(n) +struct node *n; + { + struct sym_entry *sym, *sym1; + + if (n == NULL) + return; + + /* + * Free any subtrees and other referenced storage. + */ + switch (n->nd_id) { + case SymNd: + free_sym(n->u[0].sym); /* Indicate one less reference to symbol */ + break; + + case CompNd: + /* + * Compound node. Free ordinary declarations, tended declarations, + * and executable code. + */ + free_tree(n->u[0].child); + sym = n->u[1].sym; + while (sym != NULL) { + sym1 = sym; + sym = sym->u.tnd_var.next; + free_sym(sym1); + } + free_tree(n->u[2].child); + break; + + case QuadNd: + free_tree(n->u[3].child); + /* fall thru to next case */ + case TrnryNd: + free_tree(n->u[2].child); + /* fall thru to next case */ + case AbstrNd: case BinryNd: case CommaNd: case ConCatNd: case LstNd: + case StrDclNd: + free_tree(n->u[1].child); + /* fall thru to next case */ + case IcnTypNd: case PstfxNd: case PreSpcNd: case PrefxNd: + free_tree(n->u[0].child); + /* fall thru to next case */ + case ExactCnv: case PrimryNd: + break; + + default: + fprintf(stdout, "rtt internal error: unknown node type\n"); + exit(EXIT_FAILURE); + } + free_t(n->tok); /* free token */ + free((char *)n); + } 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); + } diff --git a/src/rtt/rttparse.c b/src/rtt/rttparse.c new file mode 100644 index 0000000..9f18ec1 --- /dev/null +++ b/src/rtt/rttparse.c @@ -0,0 +1,2992 @@ + +# line 7 "rttgram.y" +#include "rtt1.h" +#define YYMAXDEPTH 250 + +# line 11 "rttgram.y" +typedef union { + struct token *t; + struct node *n; + long i; + } YYSTYPE; +# define Identifier 257 +# define StrLit 258 +# define LStrLit 259 +# define FltConst 260 +# define DblConst 261 +# define LDblConst 262 +# define CharConst 263 +# define LCharConst 264 +# define IntConst 265 +# define UIntConst 266 +# define LIntConst 267 +# define ULIntConst 268 +# define Arrow 269 +# define Incr 270 +# define Decr 271 +# define LShft 272 +# define RShft 273 +# define Leq 274 +# define Geq 275 +# define TokEqual 276 +# define Neq 277 +# define And 278 +# define Or 279 +# define MultAsgn 280 +# define DivAsgn 281 +# define ModAsgn 282 +# define PlusAsgn 283 +# define MinusAsgn 284 +# define LShftAsgn 285 +# define RShftAsgn 286 +# define AndAsgn 287 +# define XorAsgn 288 +# define OrAsgn 289 +# define Sizeof 290 +# define Intersect 291 +# define OpSym 292 +# define Typedef 293 +# define Extern 294 +# define Static 295 +# define Auto 296 +# define TokRegister 297 +# define Tended 298 +# define TokChar 299 +# define TokShort 300 +# define Int 301 +# define TokLong 302 +# define Signed 303 +# define Unsigned 304 +# define Float 305 +# define Doubl 306 +# define Const 307 +# define Volatile 308 +# define Void 309 +# define TypeDefName 310 +# define Struct 311 +# define Union 312 +# define TokEnum 313 +# define Ellipsis 314 +# define Case 315 +# define Default 316 +# define If 317 +# define Else 318 +# define Switch 319 +# define While 320 +# define Do 321 +# define For 322 +# define Goto 323 +# define Continue 324 +# define Break 325 +# define Return 326 +# define Runerr 327 +# define Is 328 +# define Cnv 329 +# define Def 330 +# define Exact 331 +# define Empty_type 332 +# define IconType 333 +# define Component 334 +# define Variable 335 +# define Any_value 336 +# define Named_var 337 +# define Struct_var 338 +# define C_Integer 339 +# define Arith_case 340 +# define C_Double 341 +# define C_String 342 +# define Tmp_string 343 +# define Tmp_cset 344 +# define Body 345 +# define End 346 +# define TokFunction 347 +# define Keyword 348 +# define Operator 349 +# define Underef 350 +# define Declare 351 +# define Suspend 352 +# define Fail 353 +# define Inline 354 +# define Abstract 355 +# define Store 356 +# define TokType 357 +# define New 358 +# define All_fields 359 +# define Then 360 +# define Type_case 361 +# define Of 362 +# define Len_case 363 +# define Constant 364 +# define Errorfail 365 +# define IfStmt 366 +#define yyclearin yychar = -1 +#define yyerrok yyerrflag = 0 +extern int yychar; +extern int yyerrflag; +#ifndef YYMAXDEPTH +#define YYMAXDEPTH 150 +#endif +YYSTYPE yylval, yyval; +# define YYERRCODE 256 + +# line 1089 "rttgram.y" + + +/* + * xfree(p) -- used with free(p) macro to avoid compiler errors from + * miscast free calls generated by Yacc. + */ +static void xfree(p) +char *p; +{ + free(p); +} + +#define free(p) xfree((char*)p) +int yyexca[] ={ +-1, 0, + 0, 279, + 258, 299, + 347, 299, + 348, 299, + 349, 299, + -2, 193, +-1, 1, + 0, -1, + -2, 0, +-1, 2, + 0, 280, + 258, 299, + 347, 299, + 348, 299, + 349, 299, + -2, 193, +-1, 51, + 44, 113, + 59, 113, + -2, 290, +-1, 58, + 44, 115, + 59, 115, + -2, 289, +-1, 100, + 123, 166, + -2, 168, +-1, 138, + 125, 257, + 59, 86, + -2, 230, +-1, 238, + 125, 257, + 59, 86, + -2, 230, +-1, 239, + 125, 258, + 59, 86, + -2, 230, +-1, 255, + 58, 293, + -2, 1, +-1, 256, + 58, 294, + -2, 98, +-1, 262, + 59, 86, + -2, 230, +-1, 308, + 41, 212, + -2, 193, +-1, 371, + 41, 204, + 44, 204, + -2, 193, +-1, 396, + 59, 86, + -2, 230, +-1, 398, + 59, 86, + -2, 230, +-1, 452, + 41, 214, + 44, 214, + -2, 194, +-1, 516, + 59, 86, + -2, 230, +-1, 545, + 40, 193, + 91, 193, + -2, 219, +-1, 617, + 293, 219, + 294, 219, + 295, 219, + 296, 219, + 297, 219, + 299, 219, + 300, 219, + 301, 219, + 302, 219, + 303, 219, + 304, 219, + 305, 219, + 306, 219, + 307, 219, + 308, 219, + 309, 219, + 310, 219, + 311, 219, + 312, 219, + 313, 219, + 41, 219, + 339, 219, + 341, 219, + 342, 219, + -2, 193, +-1, 624, + 59, 86, + -2, 230, +-1, 625, + 59, 86, + -2, 230, +-1, 627, + 59, 86, + -2, 230, +-1, 677, + 59, 86, + -2, 230, +-1, 725, + 59, 86, + -2, 230, +-1, 730, + 58, 453, + -2, 317, +-1, 731, + 58, 454, + -2, 321, +-1, 732, + 58, 455, + -2, 324, +-1, 733, + 58, 456, + -2, 337, +-1, 771, + 59, 86, + -2, 230, +-1, 792, + 59, 86, + -2, 230, + }; +# define YYNPROD 481 +# define YYLAST 3082 +int yyact[]={ + + 166, 644, 439, 665, 196, 272, 241, 718, 245, 720, + 565, 350, 645, 16, 676, 257, 63, 657, 105, 9, + 662, 9, 646, 492, 365, 212, 552, 370, 104, 8, + 358, 8, 11, 658, 240, 88, 186, 50, 143, 234, + 222, 346, 58, 638, 97, 97, 227, 761, 271, 213, + 420, 486, 140, 484, 97, 147, 745, 98, 98, 12, + 478, 51, 642, 551, 193, 13, 475, 98, 728, 55, + 118, 120, 119, 541, 146, 56, 683, 25, 238, 709, + 523, 746, 684, 90, 436, 437, 364, 438, 435, 137, + 725, 652, 553, 553, 345, 436, 437, 123, 438, 435, + 436, 437, 179, 438, 435, 347, 348, 349, 666, 93, + 132, 663, 23, 24, 144, 18, 19, 20, 21, 22, + 144, 33, 34, 35, 36, 39, 40, 37, 38, 23, + 24, 32, 308, 45, 46, 44, 97, 307, 141, 255, + 132, 132, 185, 181, 132, 180, 141, 182, 393, 98, + 670, 144, 256, 191, 56, 165, 301, 780, 751, 15, + 394, 395, 713, 228, 189, 55, 696, 184, 53, 479, + 124, 56, 288, 789, 154, 663, 446, 215, 650, 317, + 560, 318, 223, 246, 274, 315, 316, 695, 490, 298, + 321, 322, 312, 61, 183, 336, 214, 237, 338, 334, + 337, 131, 339, 412, 351, 352, 295, 297, 215, 299, + 820, 360, 800, 328, 127, 200, 31, 368, 770, 18, + 19, 20, 21, 22, 756, 691, 612, 306, 233, 384, + 510, 128, 132, 23, 24, 373, 422, 97, 496, 255, + 255, 491, 476, 215, 305, 372, 390, 384, 387, 786, + 98, 626, 256, 391, 561, 559, 138, 235, 477, 130, + 332, 313, 214, 255, 53, 409, 236, 53, 211, 406, + 210, 53, 750, 389, 378, 88, 391, 209, 391, 382, + 215, 423, 135, 413, 413, 215, 126, 59, 802, 53, + 738, 92, 97, 97, 200, 420, 429, 397, 690, 214, + 660, 95, 100, 215, 214, 98, 98, 447, 357, 404, + 509, 110, 471, 363, 312, 637, 700, 421, 651, 696, + 765, 485, 214, 312, 312, 434, 781, 385, 383, 114, + 368, 108, 226, 545, 696, 696, 334, 425, 426, 399, + 695, 218, 772, 215, 535, 306, 334, 768, 373, 306, + 666, 188, 451, 735, 351, 695, 695, 215, 372, 220, + 194, 215, 468, 469, 470, 487, 636, 764, 521, 215, + 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, + 215, 215, 215, 215, 546, 97, 452, 480, 287, 347, + 348, 349, 230, 319, 320, 512, 514, 255, 98, 255, + 52, 190, 187, 515, 500, 517, 518, 671, 448, 202, + 391, 474, 391, 228, 31, 501, 472, 503, 629, 208, + 527, 528, 529, 524, 507, 122, 531, 505, 144, 223, + 511, 49, 205, 55, 359, 508, 388, 206, 432, 56, + 530, 215, 454, 455, 488, 489, 207, 201, 408, 452, + 220, 519, 520, 203, 522, 204, 195, 433, 457, 456, + 214, 533, 424, 458, 459, 386, 466, 467, 453, 440, + 436, 437, 417, 438, 435, 441, 121, 442, 443, 444, + 445, 23, 24, 554, 526, 557, 558, 543, 202, 464, + 465, 525, 566, 419, 649, 647, 648, 566, 208, 614, + 418, 696, 411, 63, 556, 567, 215, 613, 142, 389, + 567, 205, 460, 461, 462, 463, 206, 255, 373, 361, + 362, 555, 695, 621, 611, 207, 201, 616, 372, 410, + 391, 502, 203, 420, 204, 401, 53, 818, 290, 242, + 5, 31, 5, 631, 291, 632, 633, 534, 635, 430, + 431, 107, 53, 331, 618, 380, 619, 229, 376, 31, + 215, 341, 215, 351, 815, 351, 620, 810, 113, 107, + 379, 771, 640, 375, 664, 224, 667, 643, 759, 214, + 758, 214, 659, 112, 106, 757, 715, 712, 103, 289, + 215, 516, 483, 482, 481, 398, 396, 381, 377, 304, + 303, 164, 215, 302, 697, 775, 159, 327, 178, 630, + 160, 161, 325, 162, 323, 798, 324, 326, 799, 794, + 755, 214, 795, 452, 753, 255, 255, 754, 255, 672, + 734, 673, 674, 420, 678, 669, 685, 627, 391, 391, + 420, 391, 139, 625, 692, 680, 420, 682, 693, 659, + 123, 562, 701, 702, 351, 351, 351, 703, 373, 499, + 677, 498, 686, 710, 689, 704, 705, 706, 372, 721, + 624, 699, 622, 420, 708, 623, 420, 679, 494, 659, + 563, 711, 714, 564, 536, 812, 729, 537, 736, 31, + 727, 737, 215, 811, 163, 452, 741, 806, 659, 351, + 711, 790, 749, 494, 493, 453, 373, 742, 743, 677, + 747, 214, 739, 797, 449, 792, 372, 420, 777, 776, + 760, 762, 774, 766, 566, 763, 255, 752, 740, 724, + 717, 716, 769, 688, 767, 681, 634, 567, 547, 391, + 538, 497, 450, 330, 217, 748, 698, 668, 655, 654, + 779, 773, 653, 628, 542, 540, 539, 407, 405, 403, + 782, 783, 784, 402, 785, 787, 721, 292, 293, 294, + 400, 356, 353, 314, 355, 788, 3, 502, 354, 47, + 791, 793, 641, 796, 342, 719, 723, 495, 117, 801, + 803, 721, 192, 255, 116, 115, 60, 807, 804, 805, + 808, 10, 48, 6, 4, 809, 391, 2, 392, 249, + 687, 639, 216, 329, 136, 813, 814, 99, 506, 817, + 816, 200, 504, 819, 1, 75, 167, 168, 169, 170, + 171, 172, 173, 174, 175, 176, 177, 778, 150, 151, + 550, 164, 549, 661, 344, 675, 159, 726, 178, 707, + 160, 161, 656, 162, 343, 197, 199, 198, 153, 340, + 7, 18, 19, 20, 21, 22, 243, 33, 34, 35, + 36, 39, 40, 37, 38, 23, 24, 32, 26, 45, + 46, 44, 253, 247, 248, 258, 252, 259, 261, 262, + 263, 264, 265, 266, 267, 254, 156, 157, 158, 73, + 71, 74, 69, 87, 67, 77, 81, 27, 75, 28, + 29, 84, 83, 68, 72, 251, 250, 239, 86, 70, + 268, 269, 76, 65, 80, 85, 78, 66, 82, 260, + 79, 101, 102, 270, 163, 244, 273, 544, 366, 369, + 367, 599, 62, 109, 605, 582, 600, 568, 594, 604, + 571, 597, 589, 592, 598, 607, 584, 578, 573, 609, + 608, 26, 601, 606, 580, 42, 570, 576, 588, 579, + 603, 610, 577, 585, 587, 574, 569, 595, 596, 590, + 572, 575, 73, 71, 74, 69, 87, 67, 77, 81, + 27, 225, 28, 29, 84, 83, 68, 72, 586, 591, + 593, 86, 70, 602, 583, 76, 65, 80, 85, 78, + 66, 82, 164, 79, 221, 202, 581, 159, 133, 178, + 129, 160, 161, 41, 162, 208, 309, 54, 17, 371, + 436, 437, 276, 438, 435, 148, 428, 149, 205, 155, + 744, 694, 335, 206, 43, 275, 152, 0, 0, 0, + 0, 0, 207, 201, 0, 0, 111, 0, 0, 203, + 0, 204, 0, 0, 0, 75, 167, 168, 169, 170, + 171, 172, 173, 174, 175, 176, 177, 0, 150, 151, + 33, 34, 35, 36, 39, 40, 37, 38, 23, 24, + 32, 0, 45, 46, 44, 0, 0, 0, 153, 0, + 0, 0, 0, 0, 0, 163, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 26, 75, + 0, 0, 0, 247, 248, 258, 0, 259, 261, 262, + 263, 264, 265, 266, 267, 254, 156, 157, 158, 73, + 71, 74, 69, 87, 67, 77, 81, 27, 0, 28, + 29, 84, 83, 68, 72, 0, 0, 0, 86, 70, + 268, 269, 76, 65, 80, 85, 78, 66, 82, 260, + 79, 164, 26, 270, 0, 0, 159, 0, 178, 0, + 160, 161, 0, 162, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 73, 71, 74, 69, 87, 67, 77, + 81, 27, 0, 28, 29, 84, 83, 68, 72, 0, + 0, 0, 86, 70, 0, 0, 76, 65, 80, 85, + 78, 66, 82, 0, 79, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 75, 167, 168, 169, + 170, 171, 172, 173, 174, 175, 176, 177, 0, 150, + 151, 277, 278, 279, 280, 281, 282, 283, 284, 285, + 286, 0, 0, 0, 163, 0, 0, 0, 0, 153, + 0, 0, 0, 75, 0, 0, 0, 0, 33, 34, + 35, 36, 39, 40, 37, 38, 23, 24, 32, 26, + 45, 46, 44, 164, 0, 0, 0, 0, 159, 0, + 178, 0, 160, 161, 0, 162, 0, 156, 157, 158, + 73, 71, 74, 69, 87, 67, 77, 81, 27, 0, + 28, 29, 84, 83, 68, 72, 26, 0, 0, 86, + 70, 0, 0, 76, 65, 80, 85, 78, 66, 82, + 0, 79, 0, 0, 0, 0, 0, 73, 71, 74, + 69, 87, 67, 77, 81, 27, 0, 28, 29, 84, + 83, 68, 72, 0, 0, 0, 86, 70, 0, 0, + 76, 65, 80, 85, 78, 66, 82, 0, 79, 0, + 0, 0, 0, 0, 0, 0, 163, 0, 0, 0, + 0, 0, 0, 0, 0, 75, 167, 168, 169, 170, + 171, 172, 173, 174, 175, 176, 177, 0, 150, 151, + 0, 164, 0, 0, 0, 0, 159, 0, 178, 0, + 160, 161, 0, 162, 0, 0, 0, 0, 153, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 258, 0, 259, 261, 262, + 263, 264, 265, 266, 267, 254, 156, 157, 158, 73, + 71, 74, 69, 87, 67, 77, 81, 0, 0, 0, + 0, 84, 83, 68, 72, 0, 0, 0, 86, 70, + 268, 269, 76, 65, 80, 85, 78, 66, 82, 260, + 79, 0, 0, 270, 163, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 75, 167, 168, + 169, 170, 171, 172, 173, 174, 175, 176, 177, 0, + 150, 151, 0, 0, 164, 0, 0, 0, 0, 159, + 0, 178, 0, 160, 161, 0, 162, 0, 0, 0, + 153, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 258, 0, 259, + 261, 262, 263, 264, 265, 266, 267, 254, 156, 157, + 158, 73, 731, 732, 69, 733, 730, 77, 81, 0, + 0, 0, 0, 84, 83, 68, 72, 0, 0, 0, + 86, 70, 268, 269, 76, 65, 80, 85, 78, 66, + 82, 260, 79, 0, 145, 270, 532, 163, 0, 0, + 0, 0, 0, 0, 0, 75, 167, 168, 169, 170, + 171, 172, 173, 174, 175, 176, 177, 0, 150, 151, + 164, 0, 0, 0, 0, 159, 0, 178, 427, 160, + 161, 0, 162, 0, 0, 0, 0, 0, 153, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 164, 0, 0, 0, 0, + 159, 0, 178, 0, 160, 161, 0, 162, 0, 0, + 0, 0, 0, 0, 0, 0, 156, 157, 158, 73, + 71, 74, 69, 87, 67, 77, 81, 414, 374, 415, + 416, 84, 83, 68, 72, 0, 0, 0, 86, 70, + 0, 0, 76, 65, 80, 85, 78, 66, 82, 0, + 79, 0, 0, 163, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 75, 167, + 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, + 0, 150, 151, 0, 0, 145, 0, 0, 163, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 153, 0, 164, 0, 0, 0, 0, 159, 0, + 178, 0, 160, 161, 0, 162, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 156, + 157, 158, 73, 71, 74, 69, 87, 67, 77, 81, + 0, 0, 0, 0, 84, 83, 68, 72, 0, 0, + 0, 86, 70, 0, 0, 76, 65, 80, 85, 78, + 66, 82, 0, 79, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 75, 167, 168, 169, 170, 171, + 172, 173, 174, 175, 176, 177, 163, 150, 151, 0, + 0, 0, 33, 34, 35, 36, 39, 40, 37, 38, + 23, 24, 32, 26, 45, 46, 44, 153, 0, 75, + 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, + 177, 0, 150, 151, 0, 0, 0, 0, 0, 0, + 0, 0, 27, 0, 28, 29, 0, 0, 0, 0, + 0, 0, 153, 0, 0, 156, 157, 158, 73, 71, + 74, 69, 87, 67, 77, 81, 0, 0, 0, 0, + 84, 83, 68, 72, 0, 0, 0, 86, 70, 0, + 0, 76, 65, 80, 85, 78, 66, 82, 0, 79, + 156, 157, 158, 73, 71, 74, 69, 87, 67, 77, + 81, 0, 0, 0, 0, 84, 83, 68, 72, 0, + 0, 0, 86, 70, 0, 0, 76, 65, 80, 85, + 78, 66, 82, 0, 79, 0, 0, 75, 167, 168, + 169, 170, 171, 172, 173, 174, 175, 176, 177, 0, + 150, 151, 164, 0, 0, 0, 0, 159, 0, 300, + 0, 160, 161, 0, 162, 0, 0, 0, 0, 0, + 153, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 164, 0, 0, + 0, 0, 159, 0, 296, 0, 160, 161, 0, 162, + 0, 0, 0, 0, 0, 0, 0, 0, 156, 157, + 158, 73, 71, 74, 69, 87, 67, 77, 81, 75, + 219, 0, 0, 84, 83, 68, 72, 0, 0, 0, + 86, 70, 0, 0, 76, 65, 80, 85, 78, 66, + 82, 0, 79, 0, 0, 163, 0, 0, 0, 0, + 0, 75, 0, 0, 0, 18, 19, 20, 21, 22, + 0, 33, 34, 35, 36, 39, 40, 37, 38, 23, + 24, 32, 26, 45, 46, 44, 0, 0, 0, 0, + 163, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 73, 71, 74, 69, 87, 67, 77, + 81, 27, 0, 28, 29, 84, 83, 68, 72, 0, + 0, 0, 86, 70, 0, 0, 76, 65, 80, 85, + 78, 66, 82, 617, 79, 73, 71, 74, 69, 87, + 67, 77, 81, 0, 0, 0, 0, 84, 83, 68, + 72, 0, 0, 0, 722, 70, 0, 0, 76, 65, + 80, 85, 78, 66, 82, 0, 79, 0, 0, 96, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 546, 0, 75, 167, 168, 169, + 170, 171, 172, 173, 174, 175, 176, 177, 0, 150, + 151, 0, 0, 0, 33, 34, 35, 36, 39, 40, + 37, 38, 23, 24, 32, 26, 45, 46, 44, 153, + 0, 75, 167, 168, 169, 170, 171, 172, 173, 174, + 175, 176, 177, 0, 150, 151, 0, 0, 14, 0, + 0, 0, 0, 0, 27, 0, 28, 29, 57, 64, + 0, 0, 0, 0, 153, 0, 91, 156, 157, 158, + 73, 71, 74, 69, 87, 67, 77, 81, 0, 0, + 94, 0, 84, 83, 68, 72, 0, 0, 0, 86, + 70, 0, 0, 76, 65, 80, 85, 78, 66, 82, + 0, 79, 156, 157, 158, 73, 71, 74, 69, 87, + 67, 77, 81, 75, 0, 0, 0, 84, 83, 68, + 72, 0, 0, 0, 86, 70, 0, 0, 76, 65, + 80, 85, 78, 66, 82, 0, 79, 57, 0, 0, + 0, 125, 0, 0, 0, 94, 0, 0, 0, 0, + 0, 0, 0, 0, 57, 0, 0, 0, 0, 0, + 75, 0, 0, 0, 0, 0, 26, 0, 0, 0, + 0, 0, 0, 0, 0, 94, 94, 0, 0, 125, + 0, 94, 232, 0, 0, 0, 0, 73, 71, 74, + 69, 87, 67, 77, 81, 27, 0, 28, 29, 84, + 83, 68, 72, 0, 0, 0, 86, 70, 0, 0, + 76, 65, 80, 85, 78, 66, 82, 75, 79, 0, + 200, 0, 0, 200, 0, 0, 0, 310, 0, 0, + 0, 0, 0, 0, 73, 71, 74, 69, 87, 67, + 77, 81, 0, 0, 0, 0, 84, 83, 68, 72, + 0, 0, 0, 86, 70, 0, 0, 76, 65, 80, + 85, 78, 66, 82, 0, 79, 0, 94, 0, 0, + 513, 0, 0, 0, 0, 0, 75, 0, 0, 125, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 73, 71, 74, 69, 87, 67, 77, 81, 548, + 0, 0, 0, 84, 83, 68, 72, 0, 75, 31, + 86, 70, 0, 0, 76, 65, 80, 85, 78, 66, + 82, 0, 79, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 310, + 73, 71, 74, 69, 87, 67, 77, 81, 310, 310, + 0, 0, 84, 83, 68, 72, 0, 0, 0, 86, + 70, 0, 0, 76, 65, 80, 85, 78, 66, 82, + 0, 79, 73, 71, 74, 69, 87, 67, 77, 81, + 0, 0, 0, 0, 84, 83, 68, 72, 0, 0, + 0, 86, 70, 31, 0, 76, 65, 80, 85, 78, + 66, 82, 0, 79, 202, 0, 0, 202, 0, 229, + 0, 0, 57, 0, 208, 0, 0, 208, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 205, 0, 0, + 205, 0, 206, 473, 0, 206, 333, 0, 0, 0, + 0, 207, 201, 0, 207, 201, 0, 0, 203, 0, + 204, 203, 0, 204, 0, 0, 0, 18, 19, 20, + 21, 22, 243, 33, 34, 35, 36, 39, 40, 37, + 38, 23, 24, 32, 26, 45, 46, 44, 18, 19, + 20, 21, 22, 0, 33, 34, 35, 36, 39, 40, + 37, 38, 23, 24, 32, 26, 45, 46, 44, 615, + 30, 0, 0, 27, 0, 28, 29, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 89, 0, + 0, 0, 0, 0, 27, 0, 28, 29, 18, 19, + 20, 21, 22, 243, 33, 34, 35, 36, 39, 40, + 37, 38, 23, 24, 32, 26, 45, 46, 44, 0, + 18, 19, 20, 21, 22, 0, 33, 34, 35, 36, + 39, 40, 37, 38, 23, 24, 32, 26, 45, 46, + 44, 0, 0, 0, 27, 0, 28, 29, 0, 0, + 0, 33, 34, 35, 36, 39, 40, 37, 38, 23, + 24, 32, 26, 45, 46, 44, 27, 134, 28, 29, + 18, 19, 20, 21, 22, 0, 33, 34, 35, 36, + 39, 40, 37, 38, 23, 24, 32, 26, 45, 46, + 44, 27, 0, 28, 29, 0, 0, 134, 134, 0, + 0, 134, 0, 0, 231, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 27, 0, 28, 29, + 33, 34, 35, 36, 39, 40, 37, 38, 23, 24, + 32, 26, 45, 46, 44, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 311, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 27, 0, 28, 29, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 311, 0, 0, 0, 0, 0, 0, 0, 0, + 311, 311 }; +int yypact[]={ + + 2527, -1000, 2527, -1000, -1000, -1000, -1000, -1000, 372, 2527, + -65, -1000, -1000, -1000, -1000, 2279, -74, -178, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, 174, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, 2116, 862, -1000, -1000, -1000, 2577, -1000, + 525, 270, -1000, 1016, 524, -1000, -1000, -1000, 268, -1000, + -277, -1000, 385, -1000, 647, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -74, -1000, + -1000, -1000, 174, -1000, -1000, 163, 2552, -1000, -1000, 159, + -1000, 133, 2577, -1000, 372, 2527, -1000, 647, 1652, 311, + -1000, 647, -1000, 647, 1652, -1000, -287, 92, 154, 147, + 145, 1760, -1000, 703, -1000, -1000, 2552, 1975, -1000, 517, + 2621, -1000, -195, 781, -1000, 862, 143, -1000, 568, -1000, + 270, 268, -1000, -1000, -1000, 1652, -1000, 971, 109, 498, + 2034, 2034, 1760, 1999, -122, -1000, 545, 542, 541, -1000, + -1000, -1000, -1000, -1000, -1000, 120, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 979, 167, + 735, -91, 119, -82, 571, 570, -1000, 1760, -1000, 702, + -1000, -1000, 171, 137, 2360, -63, -1000, -1000, -1000, -1000, + 171, -1000, 61, 2311, 2311, 732, -1000, -1000, 731, 169, + 169, 169, 220, -1000, -1000, -1000, 1842, -1000, 1593, -1000, + -1000, 514, -1000, 540, 1760, 511, -1000, -1000, 539, 1760, + -195, -1000, -1000, 203, -1000, 266, 862, 123, 568, 808, + -1000, -1000, -1000, -151, -1000, -1000, 538, 1760, 537, 133, + -1000, -1000, -1000, -1000, 730, -1000, -74, 476, 723, 719, + 1760, 718, 808, 717, 862, 470, 443, 1378, 1378, 441, + 434, 632, -1000, 192, -1000, 1760, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, 1760, 1760, 1760, + 1617, 862, 862, -1000, -1000, -1000, 1760, -1000, -1000, -1000, + 979, 1760, -232, 136, 136, 1760, 673, 701, 647, 2552, + 2552, -1000, -1000, 1760, 1760, 1760, 1760, 1760, 1760, 1760, + 1760, 1760, 1760, 1760, 1760, 1760, 1760, 1760, 219, 1842, + -1000, 2357, 2505, -1000, -1000, -280, -1000, -1000, -1000, -1000, + 117, 171, 135, -300, -109, -223, -1000, 536, 535, 534, + -309, 230, -311, 2311, 133, 133, -77, 116, 660, -1000, + -1000, -1000, 113, -1000, 700, -1000, 617, -1000, -1000, 615, + -1000, 647, -1000, 2577, -1000, -1000, 517, -1000, -1000, -1000, + 499, -1000, -1000, -1000, 862, 1760, 185, -1000, 105, -1000, + -1000, -1000, 647, -1000, 2220, 2311, 808, 533, 808, -1000, + 1760, -1000, 1760, 1760, 6, 1760, -240, 1760, 432, -1000, + -1000, -1000, 425, -1000, 1760, 1760, 1760, 381, -1000, -1000, + 1760, -1000, 1501, -1000, -122, 489, 251, -1000, 643, -1000, + -1000, -1000, 699, 120, 716, -1000, -1000, -1000, -1000, 715, + -1000, -1000, -1000, -1000, -1000, -1000, -258, 714, 167, -1000, + 1760, -1000, -1000, 293, -1000, -1000, 735, -91, 119, 119, + -82, -82, -82, -82, 571, 571, 570, 570, -1000, -1000, + -1000, -1000, 697, -1000, 2434, -1000, -1000, -263, 171, -223, + -1000, -232, 136, 136, 132, -85, 131, 607, -1000, -1000, + 639, 651, -1000, 169, -1000, 101, 651, -1000, 2311, 2455, + -1000, -1000, 2163, -1000, 1760, -1000, 1760, -1000, -1000, -1000, + -1000, 507, -1000, -1000, -1000, -1000, 808, -1000, 631, 629, + 602, 128, 596, 713, 359, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, 1760, -1000, -1000, 1760, -1000, 1760, + 1760, 695, 1760, -1000, 275, 647, 1760, -1000, -1000, -1000, + -264, 138, -1000, 227, -227, -1000, 712, 709, 708, -232, + 207, -90, 2311, 291, 2311, 707, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, 635, -142, -1000, -1000, -1000, -1000, 647, -1000, -1000, + -1000, -1000, 348, 1760, 808, 808, -232, 808, 1760, 1760, + -1000, -1000, 694, 603, -257, 592, 1760, -1000, 692, 2577, + 205, 100, 138, -1000, 49, 558, -1000, 706, -232, 225, + 138, 138, 171, 2311, 2311, 2311, -237, -1000, 698, 529, + -1000, -154, -1000, 528, 690, -1000, -1000, 689, 1874, -1000, + -1000, -1000, 688, -228, -1000, -248, -1000, 1260, -1000, 589, + 294, -1000, 1760, -1000, -1000, 1760, 197, 2577, -1000, 687, + -1000, -1000, 49, -1000, 138, 138, -1000, -278, 2311, 705, + 138, 231, 65, -1000, 686, 583, 576, 99, -1000, 527, + -1000, 522, -1000, 520, -1000, 171, -315, 291, 684, 276, + -1000, -1000, 2311, 651, 288, 808, 93, -1000, 513, -1000, + -1000, -1000, -1000, -1000, 283, 1760, 681, 561, -1000, 678, + -1000, -1000, 558, 558, -1000, -1000, -1000, 677, 138, 64, + -1000, 265, -1000, -1000, 1760, 1760, -1000, 171, -1000, 171, + -1000, 126, -1000, -1000, 2311, 1874, -96, 661, -1000, -1000, + -1000, 1138, -1000, 674, -1000, 1760, -1000, -1000, 578, -104, + -1000, 138, 672, 574, -1000, 87, 136, 195, -1000, 2311, + 1874, -1000, 808, 656, -1000, 138, 49, -1000, -1000, 1760, + -1000, 509, -1000, -1000, 652, -1000, -1000, -104, -1000, 644, + 171, -1000, -1000, 136, 506, 171, 136, 479, 171, 85, + -1000 }; +int yypgo[]={ + + 0, 1046, 1045, 1044, 13, 0, 10, 1042, 1041, 1040, + 257, 65, 2308, 1039, 1037, 1036, 55, 36, 142, 167, + 194, 147, 143, 145, 102, 155, 174, 1035, 74, 5, + 48, 15, 49, 25, 539, 28, 1029, 59, 1028, 18, + 37, 1027, 400, 287, 1026, 2770, 1023, 214, 231, 1020, + 201, 1018, 1014, 40, 991, 46, 965, 228, 39, 52, + 32, 943, 942, 77, 159, 259, 940, 24, 939, 27, + 938, 132, 137, 43, 937, 38, 936, 6, 935, 89, + 932, 931, 917, 916, 915, 886, 882, 86, 860, 197, + 78, 34, 2, 22, 859, 360, 4, 203, 857, 856, + 11, 855, 183, 854, 852, 849, 17, 33, 847, 14, + 845, 8, 844, 41, 843, 20, 842, 840, 26, 1, + 12, 837, 23, 30, 824, 822, 818, 817, 814, 813, + 812, 811, 810, 809, 808, 807, 776, 804, 803, 802, + 801, 796, 795, 794, 792, 788, 308, 7, 787, 786, + 785, 9, 784, 782, 778, 774, 3 }; +int yyr1[]={ + + 0, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 15, 15, 16, 16, 16, + 16, 16, 16, 1, 1, 1, 1, 1, 1, 17, + 17, 18, 18, 18, 18, 19, 19, 19, 20, 20, + 20, 21, 21, 21, 21, 21, 22, 22, 22, 23, + 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, + 28, 29, 29, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 30, 30, 31, 31, 32, 33, + 33, 34, 34, 34, 35, 35, 36, 36, 37, 37, + 37, 38, 38, 38, 38, 39, 39, 39, 39, 40, + 40, 41, 41, 42, 42, 43, 43, 11, 11, 11, + 11, 11, 44, 44, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 46, 46, 46, 3, 3, + 47, 47, 48, 48, 49, 49, 50, 50, 50, 51, + 51, 51, 52, 52, 53, 53, 125, 53, 54, 54, + 55, 55, 126, 55, 127, 56, 128, 56, 56, 57, + 57, 58, 58, 12, 12, 59, 60, 61, 61, 61, + 129, 61, 62, 62, 62, 130, 62, 87, 87, 63, + 63, 63, 63, 64, 64, 65, 65, 66, 66, 67, + 67, 68, 68, 69, 69, 69, 70, 70, 71, 71, + 71, 71, 72, 72, 73, 73, 74, 74, 74, 131, + 74, 132, 74, 75, 75, 75, 76, 76, 77, 77, + 133, 111, 111, 111, 111, 111, 111, 111, 78, 78, + 78, 79, 79, 80, 80, 81, 81, 90, 90, 91, + 91, 134, 134, 134, 134, 82, 82, 89, 89, 83, + 84, 84, 84, 84, 110, 110, 109, 108, 108, 85, + 85, 85, 86, 86, 86, 86, 86, 86, 86, 124, + 124, 135, 135, 136, 136, 136, 139, 137, 88, 88, + 88, 10, 10, 102, 102, 4, 4, 4, 4, 140, + 138, 142, 142, 142, 141, 141, 143, 148, 149, 143, + 145, 7, 7, 7, 7, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 146, 146, 146, 123, 123, 122, 122, + 147, 147, 147, 150, 150, 151, 151, 151, 144, 144, + 94, 94, 95, 95, 96, 96, 96, 96, 152, 153, + 96, 101, 101, 101, 101, 101, 104, 104, 106, 105, + 105, 107, 107, 114, 114, 115, 103, 103, 112, 112, + 113, 113, 113, 113, 113, 154, 98, 155, 98, 99, + 99, 156, 156, 100, 100, 92, 92, 92, 92, 92, + 92, 92, 92, 93, 93, 93, 93, 97, 97, 97, + 97, 116, 116, 116, 117, 117, 118, 119, 119, 119, + 120, 120, 120, 120, 120, 120, 8, 121, 121, 9, + 9 }; +int yyr2[]={ + + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 7, 2, 9, 7, 9, 7, 7, + 5, 5, 13, 17, 21, 2, 7, 2, 5, 5, + 5, 5, 9, 2, 2, 2, 2, 2, 2, 2, + 9, 2, 7, 7, 7, 2, 7, 7, 2, 7, + 7, 2, 7, 7, 7, 7, 2, 7, 7, 2, + 7, 2, 7, 2, 7, 2, 7, 2, 7, 2, + 11, 2, 7, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 7, 1, 2, 2, 1, + 2, 5, 7, 7, 2, 5, 2, 2, 3, 5, + 2, 2, 5, 5, 5, 2, 2, 5, 5, 2, + 7, 2, 7, 3, 7, 3, 7, 3, 3, 3, + 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 2, 2, 11, 9, 5, 2, 2, + 2, 5, 7, 7, 2, 5, 3, 5, 2, 2, + 5, 5, 2, 7, 3, 5, 1, 9, 2, 7, + 3, 5, 1, 9, 1, 11, 1, 13, 5, 2, + 7, 3, 7, 3, 3, 5, 5, 2, 7, 9, + 1, 11, 3, 7, 9, 1, 11, 2, 2, 3, + 5, 5, 7, 1, 2, 2, 5, 2, 7, 1, + 2, 2, 7, 5, 2, 5, 3, 7, 2, 2, + 5, 5, 2, 5, 2, 5, 7, 7, 9, 1, + 9, 1, 11, 2, 7, 9, 2, 7, 2, 2, + 1, 5, 2, 2, 2, 2, 11, 15, 7, 9, + 7, 7, 9, 2, 5, 1, 2, 2, 5, 2, + 9, 3, 5, 5, 5, 2, 5, 1, 2, 5, + 11, 15, 11, 15, 3, 5, 5, 1, 7, 11, + 15, 19, 7, 5, 5, 7, 7, 5, 5, 0, + 2, 2, 4, 2, 3, 2, 1, 9, 3, 5, + 5, 3, 3, 3, 3, 2, 2, 2, 2, 1, + 6, 9, 7, 9, 1, 3, 17, 1, 1, 23, + 11, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 1, 5, 9, 3, 3, 1, 3, + 0, 2, 9, 2, 7, 3, 5, 9, 1, 9, + 1, 2, 2, 5, 2, 2, 2, 7, 1, 1, + 13, 9, 13, 15, 19, 37, 3, 5, 5, 1, + 7, 5, 7, 2, 5, 7, 2, 5, 2, 7, + 13, 13, 17, 17, 21, 1, 7, 1, 7, 11, + 15, 0, 3, 3, 9, 3, 3, 3, 3, 3, + 3, 9, 9, 3, 3, 3, 3, 2, 5, 5, + 5, 9, 7, 3, 2, 5, 15, 2, 7, 7, + 3, 9, 11, 9, 7, 7, 2, 2, 7, 2, + 2 }; +int yychk[]={ + + -1000, -124, -135, -136, -137, -34, -138, -88, -35, -39, + -140, -60, -37, -11, -12, -64, -4, -38, 293, 294, + 295, 296, 297, 307, 308, -63, 310, 339, 341, 342, + -45, 42, 309, 299, 300, 301, 302, 305, 306, 303, + 304, -46, -56, -3, 313, 311, 312, -136, -139, 59, + -40, -59, -42, -64, -41, -37, -11, -12, -60, -43, + -141, 258, -62, -5, 40, 355, 359, 336, 345, 334, + 351, 332, 346, 331, 333, 257, 354, 337, 358, 362, + 356, 338, 360, 344, 343, 357, 350, 335, -39, -45, + -11, -12, -65, -63, -12, -10, 123, -5, -4, -127, + -10, -81, -80, -34, -35, -39, 59, 44, 61, -61, + -10, 40, 59, 44, 61, -142, -143, -145, 347, 349, + 348, 91, 40, -60, -63, -12, 123, -47, -48, -49, + -65, -50, -4, -51, -45, 123, -128, -79, 123, -34, + -59, -60, -42, -75, -29, 123, -28, -16, -27, -14, + 270, 271, -1, 290, -26, -13, 328, 329, 330, 38, + 42, 43, 45, 126, 33, -25, -5, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 267, 268, 40, -24, + -23, -22, -21, -20, -19, -18, -17, 91, 40, -59, + -43, -75, -144, 351, -95, 364, -96, -101, -98, -99, + 123, 355, 317, 361, 363, 340, 345, 354, 327, 123, + 123, 123, -33, -32, -28, -16, -130, 41, -47, 125, + -48, -52, -53, -59, 58, -54, -50, -55, -60, 58, + -65, -45, -12, -57, -58, -10, 123, -89, -90, -82, + -91, -77, -34, 298, -78, -111, -102, 315, 316, -133, + -83, -84, -85, -86, 327, -5, -4, -31, 317, 319, + 361, 320, 321, 322, 323, 324, 325, 326, 352, 353, + 365, -30, -29, -76, -75, -2, 61, 280, 281, 282, + 283, 284, 285, 286, 287, 288, 289, 279, 63, 91, + 40, 46, 269, 270, 271, -16, 40, -16, -17, -16, + 40, 278, 58, 58, 58, 124, -30, -72, -71, -44, + -12, -45, -4, 94, 38, 276, 277, 60, 62, 274, + 275, 272, 273, 43, 45, 42, 47, 37, -33, -129, + 41, -95, 123, 346, -96, -7, 258, 263, 261, 265, + -94, -95, -152, -103, -112, 33, -113, 328, 329, 330, + -100, -5, -5, 40, -154, -155, 40, -146, -123, 265, + 42, -146, -146, 93, -87, -67, -70, -66, -5, -68, + -69, -36, -35, -39, 125, 59, 44, 58, -32, 59, + 44, 58, -32, 125, 44, 61, -57, 125, -89, -91, + -77, -4, -134, 299, 311, 312, 58, -32, 58, -79, + 40, 59, 40, 40, -30, 40, -77, 40, -102, -5, + 59, 59, -97, -31, 339, 341, 342, -97, 59, 59, + 44, 125, 44, -29, -26, -30, -30, 41, -15, -29, + -10, -10, -72, -25, -93, 336, 332, 333, 335, -92, + 333, 339, 341, 342, 343, 344, 40, -92, -24, 41, + 41, -73, -63, -64, -71, -71, -23, -22, -21, -21, + -20, -20, -20, -20, -19, -19, -18, -18, -17, -17, + -17, 93, -87, 346, -90, 346, 125, 123, 360, 278, + -113, 58, 58, 58, 362, 91, 362, -100, -79, -79, + 265, 125, -122, 44, 43, -148, 125, 41, 44, 44, + -60, -73, -64, -53, -125, -55, -126, -58, -32, 125, + 125, -40, -5, 310, -5, -77, 58, -77, -29, -30, + -30, 362, -30, 320, -31, 59, 59, -29, -29, -29, + 59, -29, 125, -75, 58, 93, 41, 44, 41, 40, + 40, 331, 40, -17, -74, 40, 91, 41, 125, -116, + -117, 326, -118, 356, -96, -113, -93, -92, -92, 123, + 265, 123, 44, 41, 44, -6, -5, -4, 296, 325, + 315, 299, 329, 307, 324, 330, 316, 321, 306, 318, + 313, 365, 294, 353, 305, 322, 347, 323, 317, 301, + 328, 348, 302, 349, 297, 326, 327, 300, 303, 290, + 295, 311, 352, 319, 298, 293, 312, 304, 309, 308, + 320, -123, 125, -6, -5, 314, -69, 40, -32, -32, + 59, -77, 41, 44, 41, 41, 123, 41, 40, 59, + -28, -29, -29, -29, 41, -29, 91, 40, -73, -131, + -33, -153, 326, -118, -119, -120, -93, 357, 358, 356, + 40, 91, 318, 40, 40, 40, -104, -106, -107, -93, + 93, -114, -115, 265, -100, -156, 59, -100, 40, -122, + 292, 59, -29, -77, -77, -110, -109, -107, -77, -30, + -31, 41, 44, 333, 339, 44, -33, -132, 41, -67, + 93, 125, -119, -156, -8, 291, 270, 46, 40, -93, + 91, -119, -119, -96, -100, -100, -100, -105, -106, 316, + -96, -93, 58, 316, -115, 58, 41, 41, -147, -150, + -151, -5, 350, -149, 41, 318, -108, -109, 316, -111, + 336, 332, 333, 335, 41, 59, -29, -29, 93, -67, + 41, -156, -120, -120, -9, 334, 359, -100, 40, -119, + 41, 93, 41, 41, 44, 44, 125, 58, 58, 58, + -96, 362, -156, 41, 91, 44, -5, -6, 59, -77, + 125, 58, 59, -31, 41, 44, 41, 41, -121, -119, + 93, 61, -29, -29, -96, -96, 123, -5, -151, 269, + 40, -111, 41, -29, 41, 44, -119, 41, 41, 44, + 125, -92, 93, -5, -147, -77, 41, -119, -156, -29, + 58, 41, 41, -96, -92, 58, -96, -92, 58, -96, + 125 }; +int yydef[]={ + + -2, -2, -2, 281, 283, 284, 285, 286, 193, 193, + 304, 288, 94, 105, 106, 0, 98, 100, 117, 118, + 119, 120, 121, 173, 174, 194, 295, 296, 297, 298, + 101, 189, 124, 125, 126, 127, 128, 129, 130, 131, + 132, 133, 134, 0, 164, 138, 139, 282, 245, 91, + 0, -2, 109, 0, 0, 95, 107, 108, -2, 111, + 0, 305, 176, 182, 193, 315, 316, 317, 318, 319, + 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, + 330, 331, 332, 333, 334, 335, 336, 337, 99, 102, + 103, 104, 190, 191, 195, 137, 0, 291, 292, 0, + -2, 0, 246, 243, 193, 193, 92, 193, 0, 175, + 177, 193, 93, 193, 0, 300, 398, 0, 0, 0, + 0, 89, 185, 0, 192, 196, 0, 0, 140, 193, + 193, 144, 146, 148, 149, 0, 0, 287, -2, 244, + 113, 115, 110, 114, 223, 0, 71, 39, 69, 27, + 0, 0, 0, 0, 67, 14, 0, 0, 0, 33, + 34, 35, 36, 37, 38, 65, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 0, 63, + 61, 59, 56, 51, 48, 45, 41, 89, 180, 0, + 112, 116, 0, 0, 0, 0, 402, 404, 405, 406, + 400, 408, 0, 0, 0, 0, 435, 437, 0, 383, + 383, 383, 0, 90, 88, 39, 199, 183, 0, 136, + 141, 0, 152, 154, 0, 0, 145, 158, 160, 0, + 147, 150, 151, 0, 169, 171, 0, 0, -2, -2, + 247, 255, 249, 0, 228, 229, 0, 0, 0, 0, + 232, 233, 234, 235, 0, -2, -2, 0, 0, 0, + 0, 0, -2, 0, 0, 0, 0, 86, 86, 0, + 0, 87, 84, 0, 226, 0, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 0, 0, 0, + 0, 0, 0, 20, 21, 28, 0, 29, 30, 31, + 0, 0, 0, 0, 0, 0, 0, 0, -2, 208, + 209, 122, 123, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 199, + 178, 0, 0, 302, 403, 0, 311, 312, 313, 314, + 0, 401, 0, 0, 426, 0, 428, 0, 0, 0, + 0, 443, 0, 0, 0, 0, 0, 0, 388, 386, + 387, 307, 0, 184, 0, 187, 188, 200, 206, 197, + 201, -2, 96, 97, 135, 142, 193, 156, 155, 143, + 193, 162, 161, 165, 0, 0, 0, 241, 0, 248, + 256, 294, 193, 251, 0, 0, -2, 0, -2, 231, + 0, 259, 0, 0, 0, 0, 0, 86, 0, 293, + 273, 274, 0, 457, 0, 0, 0, 0, 277, 278, + 0, 224, 0, 72, 68, 0, 0, 16, 0, 25, + 18, 19, 0, 66, 0, 453, 454, 455, 456, 0, + 445, 446, 447, 448, 449, 450, 0, 0, 64, 13, + 0, 213, -2, 0, 210, 211, 62, 60, 57, 58, + 52, 53, 54, 55, 49, 50, 46, 47, 42, 43, + 44, 179, 0, 301, 0, 303, 407, 0, 0, 0, + 427, 0, 0, 0, 0, 0, 0, 0, 436, 438, + 0, 0, 384, 0, 389, 0, 0, 186, 0, 0, + 203, 205, 0, 153, 0, 159, 0, 170, 172, 167, + 242, 0, 252, 253, 254, 238, -2, 240, 0, 0, + 0, 0, 0, 0, 0, 272, 275, 458, 459, 460, + 276, 85, 225, 227, 0, 15, 17, 0, 32, 0, + 0, 0, 0, 40, 215, -2, 89, 181, 399, 409, + 463, 0, 464, 0, 411, 429, 0, 0, 0, 0, + 0, 0, 0, 441, 0, 0, 338, 339, 340, 341, + 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, + 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, + 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, + 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, + 382, 388, 0, 310, 207, 198, 202, -2, 157, 163, + 250, 239, 0, 0, -2, -2, 0, -2, 0, 86, + 70, 26, 0, 0, 0, 0, 89, 221, 0, 199, + 0, 0, 0, 465, 441, 467, 470, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 419, 416, 0, 0, + 444, 0, 423, 0, 0, 439, 442, 0, 390, 385, + 308, 236, 0, 260, 262, 267, 264, -2, 269, 0, + 0, 22, 0, 451, 452, 0, 0, 199, 216, 0, + 217, 410, 441, 462, 0, 0, 476, 0, 0, 0, + 0, 0, 0, 412, 0, 0, 0, 0, 417, 0, + 418, 0, 421, 0, 424, 0, 0, 441, 0, 391, + 393, 395, 336, 0, 0, -2, 0, 265, 0, 266, + -2, -2, -2, -2, 0, 86, 0, 0, 218, 0, + 220, 461, 468, 469, 474, 479, 480, 0, 0, 0, + 475, 0, 430, 431, 0, 0, 413, 0, 422, 0, + 425, 0, 440, 306, 0, 0, 396, 0, 237, 261, + 263, -2, 270, 0, 23, 0, 222, 471, 0, 477, + 473, 0, 0, 0, 420, 0, 0, 0, 394, 0, + 390, 268, -2, 0, 472, 0, 441, 432, 433, 0, + 414, 0, 392, 397, 0, 271, 24, 478, 466, 0, + 0, 309, 434, 0, 0, 0, 0, 0, 0, 0, + 415 }; +typedef struct { char *t_name; int t_val; } yytoktype; +#ifndef YYDEBUG +# define YYDEBUG 0 /* don't allow debugging */ +#endif + +#if YYDEBUG + +yytoktype yytoks[] = +{ + "Identifier", 257, + "StrLit", 258, + "LStrLit", 259, + "FltConst", 260, + "DblConst", 261, + "LDblConst", 262, + "CharConst", 263, + "LCharConst", 264, + "IntConst", 265, + "UIntConst", 266, + "LIntConst", 267, + "ULIntConst", 268, + "Arrow", 269, + "Incr", 270, + "Decr", 271, + "LShft", 272, + "RShft", 273, + "Leq", 274, + "Geq", 275, + "Equal", 276, + "Neq", 277, + "And", 278, + "Or", 279, + "MultAsgn", 280, + "DivAsgn", 281, + "ModAsgn", 282, + "PlusAsgn", 283, + "MinusAsgn", 284, + "LShftAsgn", 285, + "RShftAsgn", 286, + "AndAsgn", 287, + "XorAsgn", 288, + "OrAsgn", 289, + "Sizeof", 290, + "Intersect", 291, + "OpSym", 292, + "Typedef", 293, + "Extern", 294, + "Static", 295, + "Auto", 296, + "Register", 297, + "Tended", 298, + "Char", 299, + "Short", 300, + "Int", 301, + "Long", 302, + "Signed", 303, + "Unsigned", 304, + "Float", 305, + "Doubl", 306, + "Const", 307, + "Volatile", 308, + "Void", 309, + "TypeDefName", 310, + "Struct", 311, + "Union", 312, + "Enum", 313, + "Ellipsis", 314, + "Case", 315, + "Default", 316, + "If", 317, + "Else", 318, + "Switch", 319, + "While", 320, + "Do", 321, + "For", 322, + "Goto", 323, + "Continue", 324, + "Break", 325, + "Return", 326, + "%", 37, + "&", 38, + "(", 40, + ")", 41, + "*", 42, + "+", 43, + ",", 44, + "-", 45, + ".", 46, + "/", 47, + "{", 123, + "|", 124, + "}", 125, + "~", 126, + "[", 91, + "]", 93, + "^", 94, + ":", 58, + ";", 59, + "<", 60, + "=", 61, + ">", 62, + "?", 63, + "!", 33, + "@", 64, + "\\", 92, + "Runerr", 327, + "Is", 328, + "Cnv", 329, + "Def", 330, + "Exact", 331, + "Empty_type", 332, + "IconType", 333, + "Component", 334, + "Variable", 335, + "Any_value", 336, + "Named_var", 337, + "Struct_var", 338, + "C_Integer", 339, + "Arith_case", 340, + "C_Double", 341, + "C_String", 342, + "Tmp_string", 343, + "Tmp_cset", 344, + "Body", 345, + "End", 346, + "Function", 347, + "Keyword", 348, + "Operator", 349, + "Underef", 350, + "Declare", 351, + "Suspend", 352, + "Fail", 353, + "Inline", 354, + "Abstract", 355, + "Store", 356, + "Type", 357, + "New", 358, + "All_fields", 359, + "Then", 360, + "Type_case", 361, + "Of", 362, + "Len_case", 363, + "Constant", 364, + "Errorfail", 365, + "IfStmt", 366, + "-unknown-", -1 /* ends search */ +}; + +char * yyreds[] = +{ + "-no such reduction-", + "primary_expr : identifier", + "primary_expr : StrLit", + "primary_expr : LStrLit", + "primary_expr : FltConst", + "primary_expr : DblConst", + "primary_expr : LDblConst", + "primary_expr : CharConst", + "primary_expr : LCharConst", + "primary_expr : IntConst", + "primary_expr : UIntConst", + "primary_expr : LIntConst", + "primary_expr : ULIntConst", + "primary_expr : '(' expr ')'", + "postfix_expr : primary_expr", + "postfix_expr : postfix_expr '[' expr ']'", + "postfix_expr : postfix_expr '(' ')'", + "postfix_expr : postfix_expr '(' arg_expr_lst ')'", + "postfix_expr : postfix_expr '.' any_ident", + "postfix_expr : postfix_expr Arrow any_ident", + "postfix_expr : postfix_expr Incr", + "postfix_expr : postfix_expr Decr", + "postfix_expr : Is ':' i_type_name '(' assign_expr ')'", + "postfix_expr : Cnv ':' dest_type '(' assign_expr ',' assign_expr ')'", + "postfix_expr : Def ':' dest_type '(' assign_expr ',' assign_expr ',' assign_expr ')'", + "arg_expr_lst : assign_expr", + "arg_expr_lst : arg_expr_lst ',' assign_expr", + "unary_expr : postfix_expr", + "unary_expr : Incr unary_expr", + "unary_expr : Decr unary_expr", + "unary_expr : unary_op cast_expr", + "unary_expr : Sizeof unary_expr", + "unary_expr : Sizeof '(' type_name ')'", + "unary_op : '&'", + "unary_op : '*'", + "unary_op : '+'", + "unary_op : '-'", + "unary_op : '~'", + "unary_op : '!'", + "cast_expr : unary_expr", + "cast_expr : '(' type_name ')' cast_expr", + "multiplicative_expr : cast_expr", + "multiplicative_expr : multiplicative_expr '*' cast_expr", + "multiplicative_expr : multiplicative_expr '/' cast_expr", + "multiplicative_expr : multiplicative_expr '%' cast_expr", + "additive_expr : multiplicative_expr", + "additive_expr : additive_expr '+' multiplicative_expr", + "additive_expr : additive_expr '-' multiplicative_expr", + "shift_expr : additive_expr", + "shift_expr : shift_expr LShft additive_expr", + "shift_expr : shift_expr RShft additive_expr", + "relational_expr : shift_expr", + "relational_expr : relational_expr '<' shift_expr", + "relational_expr : relational_expr '>' shift_expr", + "relational_expr : relational_expr Leq shift_expr", + "relational_expr : relational_expr Geq shift_expr", + "equality_expr : relational_expr", + "equality_expr : equality_expr Equal relational_expr", + "equality_expr : equality_expr Neq relational_expr", + "and_expr : equality_expr", + "and_expr : and_expr '&' equality_expr", + "exclusive_or_expr : and_expr", + "exclusive_or_expr : exclusive_or_expr '^' and_expr", + "inclusive_or_expr : exclusive_or_expr", + "inclusive_or_expr : inclusive_or_expr '|' exclusive_or_expr", + "logical_and_expr : inclusive_or_expr", + "logical_and_expr : logical_and_expr And inclusive_or_expr", + "logical_or_expr : logical_and_expr", + "logical_or_expr : logical_or_expr Or logical_and_expr", + "conditional_expr : logical_or_expr", + "conditional_expr : logical_or_expr '?' expr ':' conditional_expr", + "assign_expr : conditional_expr", + "assign_expr : unary_expr assign_op assign_expr", + "assign_op : '='", + "assign_op : MultAsgn", + "assign_op : DivAsgn", + "assign_op : ModAsgn", + "assign_op : PlusAsgn", + "assign_op : MinusAsgn", + "assign_op : LShftAsgn", + "assign_op : RShftAsgn", + "assign_op : AndAsgn", + "assign_op : XorAsgn", + "assign_op : OrAsgn", + "expr : assign_expr", + "expr : expr ',' assign_expr", + "opt_expr : /* empty */", + "opt_expr : expr", + "constant_expr : conditional_expr", + "opt_constant_expr : /* empty */", + "opt_constant_expr : constant_expr", + "dcltion : typ_dcltion_specs ';'", + "dcltion : typ_dcltion_specs init_dcltor_lst ';'", + "dcltion : storcl_tqual_lst no_tdn_init_dcltor_lst ';'", + "typ_dcltion_specs : type_ind", + "typ_dcltion_specs : storcl_tqual_lst type_ind", + "dcltion_specs : typ_dcltion_specs", + "dcltion_specs : storcl_tqual_lst", + "type_ind : typedefname", + "type_ind : typedefname storcl_tqual_lst", + "type_ind : type_storcl_tqual_lst", + "type_storcl_tqual_lst : stnd_type", + "type_storcl_tqual_lst : type_storcl_tqual_lst stnd_type", + "type_storcl_tqual_lst : type_storcl_tqual_lst storage_class_spec", + "type_storcl_tqual_lst : type_storcl_tqual_lst type_qual", + "storcl_tqual_lst : storage_class_spec", + "storcl_tqual_lst : type_qual", + "storcl_tqual_lst : storcl_tqual_lst storage_class_spec", + "storcl_tqual_lst : storcl_tqual_lst type_qual", + "init_dcltor_lst : init_dcltor", + "init_dcltor_lst : init_dcltor_lst ',' init_dcltor", + "no_tdn_init_dcltor_lst : no_tdn_init_dcltor", + "no_tdn_init_dcltor_lst : no_tdn_init_dcltor_lst ',' no_tdn_init_dcltor", + "init_dcltor : dcltor", + "init_dcltor : dcltor '=' initializer", + "no_tdn_init_dcltor : no_tdn_dcltor", + "no_tdn_init_dcltor : no_tdn_dcltor '=' initializer", + "storage_class_spec : Typedef", + "storage_class_spec : Extern", + "storage_class_spec : Static", + "storage_class_spec : Auto", + "storage_class_spec : Register", + "type_spec : stnd_type", + "type_spec : typedefname", + "stnd_type : Void", + "stnd_type : Char", + "stnd_type : Short", + "stnd_type : Int", + "stnd_type : Long", + "stnd_type : Float", + "stnd_type : Doubl", + "stnd_type : Signed", + "stnd_type : Unsigned", + "stnd_type : struct_or_union_spec", + "stnd_type : enum_spec", + "struct_or_union_spec : struct_or_union any_ident '{' struct_dcltion_lst '}'", + "struct_or_union_spec : struct_or_union '{' struct_dcltion_lst '}'", + "struct_or_union_spec : struct_or_union any_ident", + "struct_or_union : Struct", + "struct_or_union : Union", + "struct_dcltion_lst : struct_dcltion", + "struct_dcltion_lst : struct_dcltion_lst struct_dcltion", + "struct_dcltion : struct_dcltion_specs struct_dcltor_lst ';'", + "struct_dcltion : tqual_lst struct_no_tdn_dcltor_lst ';'", + "struct_dcltion_specs : struct_type_ind", + "struct_dcltion_specs : tqual_lst struct_type_ind", + "struct_type_ind : typedefname", + "struct_type_ind : typedefname tqual_lst", + "struct_type_ind : struct_type_lst", + "struct_type_lst : stnd_type", + "struct_type_lst : struct_type_lst stnd_type", + "struct_type_lst : struct_type_lst type_qual", + "struct_dcltor_lst : struct_dcltor", + "struct_dcltor_lst : struct_dcltor_lst ',' struct_dcltor", + "struct_dcltor : dcltor", + "struct_dcltor : ':' constant_expr", + "struct_dcltor : dcltor ':'", + "struct_dcltor : dcltor ':' constant_expr", + "struct_no_tdn_dcltor_lst : struct_no_tdn_dcltor", + "struct_no_tdn_dcltor_lst : struct_no_tdn_dcltor_lst ',' struct_no_tdn_dcltor", + "struct_no_tdn_dcltor : no_tdn_dcltor", + "struct_no_tdn_dcltor : ':' constant_expr", + "struct_no_tdn_dcltor : no_tdn_dcltor ':'", + "struct_no_tdn_dcltor : no_tdn_dcltor ':' constant_expr", + "enum_spec : Enum", + "enum_spec : Enum '{' enumerator_lst '}'", + "enum_spec : Enum any_ident", + "enum_spec : Enum any_ident '{' enumerator_lst '}'", + "enum_spec : Enum any_ident", + "enumerator_lst : enumerator", + "enumerator_lst : enumerator_lst ',' enumerator", + "enumerator : any_ident", + "enumerator : any_ident '=' constant_expr", + "type_qual : Const", + "type_qual : Volatile", + "dcltor : opt_pointer direct_dcltor", + "no_tdn_dcltor : opt_pointer no_tdn_direct_dcltor", + "direct_dcltor : any_ident", + "direct_dcltor : '(' dcltor ')'", + "direct_dcltor : direct_dcltor '[' opt_constant_expr ']'", + "direct_dcltor : direct_dcltor '('", + "direct_dcltor : direct_dcltor '(' parm_dcls_or_ids ')'", + "no_tdn_direct_dcltor : identifier", + "no_tdn_direct_dcltor : '(' no_tdn_dcltor ')'", + "no_tdn_direct_dcltor : no_tdn_direct_dcltor '[' opt_constant_expr ']'", + "no_tdn_direct_dcltor : no_tdn_direct_dcltor '('", + "no_tdn_direct_dcltor : no_tdn_direct_dcltor '(' parm_dcls_or_ids ')'", + "parm_dcls_or_ids : opt_param_type_lst", + "parm_dcls_or_ids : ident_lst", + "pointer : '*'", + "pointer : '*' tqual_lst", + "pointer : '*' pointer", + "pointer : '*' tqual_lst pointer", + "opt_pointer : /* empty */", + "opt_pointer : pointer", + "tqual_lst : type_qual", + "tqual_lst : tqual_lst type_qual", + "param_type_lst : param_lst", + "param_type_lst : param_lst ',' Ellipsis", + "opt_param_type_lst : /* empty */", + "opt_param_type_lst : param_type_lst", + "param_lst : param_dcltion", + "param_lst : param_lst ',' param_dcltion", + "param_dcltion : dcltion_specs no_tdn_dcltor", + "param_dcltion : dcltion_specs", + "param_dcltion : dcltion_specs abstract_dcltor", + "ident_lst : identifier", + "ident_lst : ident_lst ',' identifier", + "type_tqual_lst : type_spec", + "type_tqual_lst : type_qual", + "type_tqual_lst : type_spec type_tqual_lst", + "type_tqual_lst : type_qual type_tqual_lst", + "type_name : type_tqual_lst", + "type_name : type_tqual_lst abstract_dcltor", + "abstract_dcltor : pointer", + "abstract_dcltor : opt_pointer direct_abstract_dcltor", + "direct_abstract_dcltor : '(' abstract_dcltor ')'", + "direct_abstract_dcltor : '[' opt_constant_expr ']'", + "direct_abstract_dcltor : direct_abstract_dcltor '[' opt_constant_expr ']'", + "direct_abstract_dcltor : '('", + "direct_abstract_dcltor : '(' opt_param_type_lst ')'", + "direct_abstract_dcltor : direct_abstract_dcltor '('", + "direct_abstract_dcltor : direct_abstract_dcltor '(' opt_param_type_lst ')'", + "initializer : assign_expr", + "initializer : '{' initializer_lst '}'", + "initializer : '{' initializer_lst ',' '}'", + "initializer_lst : initializer", + "initializer_lst : initializer_lst ',' initializer", + "stmt : labeled_stmt", + "stmt : non_lbl_stmt", + "non_lbl_stmt : /* empty */", + "non_lbl_stmt : compound_stmt", + "non_lbl_stmt : expr_stmt", + "non_lbl_stmt : selection_stmt", + "non_lbl_stmt : iteration_stmt", + "non_lbl_stmt : jump_stmt", + "non_lbl_stmt : Runerr '(' assign_expr ')' ';'", + "non_lbl_stmt : Runerr '(' assign_expr ',' assign_expr ')' ';'", + "labeled_stmt : label ':' stmt", + "labeled_stmt : Case constant_expr ':' stmt", + "labeled_stmt : Default ':' stmt", + "compound_stmt : '{' opt_stmt_lst '}'", + "compound_stmt : '{' local_dcls opt_stmt_lst '}'", + "dcltion_lst : dcltion", + "dcltion_lst : dcltion_lst dcltion", + "opt_dcltion_lst : /* empty */", + "opt_dcltion_lst : dcltion_lst", + "local_dcls : local_dcl", + "local_dcls : local_dcls local_dcl", + "local_dcl : dcltion", + "local_dcl : Tended tended_type init_dcltor_lst ';'", + "tended_type : Char", + "tended_type : Struct identifier", + "tended_type : Struct TypeDefName", + "tended_type : Union identifier", + "stmt_lst : stmt", + "stmt_lst : stmt_lst stmt", + "opt_stmt_lst : /* empty */", + "opt_stmt_lst : stmt_lst", + "expr_stmt : opt_expr ';'", + "selection_stmt : If '(' expr ')' stmt", + "selection_stmt : If '(' expr ')' stmt Else stmt", + "selection_stmt : Switch '(' expr ')' stmt", + "selection_stmt : Type_case expr Of '{' c_type_select_lst c_opt_default '}'", + "c_type_select_lst : c_type_select", + "c_type_select_lst : c_type_select_lst c_type_select", + "c_type_select : selector_lst non_lbl_stmt", + "c_opt_default : /* empty */", + "c_opt_default : Default ':' non_lbl_stmt", + "iteration_stmt : While '(' expr ')' stmt", + "iteration_stmt : Do stmt While '(' expr ')' ';'", + "iteration_stmt : For '(' opt_expr ';' opt_expr ';' opt_expr ')' stmt", + "jump_stmt : Goto label ';'", + "jump_stmt : Continue ';'", + "jump_stmt : Break ';'", + "jump_stmt : Return ret_val ';'", + "jump_stmt : Suspend ret_val ';'", + "jump_stmt : Fail ';'", + "jump_stmt : Errorfail ';'", + "translation_unit : /* empty */", + "translation_unit : extrn_decltn_lst", + "extrn_decltn_lst : external_dcltion", + "extrn_decltn_lst : extrn_decltn_lst external_dcltion", + "external_dcltion : function_definition", + "external_dcltion : dcltion", + "external_dcltion : definition", + "function_definition : func_head", + "function_definition : func_head opt_dcltion_lst compound_stmt", + "func_head : no_tdn_dcltor", + "func_head : storcl_tqual_lst no_tdn_dcltor", + "func_head : typ_dcltion_specs dcltor", + "any_ident : identifier", + "any_ident : typedefname", + "label : identifier", + "label : typedefname", + "typedefname : TypeDefName", + "typedefname : C_Integer", + "typedefname : C_Double", + "typedefname : C_String", + "definition : /* empty */", + "definition : description operation", + "operation : fnc_oper op_declare actions End", + "operation : keyword actions End", + "operation : keyword Constant key_const End", + "description : /* empty */", + "description : StrLit", + "fnc_oper : Function '{' result_seq '}' op_name '(' opt_s_parm_lst ')'", + "fnc_oper : Operator '{' result_seq", + "fnc_oper : Operator '{' result_seq '}' OpSym", + "fnc_oper : Operator '{' result_seq '}' OpSym op_name '(' opt_s_parm_lst ')'", + "keyword : Keyword '{' result_seq '}' op_name", + "key_const : StrLit", + "key_const : CharConst", + "key_const : DblConst", + "key_const : IntConst", + "identifier : Abstract", + "identifier : All_fields", + "identifier : Any_value", + "identifier : Body", + "identifier : Component", + "identifier : Declare", + "identifier : Empty_type", + "identifier : End", + "identifier : Exact", + "identifier : IconType", + "identifier : Identifier", + "identifier : Inline", + "identifier : Named_var", + "identifier : New", + "identifier : Of", + "identifier : Store", + "identifier : Struct_var", + "identifier : Then", + "identifier : Tmp_cset", + "identifier : Tmp_string", + "identifier : TokType", + "identifier : Underef", + "identifier : Variable", + "op_name : identifier", + "op_name : typedefname", + "op_name : Auto", + "op_name : Break", + "op_name : Case", + "op_name : Char", + "op_name : Cnv", + "op_name : Const", + "op_name : Continue", + "op_name : Def", + "op_name : Default", + "op_name : Do", + "op_name : Doubl", + "op_name : Else", + "op_name : Enum", + "op_name : Errorfail", + "op_name : Extern", + "op_name : Fail", + "op_name : Float", + "op_name : For", + "op_name : Function", + "op_name : Goto", + "op_name : If", + "op_name : Int", + "op_name : Is", + "op_name : Keyword", + "op_name : Long", + "op_name : Operator", + "op_name : Register", + "op_name : Return", + "op_name : Runerr", + "op_name : Short", + "op_name : Signed", + "op_name : Sizeof", + "op_name : Static", + "op_name : Struct", + "op_name : Suspend", + "op_name : Switch", + "op_name : Tended", + "op_name : Typedef", + "op_name : Union", + "op_name : Unsigned", + "op_name : Void", + "op_name : Volatile", + "op_name : While", + "result_seq : /* empty */", + "result_seq : length opt_plus", + "result_seq : length ',' length opt_plus", + "length : IntConst", + "length : '*'", + "opt_plus : /* empty */", + "opt_plus : '+'", + "opt_s_parm_lst : /* empty */", + "opt_s_parm_lst : s_parm_lst", + "opt_s_parm_lst : s_parm_lst '[' identifier ']'", + "s_parm_lst : s_parm", + "s_parm_lst : s_parm_lst ',' s_parm", + "s_parm : identifier", + "s_parm : Underef identifier", + "s_parm : Underef identifier Arrow identifier", + "op_declare : /* empty */", + "op_declare : Declare '{' local_dcls '}'", + "opt_actions : /* empty */", + "opt_actions : actions", + "actions : action", + "actions : actions action", + "action : checking_conversions", + "action : detail_code", + "action : runerr", + "action : '{' opt_actions '}'", + "action : Abstract", + "action : Abstract '{' type_computations", + "action : Abstract '{' type_computations '}'", + "checking_conversions : If type_check Then action", + "checking_conversions : If type_check Then action Else action", + "checking_conversions : Type_case variable Of '{' type_select_lst opt_default '}'", + "checking_conversions : Len_case identifier Of '{' len_select_lst Default ':' action '}'", + "checking_conversions : Arith_case '(' variable ',' variable ')' Of '{' dest_type ':' action dest_type ':' action dest_type ':' action '}'", + "type_select_lst : type_select", + "type_select_lst : type_select_lst type_select", + "type_select : selector_lst action", + "opt_default : /* empty */", + "opt_default : Default ':' action", + "selector_lst : i_type_name ':'", + "selector_lst : selector_lst i_type_name ':'", + "len_select_lst : len_select", + "len_select_lst : len_select_lst len_select", + "len_select : IntConst ':' action", + "type_check : simple_check_conj", + "type_check : '!' simple_check", + "simple_check_conj : simple_check", + "simple_check_conj : simple_check_conj And simple_check", + "simple_check : Is ':' i_type_name '(' variable ')'", + "simple_check : Cnv ':' dest_type '(' variable ')'", + "simple_check : Cnv ':' dest_type '(' variable ',' assign_expr ')'", + "simple_check : Def ':' dest_type '(' variable ',' assign_expr ')'", + "simple_check : Def ':' dest_type '(' variable ',' assign_expr ',' assign_expr ')'", + "detail_code : Body", + "detail_code : Body compound_stmt", + "detail_code : Inline", + "detail_code : Inline compound_stmt", + "runerr : Runerr '(' IntConst ')' opt_semi", + "runerr : Runerr '(' IntConst ',' variable ')' opt_semi", + "opt_semi : /* empty */", + "opt_semi : ';'", + "variable : identifier", + "variable : identifier '[' IntConst ']'", + "dest_type : IconType", + "dest_type : C_Integer", + "dest_type : C_Double", + "dest_type : C_String", + "dest_type : Tmp_string", + "dest_type : Tmp_cset", + "dest_type : '(' Exact ')' IconType", + "dest_type : '(' Exact ')' C_Integer", + "i_type_name : Any_value", + "i_type_name : Empty_type", + "i_type_name : IconType", + "i_type_name : Variable", + "ret_val : opt_expr", + "ret_val : C_Integer assign_expr", + "ret_val : C_Double assign_expr", + "ret_val : C_String assign_expr", + "type_computations : side_effect_lst Return type opt_semi", + "type_computations : Return type opt_semi", + "type_computations : side_effect_lst", + "side_effect_lst : side_effect", + "side_effect_lst : side_effect_lst side_effect", + "side_effect : Store '[' type ']' '=' type opt_semi", + "type : basic_type", + "type : type union basic_type", + "type : type Intersect basic_type", + "basic_type : i_type_name", + "basic_type : TokType '(' variable ')'", + "basic_type : New i_type_name '(' type_lst ')'", + "basic_type : Store '[' type ']'", + "basic_type : basic_type '.' attrb_name", + "basic_type : '(' type ')'", + "union : Incr", + "type_lst : type", + "type_lst : type_lst ',' type", + "attrb_name : Component", + "attrb_name : All_fields", +}; +#endif /* YYDEBUG */ +#line 1 "/usr/lib/yaccpar" +/* @(#)yaccpar 1.10 89/04/04 SMI; from S5R3 1.10 */ + +/* +** Skeleton parser driver for yacc output +*/ + +/* +** yacc user known macros and defines +*/ +#define YYERROR goto yyerrlab +#define YYACCEPT { free(yys); free(yyv); return(0); } +#define YYABORT { free(yys); free(yyv); return(1); } +#define YYBACKUP( newtoken, newvalue )\ +{\ + if ( yychar >= 0 || ( yyr2[ yytmp ] >> 1 ) != 1 )\ + {\ + yyerror( "syntax error - cannot backup" );\ + goto yyerrlab;\ + }\ + yychar = newtoken;\ + yystate = *yyps;\ + yylval = newvalue;\ + goto yynewstate;\ +} +#define YYRECOVERING() (!!yyerrflag) +#ifndef YYDEBUG +# define YYDEBUG 1 /* make debugging available */ +#endif + +/* +** user known globals +*/ +int yydebug; /* set to 1 to get debugging */ + +/* +** driver internal defines +*/ +#define YYFLAG (-1000) + +/* +** static variables used by the parser +*/ +static YYSTYPE *yyv; /* value stack */ +static int *yys; /* state stack */ + +static YYSTYPE *yypv; /* top of value stack */ +static int *yyps; /* top of state stack */ + +static int yystate; /* current state */ +static int yytmp; /* extra var (lasts between blocks) */ + +int yynerrs; /* number of errors */ + +int yyerrflag; /* error recovery flag */ +int yychar; /* current input token number */ + + +/* +** yyparse - return 0 if worked, 1 if syntax error not recovered from +*/ +int +yyparse() +{ + register YYSTYPE *yypvt; /* top of value stack for $vars */ + unsigned yymaxdepth = YYMAXDEPTH; + + /* + ** Initialize externals - yyparse may be called more than once + */ + yyv = (YYSTYPE*)malloc(yymaxdepth*sizeof(YYSTYPE)); + yys = (int*)malloc(yymaxdepth*sizeof(int)); + if (!yyv || !yys) + { + yyerror( "out of memory" ); + return(1); + } + yypv = &yyv[-1]; + yyps = &yys[-1]; + yystate = 0; + yytmp = 0; + yynerrs = 0; + yyerrflag = 0; + yychar = -1; + + goto yystack; + { + register YYSTYPE *yy_pv; /* top of value stack */ + register int *yy_ps; /* top of state stack */ + register int yy_state; /* current state */ + register int yy_n; /* internal state number info */ + + /* + ** get globals into registers. + ** branch to here only if YYBACKUP was called. + */ + yynewstate: + yy_pv = yypv; + yy_ps = yyps; + yy_state = yystate; + goto yy_newstate; + + /* + ** get globals into registers. + ** either we just started, or we just finished a reduction + */ + yystack: + yy_pv = yypv; + yy_ps = yyps; + yy_state = yystate; + + /* + ** top of for (;;) loop while no reductions done + */ + yy_stack: + /* + ** put a state and value onto the stacks + */ +#if YYDEBUG + /* + ** if debugging, look up token value in list of value vs. + ** name pairs. 0 and negative (-1) are special values. + ** Note: linear search is used since time is not a real + ** consideration while debugging. + */ + if ( yydebug ) + { + register int yy_i; + + (void)printf( "State %d, token ", yy_state ); + if ( yychar == 0 ) + (void)printf( "end-of-file\n" ); + else if ( yychar < 0 ) + (void)printf( "-none-\n" ); + else + { + for ( yy_i = 0; yytoks[yy_i].t_val >= 0; + yy_i++ ) + { + if ( yytoks[yy_i].t_val == yychar ) + break; + } + (void)printf( "%s\n", yytoks[yy_i].t_name ); + } + } +#endif /* YYDEBUG */ + if ( ++yy_ps >= &yys[ yymaxdepth ] ) /* room on stack? */ + { + /* + ** reallocate and recover. Note that pointers + ** have to be reset, or bad things will happen + */ + int yyps_index = (yy_ps - yys); + int yypv_index = (yy_pv - yyv); + int yypvt_index = (yypvt - yyv); + yymaxdepth += YYMAXDEPTH; + yyv = (YYSTYPE*)realloc((char*)yyv, + yymaxdepth * sizeof(YYSTYPE)); + yys = (int*)realloc((char*)yys, + yymaxdepth * sizeof(int)); + if (!yyv || !yys) + { + yyerror( "yacc stack overflow" ); + return(1); + } + yy_ps = yys + yyps_index; + yy_pv = yyv + yypv_index; + yypvt = yyv + yypvt_index; + } + *yy_ps = yy_state; + *++yy_pv = yyval; + + /* + ** we have a new state - find out what to do + */ + yy_newstate: + if ( ( yy_n = yypact[ yy_state ] ) <= YYFLAG ) + goto yydefault; /* simple state */ +#if YYDEBUG + /* + ** if debugging, need to mark whether new token grabbed + */ + yytmp = yychar < 0; +#endif + if ( ( yychar < 0 ) && ( ( yychar = yylex() ) < 0 ) ) + yychar = 0; /* reached EOF */ +#if YYDEBUG + if ( yydebug && yytmp ) + { + register int yy_i; + + (void)printf( "Received token " ); + if ( yychar == 0 ) + (void)printf( "end-of-file\n" ); + else if ( yychar < 0 ) + (void)printf( "-none-\n" ); + else + { + for ( yy_i = 0; yytoks[yy_i].t_val >= 0; + yy_i++ ) + { + if ( yytoks[yy_i].t_val == yychar ) + break; + } + (void)printf( "%s\n", yytoks[yy_i].t_name ); + } + } +#endif /* YYDEBUG */ + if ( ( ( yy_n += yychar ) < 0 ) || ( yy_n >= YYLAST ) ) + goto yydefault; + if ( yychk[ yy_n = yyact[ yy_n ] ] == yychar ) /*valid shift*/ + { + yychar = -1; + yyval = yylval; + yy_state = yy_n; + if ( yyerrflag > 0 ) + yyerrflag--; + goto yy_stack; + } + + yydefault: + if ( ( yy_n = yydef[ yy_state ] ) == -2 ) + { +#if YYDEBUG + yytmp = yychar < 0; +#endif + if ( ( yychar < 0 ) && ( ( yychar = yylex() ) < 0 ) ) + yychar = 0; /* reached EOF */ +#if YYDEBUG + if ( yydebug && yytmp ) + { + register int yy_i; + + (void)printf( "Received token " ); + if ( yychar == 0 ) + (void)printf( "end-of-file\n" ); + else if ( yychar < 0 ) + (void)printf( "-none-\n" ); + else + { + for ( yy_i = 0; + yytoks[yy_i].t_val >= 0; + yy_i++ ) + { + if ( yytoks[yy_i].t_val + == yychar ) + { + break; + } + } + (void)printf( "%s\n", yytoks[yy_i].t_name ); + } + } +#endif /* YYDEBUG */ + /* + ** look through exception table + */ + { + register int *yyxi = yyexca; + + while ( ( *yyxi != -1 ) || + ( yyxi[1] != yy_state ) ) + { + yyxi += 2; + } + while ( ( *(yyxi += 2) >= 0 ) && + ( *yyxi != yychar ) ) + ; + if ( ( yy_n = yyxi[1] ) < 0 ) + YYACCEPT; + } + } + + /* + ** check for syntax error + */ + if ( yy_n == 0 ) /* have an error */ + { + /* no worry about speed here! */ + switch ( yyerrflag ) + { + case 0: /* new error */ + yyerror( "syntax error" ); + goto skip_init; + yyerrlab: + /* + ** get globals into registers. + ** we have a user generated syntax type error + */ + yy_pv = yypv; + yy_ps = yyps; + yy_state = yystate; + yynerrs++; + skip_init: + case 1: + case 2: /* incompletely recovered error */ + /* try again... */ + yyerrflag = 3; + /* + ** find state where "error" is a legal + ** shift action + */ + while ( yy_ps >= yys ) + { + yy_n = yypact[ *yy_ps ] + YYERRCODE; + if ( yy_n >= 0 && yy_n < YYLAST && + yychk[yyact[yy_n]] == YYERRCODE) { + /* + ** simulate shift of "error" + */ + yy_state = yyact[ yy_n ]; + goto yy_stack; + } + /* + ** current state has no shift on + ** "error", pop stack + */ +#if YYDEBUG +# define _POP_ "Error recovery pops state %d, uncovers state %d\n" + if ( yydebug ) + (void)printf( _POP_, *yy_ps, + yy_ps[-1] ); +# undef _POP_ +#endif + yy_ps--; + yy_pv--; + } + /* + ** there is no state on stack with "error" as + ** a valid shift. give up. + */ + YYABORT; + case 3: /* no shift yet; eat a token */ +#if YYDEBUG + /* + ** if debugging, look up token in list of + ** pairs. 0 and negative shouldn't occur, + ** but since timing doesn't matter when + ** debugging, it doesn't hurt to leave the + ** tests here. + */ + if ( yydebug ) + { + register int yy_i; + + (void)printf( "Error recovery discards " ); + if ( yychar == 0 ) + (void)printf( "token end-of-file\n" ); + else if ( yychar < 0 ) + (void)printf( "token -none-\n" ); + else + { + for ( yy_i = 0; + yytoks[yy_i].t_val >= 0; + yy_i++ ) + { + if ( yytoks[yy_i].t_val + == yychar ) + { + break; + } + } + (void)printf( "token %s\n", + yytoks[yy_i].t_name ); + } + } +#endif /* YYDEBUG */ + if ( yychar == 0 ) /* reached EOF. quit */ + YYABORT; + yychar = -1; + goto yy_newstate; + } + }/* end if ( yy_n == 0 ) */ + /* + ** reduction by production yy_n + ** put stack tops, etc. so things right after switch + */ +#if YYDEBUG + /* + ** if debugging, print the string that is the user's + ** specification of the reduction which is just about + ** to be done. + */ + if ( yydebug ) + (void)printf( "Reduce by (%d) \"%s\"\n", + yy_n, yyreds[ yy_n ] ); +#endif + yytmp = yy_n; /* value to switch over */ + yypvt = yy_pv; /* $vars top of value stack */ + /* + ** Look in goto table for next state + ** Sorry about using yy_state here as temporary + ** register variable, but why not, if it works... + ** If yyr2[ yy_n ] doesn't have the low order bit + ** set, then there is no action to be done for + ** this reduction. So, no saving & unsaving of + ** registers done. The only difference between the + ** code just after the if and the body of the if is + ** the goto yy_stack in the body. This way the test + ** can be made before the choice of what to do is needed. + */ + { + /* length of production doubled with extra bit */ + register int yy_len = yyr2[ yy_n ]; + + if ( !( yy_len & 01 ) ) + { + yy_len >>= 1; + yyval = ( yy_pv -= yy_len )[1]; /* $$ = $1 */ + yy_state = yypgo[ yy_n = yyr1[ yy_n ] ] + + *( yy_ps -= yy_len ) + 1; + if ( yy_state >= YYLAST || + yychk[ yy_state = + yyact[ yy_state ] ] != -yy_n ) + { + yy_state = yyact[ yypgo[ yy_n ] ]; + } + goto yy_stack; + } + yy_len >>= 1; + yyval = ( yy_pv -= yy_len )[1]; /* $$ = $1 */ + yy_state = yypgo[ yy_n = yyr1[ yy_n ] ] + + *( yy_ps -= yy_len ) + 1; + if ( yy_state >= YYLAST || + yychk[ yy_state = yyact[ yy_state ] ] != -yy_n ) + { + yy_state = yyact[ yypgo[ yy_n ] ]; + } + } + /* save until reenter driver code */ + yystate = yy_state; + yyps = yy_ps; + yypv = yy_pv; + } + /* + ** code supplied by user is placed in this switch + */ + switch( yytmp ) + { + +case 1: +# line 81 "rttgram.y" +{yyval.n = sym_node(yypvt[-0].t);} break; +case 2: +# line 82 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 3: +# line 83 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 4: +# line 84 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 5: +# line 85 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 6: +# line 86 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 7: +# line 87 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 8: +# line 88 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 9: +# line 89 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 10: +# line 90 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 11: +# line 91 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 12: +# line 92 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 13: +# line 93 "rttgram.y" +{yyval.n = node1(PrefxNd, yypvt[-2].t, yypvt[-1].n); free_t(yypvt[-0].t);} break; +case 15: +# line 98 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-2].t, yypvt[-3].n, yypvt[-1].n); + free_t(yypvt[-0].t);} break; +case 16: +# line 100 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-0].t, yypvt[-2].n, NULL); + free_t(yypvt[-1].t);} break; +case 17: +# line 102 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-0].t, yypvt[-3].n, yypvt[-1].n); + free_t(yypvt[-2].t);} break; +case 18: +# line 104 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 19: +# line 105 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 20: +# line 106 "rttgram.y" +{yyval.n = node1(PstfxNd, yypvt[-0].t, yypvt[-1].n);} break; +case 21: +# line 107 "rttgram.y" +{yyval.n = node1(PstfxNd, yypvt[-0].t, yypvt[-1].n);} break; +case 22: +# line 109 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-5].t, yypvt[-3].n, yypvt[-1].n); free_t(yypvt[-4].t); free_t(yypvt[-2].t); free_t(yypvt[-0].t);} break; +case 23: +# line 111 "rttgram.y" +{yyval.n = node3(TrnryNd, yypvt[-7].t, yypvt[-5].n, yypvt[-3].n, yypvt[-1].n), free_t(yypvt[-6].t); free_t(yypvt[-4].t); free_t(yypvt[-2].t); + free_t(yypvt[-0].t);} break; +case 24: +# line 114 "rttgram.y" +{yyval.n = node4(QuadNd, yypvt[-9].t, yypvt[-7].n, yypvt[-5].n, yypvt[-3].n, yypvt[-1].n), free_t(yypvt[-8].t); free_t(yypvt[-6].t); + free_t(yypvt[-4].t); free_t(yypvt[-2].t); free_t(yypvt[-0].t);} break; +case 26: +# line 120 "rttgram.y" +{yyval.n = node2(CommaNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 28: +# line 125 "rttgram.y" +{yyval.n = node1(PrefxNd, yypvt[-1].t, yypvt[-0].n);} break; +case 29: +# line 126 "rttgram.y" +{yyval.n = node1(PrefxNd, yypvt[-1].t, yypvt[-0].n);} break; +case 30: +# line 127 "rttgram.y" +{yyval.n = node1(PrefxNd, yypvt[-1].t, yypvt[-0].n);} break; +case 31: +# line 128 "rttgram.y" +{yyval.n = node1(PrefxNd, yypvt[-1].t, yypvt[-0].n);} break; +case 32: +# line 129 "rttgram.y" +{yyval.n = node1(PrefxNd, yypvt[-3].t, yypvt[-1].n); + free_t(yypvt[-2].t); free_t(yypvt[-0].t);} break; +case 40: +# line 144 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-3].t, yypvt[-2].n, yypvt[-0].n); free_t(yypvt[-1].t);} break; +case 42: +# line 149 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 43: +# line 150 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 44: +# line 151 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 46: +# line 156 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 47: +# line 157 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 49: +# line 162 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 50: +# line 163 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 52: +# line 168 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 53: +# line 169 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 54: +# line 170 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 55: +# line 171 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 57: +# line 176 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 58: +# line 177 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 60: +# line 182 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 62: +# line 187 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 64: +# line 192 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 66: +# line 197 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 68: +# line 202 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 70: +# line 208 "rttgram.y" +{yyval.n = node3(TrnryNd, yypvt[-3].t, yypvt[-4].n, yypvt[-2].n, yypvt[-0].n); + free_t(yypvt[-1].t);} break; +case 72: +# line 214 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 85: +# line 233 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 86: +# line 237 "rttgram.y" +{yyval.n = NULL;} break; +case 89: +# line 246 "rttgram.y" +{yyval.n = NULL;} break; +case 91: +# line 251 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-0].t, yypvt[-1].n, NULL); + dcl_stk->kind_dcl = OtherDcl;} break; +case 92: +# line 253 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-0].t, yypvt[-2].n, yypvt[-1].n); + dcl_stk->kind_dcl = OtherDcl;} break; +case 93: +# line 256 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-0].t, yypvt[-2].n, yypvt[-1].n); + dcl_stk->kind_dcl = OtherDcl;} break; +case 95: +# line 262 "rttgram.y" +{yyval.n = node2(LstNd, NULL, yypvt[-1].n, yypvt[-0].n);} break; +case 98: +# line 271 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 99: +# line 273 "rttgram.y" +{yyval.n = node2(LstNd, NULL, node0(PrimryNd, yypvt[-1].t), yypvt[-0].n);} break; +case 102: +# line 279 "rttgram.y" +{yyval.n = node2(LstNd, NULL, yypvt[-1].n, yypvt[-0].n);} break; +case 103: +# line 280 "rttgram.y" +{yyval.n = node2(LstNd, NULL, yypvt[-1].n, yypvt[-0].n);} break; +case 104: +# line 281 "rttgram.y" +{yyval.n = node2(LstNd, NULL, yypvt[-1].n, yypvt[-0].n);} break; +case 107: +# line 287 "rttgram.y" +{yyval.n = node2(LstNd, NULL, yypvt[-1].n, yypvt[-0].n);} break; +case 108: +# line 288 "rttgram.y" +{yyval.n = node2(LstNd, NULL, yypvt[-1].n, yypvt[-0].n);} break; +case 110: +# line 293 "rttgram.y" +{yyval.n = node2(CommaNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 112: +# line 299 "rttgram.y" +{yyval.n = node2(CommaNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 113: +# line 303 "rttgram.y" +{yyval.n = yypvt[-0].n; id_def(yypvt[-0].n, NULL);} break; +case 114: +# line 304 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n); id_def(yypvt[-2].n, yypvt[-0].n);} break; +case 115: +# line 308 "rttgram.y" +{yyval.n = yypvt[-0].n; id_def(yypvt[-0].n, NULL);} break; +case 116: +# line 310 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n); id_def(yypvt[-2].n, yypvt[-0].n);} break; +case 117: +# line 314 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t); dcl_stk->kind_dcl = IsTypedef;} break; +case 118: +# line 315 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 119: +# line 316 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 120: +# line 317 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 121: +# line 318 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 123: +# line 323 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 124: +# line 327 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 125: +# line 328 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 126: +# line 329 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 127: +# line 330 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 128: +# line 331 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 129: +# line 332 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 130: +# line 333 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 131: +# line 334 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 132: +# line 335 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 135: +# line 342 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-4].t, yypvt[-3].n, yypvt[-1].n); + free_t(yypvt[-2].t); free_t(yypvt[-0].t);} break; +case 136: +# line 345 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-3].t, NULL, yypvt[-1].n); + free_t(yypvt[-2].t); free_t(yypvt[-0].t);} break; +case 137: +# line 347 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-1].t, yypvt[-0].n, NULL);} break; +case 141: +# line 357 "rttgram.y" +{yyval.n = node2(LstNd, NULL, yypvt[-1].n, yypvt[-0].n);} break; +case 142: +# line 362 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-0].t, yypvt[-2].n, yypvt[-1].n);} break; +case 143: +# line 363 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-0].t, yypvt[-2].n, yypvt[-1].n);} break; +case 145: +# line 368 "rttgram.y" +{yyval.n = node2(LstNd, NULL, yypvt[-1].n, yypvt[-0].n);} break; +case 146: +# line 372 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 147: +# line 373 "rttgram.y" +{yyval.n = node2(LstNd, NULL, node0(PrimryNd, yypvt[-1].t), yypvt[-0].n);} break; +case 150: +# line 379 "rttgram.y" +{yyval.n = node2(LstNd, NULL, yypvt[-1].n, yypvt[-0].n);} break; +case 151: +# line 380 "rttgram.y" +{yyval.n = node2(LstNd, NULL, yypvt[-1].n, yypvt[-0].n);} break; +case 153: +# line 384 "rttgram.y" +{yyval.n = node2(CommaNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 154: +# line 388 "rttgram.y" +{yyval.n = node2(StrDclNd, NULL, yypvt[-0].n, NULL); + if (dcl_stk->parms_done) pop_cntxt();} break; +case 155: +# line 390 "rttgram.y" +{yyval.n = node2(StrDclNd, yypvt[-1].t, NULL, yypvt[-0].n);} break; +case 156: +# line 391 "rttgram.y" +{if (dcl_stk->parms_done) pop_cntxt();} break; +case 157: +# line 392 "rttgram.y" +{yyval.n = node2(StrDclNd, yypvt[-2].t, yypvt[-3].n, yypvt[-0].n);} break; +case 159: +# line 398 "rttgram.y" +{yyval.n = node2(CommaNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 160: +# line 402 "rttgram.y" +{yyval.n = node2(StrDclNd, NULL, yypvt[-0].n, NULL); + if (dcl_stk->parms_done) pop_cntxt();} break; +case 161: +# line 404 "rttgram.y" +{yyval.n = node2(StrDclNd, yypvt[-1].t, NULL, yypvt[-0].n);} break; +case 162: +# line 405 "rttgram.y" +{if (dcl_stk->parms_done) pop_cntxt();} break; +case 163: +# line 406 "rttgram.y" +{yyval.n = node2(StrDclNd, yypvt[-2].t, yypvt[-3].n, yypvt[-0].n);} break; +case 164: +# line 410 "rttgram.y" +{push_cntxt(0);} break; +case 165: +# line 411 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-4].t, NULL, yypvt[-1].n); pop_cntxt(); free_t(yypvt[-2].t); free_t(yypvt[-0].t);} break; +case 166: +# line 412 "rttgram.y" +{push_cntxt(0);} break; +case 167: +# line 413 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-5].t, yypvt[-4].n, yypvt[-1].n); pop_cntxt(); free_t(yypvt[-2].t); free_t(yypvt[-0].t);} break; +case 168: +# line 414 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-1].t, yypvt[-0].n, NULL);} break; +case 170: +# line 419 "rttgram.y" +{yyval.n = node2(CommaNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 171: +# line 423 "rttgram.y" +{yyval.n = yypvt[-0].n; id_def(yypvt[-0].n, NULL);} break; +case 172: +# line 425 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n); id_def(yypvt[-2].n, yypvt[-0].n);} break; +case 173: +# line 429 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 174: +# line 430 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 175: +# line 435 "rttgram.y" +{yyval.n = node2(ConCatNd, NULL, yypvt[-1].n, yypvt[-0].n);} break; +case 176: +# line 439 "rttgram.y" +{yyval.n = node2(ConCatNd, NULL, yypvt[-1].n, yypvt[-0].n);} break; +case 178: +# line 444 "rttgram.y" +{yyval.n = node1(PrefxNd, yypvt[-2].t, yypvt[-1].n); + free_t(yypvt[-0].t);} break; +case 179: +# line 446 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-2].t, yypvt[-3].n, yypvt[-1].n); + free_t(yypvt[-0].t);} break; +case 180: +# line 448 "rttgram.y" +{push_cntxt(1);} break; +case 181: +# line 449 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-0].t, yypvt[-4].n, yypvt[-1].n); + if (dcl_stk->nest_lvl == 2) + dcl_stk->parms_done = 1; + else + pop_cntxt(); + free_t(yypvt[-3].t);} break; +case 182: +# line 458 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 183: +# line 459 "rttgram.y" +{yyval.n = node1(PrefxNd, yypvt[-2].t, yypvt[-1].n); + free_t(yypvt[-0].t);} break; +case 184: +# line 462 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-2].t, yypvt[-3].n, yypvt[-1].n); + free_t(yypvt[-0].t);} break; +case 185: +# line 464 "rttgram.y" +{push_cntxt(1);} break; +case 186: +# line 465 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-0].t, yypvt[-4].n, yypvt[-1].n); + if (dcl_stk->nest_lvl == 2) + dcl_stk->parms_done = 1; + else + pop_cntxt(); + free_t(yypvt[-3].t);} break; +case 189: +# line 479 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 190: +# line 480 "rttgram.y" +{yyval.n = node1(PreSpcNd, yypvt[-1].t, yypvt[-0].n);} break; +case 191: +# line 481 "rttgram.y" +{yyval.n = node1(PrefxNd, yypvt[-1].t, yypvt[-0].n);} break; +case 192: +# line 482 "rttgram.y" +{yyval.n = node1(PrefxNd, yypvt[-2].t, node2(LstNd, NULL, yypvt[-1].n,yypvt[-0].n));} break; +case 193: +# line 486 "rttgram.y" +{yyval.n = NULL;} break; +case 196: +# line 492 "rttgram.y" +{yyval.n = node2(LstNd, NULL, yypvt[-1].n, yypvt[-0].n);} break; +case 198: +# line 497 "rttgram.y" +{yyval.n = node2(CommaNd, yypvt[-1].t, yypvt[-2].n, node0(PrimryNd, yypvt[-0].t));} break; +case 199: +# line 501 "rttgram.y" +{yyval.n = NULL;} break; +case 202: +# line 507 "rttgram.y" +{yyval.n = node2(CommaNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 203: +# line 511 "rttgram.y" +{yyval.n = node2(LstNd, NULL, yypvt[-1].n, yypvt[-0].n); + id_def(yypvt[-0].n, NULL);} break; +case 205: +# line 514 "rttgram.y" +{yyval.n = node2(LstNd, NULL, yypvt[-1].n, yypvt[-0].n);} break; +case 206: +# line 518 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 207: +# line 519 "rttgram.y" +{yyval.n = node2(CommaNd, yypvt[-1].t, yypvt[-2].n, node0(PrimryNd,yypvt[-0].t));} break; +case 210: +# line 525 "rttgram.y" +{yyval.n = node2(LstNd, NULL, yypvt[-1].n, yypvt[-0].n);} break; +case 211: +# line 526 "rttgram.y" +{yyval.n = node2(LstNd, NULL, yypvt[-1].n, yypvt[-0].n);} break; +case 213: +# line 531 "rttgram.y" +{yyval.n = node2(LstNd, NULL, yypvt[-1].n, yypvt[-0].n);} break; +case 215: +# line 536 "rttgram.y" +{yyval.n = node2(ConCatNd, NULL, yypvt[-1].n, yypvt[-0].n);} break; +case 216: +# line 540 "rttgram.y" +{yyval.n = node1(PrefxNd, yypvt[-2].t, yypvt[-1].n); + free_t(yypvt[-0].t);} break; +case 217: +# line 543 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-2].t, NULL, yypvt[-1].n); + free_t(yypvt[-0].t);} break; +case 218: +# line 546 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-2].t, yypvt[-3].n, yypvt[-1].n); + free_t(yypvt[-0].t);} break; +case 219: +# line 548 "rttgram.y" +{push_cntxt(1);} break; +case 220: +# line 549 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-0].t, NULL, yypvt[-1].n); + pop_cntxt(); + free_t(yypvt[-3].t);} break; +case 221: +# line 552 "rttgram.y" +{push_cntxt(1);} break; +case 222: +# line 553 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-0].t, yypvt[-4].n, yypvt[-1].n); + pop_cntxt(); + free_t(yypvt[-3].t);} break; +case 224: +# line 561 "rttgram.y" +{yyval.n = node1(PrefxNd, yypvt[-2].t, yypvt[-1].n); free_t(yypvt[-0].t);} break; +case 225: +# line 563 "rttgram.y" +{yyval.n = node1(PrefxNd, yypvt[-3].t, node2(CommaNd, yypvt[-1].t, yypvt[-2].n, NULL)); + free_t(yypvt[-0].t);} break; +case 227: +# line 569 "rttgram.y" +{yyval.n = node2(CommaNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 230: +# line 578 "rttgram.y" +{push_cntxt(1);} break; +case 231: +# line 578 "rttgram.y" +{yyval.n = yypvt[-0].n; pop_cntxt();} break; +case 236: +# line 584 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-4].t, yypvt[-2].n, NULL); free_t(yypvt[-3].t); free_t(yypvt[-1].t);} break; +case 237: +# line 586 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-6].t, yypvt[-4].n, yypvt[-2].n); free_t(yypvt[-5].t); free_t(yypvt[-3].t); free_t(yypvt[-1].t);} break; +case 238: +# line 590 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 239: +# line 591 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-3].t, yypvt[-2].n, yypvt[-0].n); free_t(yypvt[-1].t);} break; +case 240: +# line 592 "rttgram.y" +{yyval.n = node1(PrefxNd, yypvt[-2].t, yypvt[-0].n); free_t(yypvt[-1].t);} break; +case 241: +# line 596 "rttgram.y" +{yyval.n = comp_nd(yypvt[-2].t, NULL, yypvt[-1].n); free_t(yypvt[-0].t);} break; +case 242: +# line 597 "rttgram.y" +{yyval.n = comp_nd(yypvt[-3].t, yypvt[-2].n, yypvt[-1].n); free_t(yypvt[-0].t);} break; +case 244: +# line 602 "rttgram.y" +{yyval.n = node2(LstNd, NULL, yypvt[-1].n, yypvt[-0].n);} break; +case 245: +# line 606 "rttgram.y" +{yyval.n = NULL;} break; +case 248: +# line 612 "rttgram.y" +{yyval.n = (yypvt[-0].n == NULL ? yypvt[-1].n : node2(LstNd, NULL, yypvt[-1].n, yypvt[-0].n));} break; +case 250: +# line 618 "rttgram.y" +{yyval.n = NULL; free_t(yypvt[-3].t); free_t(yypvt[-0].t); dcl_stk->kind_dcl = OtherDcl;} break; +case 251: +# line 622 "rttgram.y" +{tnd_char(); free_t(yypvt[-0].t);} break; +case 252: +# line 623 "rttgram.y" +{tnd_strct(yypvt[-0].t); free_t(yypvt[-1].t);} break; +case 253: +# line 624 "rttgram.y" +{tnd_strct(yypvt[-0].t); free_t(yypvt[-1].t);} break; +case 254: +# line 625 "rttgram.y" +{tnd_union(yypvt[-0].t); free_t(yypvt[-1].t);} break; +case 256: +# line 630 "rttgram.y" +{yyval.n = node2(ConCatNd, NULL, yypvt[-1].n, yypvt[-0].n);} break; +case 257: +# line 634 "rttgram.y" +{yyval.n = NULL;} break; +case 259: +# line 638 "rttgram.y" +{yyval.n = node1(PstfxNd, yypvt[-0].t, yypvt[-1].n);} break; +case 260: +# line 642 "rttgram.y" +{yyval.n = node3(TrnryNd, yypvt[-4].t, yypvt[-2].n, yypvt[-0].n,NULL); + free_t(yypvt[-3].t); free_t(yypvt[-1].t);} break; +case 261: +# line 644 "rttgram.y" +{yyval.n = node3(TrnryNd, yypvt[-6].t, yypvt[-4].n, yypvt[-2].n, yypvt[-0].n); + free_t(yypvt[-5].t); free_t(yypvt[-3].t); free_t(yypvt[-1].t);} break; +case 262: +# line 646 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-4].t, yypvt[-2].n, yypvt[-0].n); + free_t(yypvt[-3].t); free_t(yypvt[-1].t);} break; +case 263: +# line 649 "rttgram.y" +{yyval.n = node3(TrnryNd, yypvt[-6].t, yypvt[-5].n, yypvt[-2].n, yypvt[-1].n); free_t(yypvt[-4].t); free_t(yypvt[-3].t); free_t(yypvt[-0].t);} break; +case 264: +# line 653 "rttgram.y" +{yyval.n = node2(ConCatNd, NULL, NULL, yypvt[-0].n);} break; +case 265: +# line 654 "rttgram.y" +{yyval.n = node2(ConCatNd, NULL, yypvt[-1].n, yypvt[-0].n);} break; +case 266: +# line 658 "rttgram.y" +{yyval.n = node2(ConCatNd, NULL, yypvt[-1].n, yypvt[-0].n);} break; +case 267: +# line 662 "rttgram.y" +{yyval.n = NULL;} break; +case 268: +# line 663 "rttgram.y" +{yyval.n = yypvt[-0].n; free_t(yypvt[-2].t); free_t(yypvt[-1].t);} break; +case 269: +# line 667 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-4].t, yypvt[-2].n, yypvt[-0].n); + free_t(yypvt[-3].t); free_t(yypvt[-1].t);} break; +case 270: +# line 669 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-6].t, yypvt[-5].n, yypvt[-2].n); + free_t(yypvt[-4].t); free_t(yypvt[-3].t); free_t(yypvt[-1].t); + free_t(yypvt[-0].t);} break; +case 271: +# line 673 "rttgram.y" +{yyval.n = node4(QuadNd, yypvt[-8].t, yypvt[-6].n, yypvt[-4].n, yypvt[-2].n, yypvt[-0].n); + free_t(yypvt[-7].t); free_t(yypvt[-5].t); free_t(yypvt[-3].t); + free_t(yypvt[-1].t);} break; +case 272: +# line 679 "rttgram.y" +{yyval.n = node1(PrefxNd, yypvt[-2].t, yypvt[-1].n); free_t(yypvt[-0].t);} break; +case 273: +# line 680 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-1].t); free_t(yypvt[-0].t);} break; +case 274: +# line 681 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-1].t); free_t(yypvt[-0].t);} break; +case 275: +# line 682 "rttgram.y" +{yyval.n = node1(PrefxNd, yypvt[-2].t, yypvt[-1].n); free_t(yypvt[-0].t);} break; +case 276: +# line 683 "rttgram.y" +{yyval.n = node1(PrefxNd, yypvt[-2].t, yypvt[-1].n); free_t(yypvt[-0].t);} break; +case 277: +# line 684 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-1].t); free_t(yypvt[-0].t);} break; +case 278: +# line 685 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-1].t); free_t(yypvt[-0].t);} break; +case 284: +# line 700 "rttgram.y" +{dclout(yypvt[-0].n);} break; +case 286: +# line 705 "rttgram.y" +{func_def(yypvt[-0].n);} break; +case 287: +# line 706 "rttgram.y" +{fncout(yypvt[-3].n, yypvt[-1].n, yypvt[-0].n);} break; +case 288: +# line 710 "rttgram.y" +{yyval.n = node2(LstNd, NULL, NULL, yypvt[-0].n);} break; +case 289: +# line 711 "rttgram.y" +{yyval.n = node2(LstNd, NULL, yypvt[-1].n, yypvt[-0].n);} break; +case 290: +# line 712 "rttgram.y" +{yyval.n = node2(LstNd, NULL, yypvt[-1].n, yypvt[-0].n);} break; +case 291: +# line 716 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 292: +# line 717 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 293: +# line 721 "rttgram.y" +{yyval.n = lbl(yypvt[-0].t);} break; +case 294: +# line 722 "rttgram.y" +{yyval.n = lbl(yypvt[-0].t);} break; +case 299: +# line 737 "rttgram.y" +{strt_def();} break; +case 301: +# line 741 "rttgram.y" +{defout(yypvt[-1].n); free_t(yypvt[-0].t);} break; +case 302: +# line 742 "rttgram.y" +{defout(yypvt[-1].n); free_t(yypvt[-0].t);} break; +case 303: +# line 743 "rttgram.y" +{keyconst(yypvt[-1].t); free_t(yypvt[-2].t); free_t(yypvt[-0].t);} break; +case 304: +# line 747 "rttgram.y" +{comment = NULL;} break; +case 305: +# line 748 "rttgram.y" +{comment = yypvt[-0].t;} break; +case 306: +# line 753 "rttgram.y" +{impl_fnc(yypvt[-3].t); free_t(yypvt[-7].t); free_t(yypvt[-6].t); free_t(yypvt[-4].t); free_t(yypvt[-2].t); + free_t(yypvt[-0].t);} break; +case 307: +# line 755 "rttgram.y" +{lex_state = OpHead;} break; +case 308: +# line 756 "rttgram.y" +{lex_state = DfltLex;} break; +case 309: +# line 757 "rttgram.y" +{impl_op(yypvt[-5].t, yypvt[-3].t); free_t(yypvt[-10].t); free_t(yypvt[-9].t); free_t(yypvt[-6].t); free_t(yypvt[-2].t); + free_t(yypvt[-0].t);} break; +case 310: +# line 762 "rttgram.y" +{impl_key(yypvt[-0].t); free_t(yypvt[-4].t); free_t(yypvt[-3].t); free_t(yypvt[-1].t);} break; +case 383: +# line 853 "rttgram.y" +{set_r_seq(NoRsltSeq, NoRsltSeq, 0);} break; +case 384: +# line 854 "rttgram.y" +{set_r_seq(yypvt[-1].i, yypvt[-1].i, (int)yypvt[-0].i);} break; +case 385: +# line 855 "rttgram.y" +{set_r_seq(yypvt[-3].i, yypvt[-1].i, (int)yypvt[-0].i); free_t(yypvt[-2].t);} break; +case 386: +# line 859 "rttgram.y" +{yyval.i = ttol(yypvt[-0].t); free_t(yypvt[-0].t);} break; +case 387: +# line 860 "rttgram.y" +{yyval.i = UnbndSeq; free_t(yypvt[-0].t);} break; +case 388: +# line 864 "rttgram.y" +{yyval.i = 0;} break; +case 389: +# line 865 "rttgram.y" +{yyval.i = 1; free_t(yypvt[-0].t);} break; +case 392: +# line 871 "rttgram.y" +{var_args(yypvt[-1].t); free_t(yypvt[-2].t); free_t(yypvt[-0].t);} break; +case 394: +# line 876 "rttgram.y" +{free_t(yypvt[-1].t);} break; +case 395: +# line 880 "rttgram.y" +{s_prm_def(NULL, yypvt[-0].t);} break; +case 396: +# line 881 "rttgram.y" +{s_prm_def(yypvt[-0].t, NULL); free_t(yypvt[-1].t);} break; +case 397: +# line 882 "rttgram.y" +{s_prm_def(yypvt[-2].t, yypvt[-0].t); free_t(yypvt[-3].t); + free_t(yypvt[-1].t);} break; +case 398: +# line 887 "rttgram.y" +{} break; +case 399: +# line 888 "rttgram.y" +{d_lst_typ(yypvt[-1].n); free_t(yypvt[-3].t); free_t(yypvt[-2].t); + free_t(yypvt[-0].t);} break; +case 400: +# line 893 "rttgram.y" +{yyval.n = NULL;} break; +case 403: +# line 899 "rttgram.y" +{yyval.n = node2(ConCatNd, NULL, yypvt[-1].n, yypvt[-0].n);} break; +case 407: +# line 906 "rttgram.y" +{yyval.n = node1(PrefxNd, yypvt[-2].t, yypvt[-1].n); free_t(yypvt[-0].t);} break; +case 408: +# line 907 "rttgram.y" +{lex_state = TypeComp;} break; +case 409: +# line 908 "rttgram.y" +{lex_state = DfltLex;} break; +case 410: +# line 909 "rttgram.y" +{yyval.n = yypvt[-2].n; free_t(yypvt[-5].t); free_t(yypvt[-3].t); free_t(yypvt[-0].t);} break; +case 411: +# line 914 "rttgram.y" +{yyval.n = node3(TrnryNd, yypvt[-3].t, yypvt[-2].n, yypvt[-0].n, NULL); free_t(yypvt[-1].t);} break; +case 412: +# line 916 "rttgram.y" +{yyval.n = node3(TrnryNd, yypvt[-5].t, yypvt[-4].n, yypvt[-2].n, yypvt[-0].n); free_t(yypvt[-3].t); free_t(yypvt[-1].t);} break; +case 413: +# line 918 "rttgram.y" +{yyval.n = node3(TrnryNd, yypvt[-6].t, yypvt[-5].n, yypvt[-2].n, yypvt[-1].n); free_t(yypvt[-4].t); free_t(yypvt[-3].t); free_t(yypvt[-0].t);} break; +case 414: +# line 920 "rttgram.y" +{yyval.n = node3(TrnryNd, yypvt[-8].t, sym_node(yypvt[-7].t), yypvt[-4].n, yypvt[-1].n); free_t(yypvt[-6].t), free_t(yypvt[-5].t); + free_t(yypvt[-3].t); free_t(yypvt[-2].t); free_t(yypvt[-0].t);} break; +case 415: +# line 924 "rttgram.y" +{yyval.n = arith_nd(yypvt[-17].t, yypvt[-15].n, yypvt[-13].n, yypvt[-9].n, yypvt[-7].n, yypvt[-6].n, yypvt[-4].n, yypvt[-3].n, yypvt[-1].n); free_t(yypvt[-16].t); + free_t(yypvt[-14].t), free_t(yypvt[-12].t); free_t(yypvt[-11].t); free_t(yypvt[-10].t); free_t(yypvt[-8].t); + free_t(yypvt[-5].t); free_t(yypvt[-2].t); free_t(yypvt[-0].t);} break; +case 416: +# line 930 "rttgram.y" +{yyval.n = node2(ConCatNd, NULL, NULL, yypvt[-0].n);} break; +case 417: +# line 931 "rttgram.y" +{yyval.n = node2(ConCatNd, NULL, yypvt[-1].n, yypvt[-0].n);} break; +case 418: +# line 935 "rttgram.y" +{yyval.n = node2(ConCatNd, NULL, yypvt[-1].n, yypvt[-0].n);} break; +case 419: +# line 939 "rttgram.y" +{yyval.n = NULL;} break; +case 420: +# line 940 "rttgram.y" +{yyval.n = yypvt[-0].n; free_t(yypvt[-2].t); free_t(yypvt[-1].t);} break; +case 421: +# line 944 "rttgram.y" +{yyval.n = node2(ConCatNd, NULL, NULL, yypvt[-1].n); + free_t(yypvt[-0].t);} break; +case 422: +# line 946 "rttgram.y" +{yyval.n = node2(ConCatNd, NULL, yypvt[-2].n, yypvt[-1].n); + free_t(yypvt[-0].t);} break; +case 424: +# line 952 "rttgram.y" +{yyval.n = node2(ConCatNd, NULL, yypvt[-1].n, yypvt[-0].n);} break; +case 425: +# line 956 "rttgram.y" +{yyval.n = node1(PrefxNd, yypvt[-2].t, yypvt[-0].n); free_t(yypvt[-1].t);} break; +case 427: +# line 961 "rttgram.y" +{yyval.n = node1(PrefxNd, yypvt[-1].t, yypvt[-0].n);} break; +case 429: +# line 966 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 430: +# line 971 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-5].t, yypvt[-3].n, yypvt[-1].n); free_t(yypvt[-4].t); free_t(yypvt[-2].t); free_t(yypvt[-0].t);} break; +case 431: +# line 973 "rttgram.y" +{yyval.n = node3(TrnryNd, yypvt[-5].t, yypvt[-3].n, yypvt[-1].n, NULL), dst_alloc(yypvt[-3].n, yypvt[-1].n); free_t(yypvt[-4].t); + free_t(yypvt[-2].t); free_t(yypvt[-0].t);} break; +case 432: +# line 976 "rttgram.y" +{yyval.n = node3(TrnryNd, yypvt[-7].t, yypvt[-5].n, yypvt[-3].n, yypvt[-1].n), free_t(yypvt[-6].t); free_t(yypvt[-4].t); free_t(yypvt[-2].t); + free_t(yypvt[-0].t);} break; +case 433: +# line 979 "rttgram.y" +{yyval.n = node4(QuadNd, yypvt[-7].t, yypvt[-5].n, yypvt[-3].n, yypvt[-1].n, NULL), dst_alloc(yypvt[-5].n, yypvt[-3].n); free_t(yypvt[-6].t); + free_t(yypvt[-4].t); free_t(yypvt[-2].t); free_t(yypvt[-0].t);} break; +case 434: +# line 982 "rttgram.y" +{yyval.n = node4(QuadNd, yypvt[-9].t, yypvt[-7].n, yypvt[-5].n, yypvt[-3].n, yypvt[-1].n), free_t(yypvt[-8].t); free_t(yypvt[-6].t); + free_t(yypvt[-4].t); free_t(yypvt[-2].t); free_t(yypvt[-0].t);} break; +case 435: +# line 987 "rttgram.y" +{push_cntxt(1);} break; +case 436: +# line 988 "rttgram.y" +{yyval.n = node1(PrefxNd, yypvt[-2].t, yypvt[-0].n); pop_cntxt();} break; +case 437: +# line 989 "rttgram.y" +{push_cntxt(1);} break; +case 438: +# line 990 "rttgram.y" +{yyval.n = node1(PrefxNd, yypvt[-2].t, yypvt[-0].n); pop_cntxt();} break; +case 439: +# line 995 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-4].t, node0(PrimryNd, yypvt[-2].t), NULL); + free_t(yypvt[-3].t); free_t(yypvt[-1].t);} break; +case 440: +# line 998 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-6].t, node0(PrimryNd, yypvt[-4].t), yypvt[-2].n); + free_t(yypvt[-5].t); free_t(yypvt[-3].t); free_t(yypvt[-1].t);} break; +case 442: +# line 1004 "rttgram.y" +{free_t(yypvt[-0].t);} break; +case 443: +# line 1008 "rttgram.y" +{yyval.n = sym_node(yypvt[-0].t);} break; +case 444: +# line 1009 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-2].t, sym_node(yypvt[-3].t), + node0(PrimryNd, yypvt[-1].t)); + free_t(yypvt[-0].t);} break; +case 445: +# line 1014 "rttgram.y" +{yyval.n = dest_node(yypvt[-0].t);} break; +case 446: +# line 1015 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 447: +# line 1016 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 448: +# line 1017 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 449: +# line 1018 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t); ++n_tmp_str;} break; +case 450: +# line 1019 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t); ++n_tmp_cset;} break; +case 451: +# line 1020 "rttgram.y" +{yyval.n = node0(ExactCnv, chk_exct(yypvt[-0].t)); free_t(yypvt[-3].t); + free_t(yypvt[-2].t); free_t(yypvt[-1].t);} break; +case 452: +# line 1022 "rttgram.y" +{yyval.n = node0(ExactCnv, yypvt[-0].t); free_t(yypvt[-3].t); free_t(yypvt[-2].t); + free_t(yypvt[-1].t);} break; +case 453: +# line 1027 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 454: +# line 1028 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 455: +# line 1029 "rttgram.y" +{yyval.n = sym_node(yypvt[-0].t);} break; +case 456: +# line 1030 "rttgram.y" +{yyval.n = node0(PrimryNd, yypvt[-0].t);} break; +case 458: +# line 1035 "rttgram.y" +{yyval.n = node1(PrefxNd, yypvt[-1].t, yypvt[-0].n);} break; +case 459: +# line 1036 "rttgram.y" +{yyval.n = node1(PrefxNd, yypvt[-1].t, yypvt[-0].n);} break; +case 460: +# line 1037 "rttgram.y" +{yyval.n = node1(PrefxNd, yypvt[-1].t, yypvt[-0].n);} break; +case 461: +# line 1041 "rttgram.y" +{yyval.n = node2(AbstrNd, yypvt[-2].t, yypvt[-3].n, yypvt[-1].n);} break; +case 462: +# line 1042 "rttgram.y" +{yyval.n = node2(AbstrNd, yypvt[-2].t, NULL, yypvt[-1].n);} break; +case 463: +# line 1043 "rttgram.y" +{yyval.n = node2(AbstrNd, NULL, yypvt[-0].n, NULL);} break; +case 465: +# line 1048 "rttgram.y" +{yyval.n = node2(ConCatNd, NULL, yypvt[-1].n, yypvt[-0].n);} break; +case 466: +# line 1052 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-2].t, yypvt[-4].n, yypvt[-1].n); + free_t(yypvt[-6].t); free_t(yypvt[-5].t); free_t(yypvt[-3].t);} break; +case 468: +# line 1058 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 469: +# line 1059 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; +case 470: +# line 1062 "rttgram.y" +{yyval.n = node1(IcnTypNd, + copy_t(yypvt[-0].n->tok), yypvt[-0].n);} break; +case 471: +# line 1064 "rttgram.y" +{yyval.n = node1(PrefxNd, yypvt[-3].t, yypvt[-1].n); + free_t(yypvt[-2].t); free_t(yypvt[-0].t);} break; +case 472: +# line 1066 "rttgram.y" +{yyval.n = node2(BinryNd, yypvt[-4].t, yypvt[-3].n, yypvt[-1].n); + free_t(yypvt[-2].t); free_t(yypvt[-0].t);} break; +case 473: +# line 1068 "rttgram.y" +{yyval.n = node1(PrefxNd, yypvt[-3].t, yypvt[-1].n); + free_t(yypvt[-2].t); free_t(yypvt[-0].t);} break; +case 474: +# line 1070 "rttgram.y" +{yyval.n = node1(PstfxNd, yypvt[-0].t, yypvt[-2].n); + free_t(yypvt[-1].t);} break; +case 475: +# line 1072 "rttgram.y" +{yyval.n = yypvt[-1].n; free_t(yypvt[-2].t); free_t(yypvt[-0].t);} break; +case 478: +# line 1081 "rttgram.y" +{yyval.n = node2(CommaNd, yypvt[-1].t, yypvt[-2].n, yypvt[-0].n);} break; + } + goto yystack; /* reset registers in driver code */ +} diff --git a/src/rtt/rttproto.h b/src/rtt/rttproto.h new file mode 100644 index 0000000..315286b --- /dev/null +++ b/src/rtt/rttproto.h @@ -0,0 +1,92 @@ +void add_dpnd (struct srcfile *sfile, char *objname); +int alloc_tnd (int typ, struct node *init, int lvl); +struct node *arith_nd (struct token *tok, struct node *p1, + struct node *p2, struct node *c_int, + struct node *ci_act, struct node *intgr, + struct node *i_act, struct node *dbl, + struct node *d_act); +struct il_c *bdy_prm (int addr_of, int just_desc, struct sym_entry *sym, int may_mod); +int c_walk (struct node *n, int indent, int brace); +int call_ret (struct node *n); +struct token *chk_exct (struct token *tok); +void chkabsret (struct token *tok, int ret_typ); +void clr_def (void); +void clr_dpnd (char *srcname); +void clr_prmloc (void); +struct token *cnv_to_id (struct token *t); +char *cnv_name (int typcd, struct node *dflt, int *dflt_to_ptr); +struct node *comp_nd (struct token *tok, struct node *dcls, + struct node *stmts); +int creat_obj (void); +void d_lst_typ (struct node *dcls); +void dclout (struct node *n); +struct node *dest_node (struct token *tok); +void dst_alloc (struct node *cnv_typ, struct node *var); +void dumpdb (char *dbname); +void fncout (struct node *head, struct node *prm_dcl, + struct node *block); +void force_nl (int indent); +void free_sym (struct sym_entry *sym); +void free_tree (struct node *n); +void free_tend (void); +void full_lst (char *fname); +void func_def (struct node *dcltor); +void id_def (struct node *dcltor, struct node *x); +void keepdir (struct token *s); +int icn_typ (struct node *n); +struct il_c *ilc_dcl (struct node *tqual, struct node *dcltor, + struct node *init); +void impl_fnc (struct token *name); +void impl_key (struct token *name); +void impl_op (struct token *op_sym, struct token *name); +void init_lex (void); +void init_sym (void); +struct il_c *inlin_c (struct node *n, int may_mod); +void in_line (struct node *n); +void just_type (struct node *typ, int indent, int ilc); +void keyconst (struct token *t); +struct node *lbl (struct token *t); +void ld_prmloc (struct parminfo *parminfo); +void loaddb (char *db); +void mrg_prmloc (struct parminfo *parminfo); +struct parminfo *new_prmloc (void); +struct node *node0 (int id, struct token *tok); +struct node *node1 (int id, struct token *tok, struct node *n1); +struct node *node2 (int id, struct token *tok, struct node *n1, + struct node *n2); +struct node *node3 (int id, struct token *tok, struct node *n1, + struct node *n2, struct node *n3); +struct node *node4 (int id, struct token *tok, struct node *n1, + struct node *n2, struct node *n3, + struct node *n4); +struct il_c *parm_dcl (int addr_of, struct sym_entry *sym); +void pop_cntxt (void); +void pop_lvl (void); +void prologue (void); +void prt_str (char *s, int indent); +void ptout (struct token * x); +void push_cntxt (int lvl_incr); +void push_lvl (void); +void put_c_fl (char *fname, int keep); +void defout (struct node *n); +void set_r_seq (long min, long max, int resume); +struct il_c *simpl_dcl (char *tqual, int addr_of, struct sym_entry *sym); +void spcl_dcls (struct sym_entry *op_params); +struct srcfile *src_lkup (char *srcname); +void strt_def (void); +void sv_prmloc (struct parminfo *parminfo); +struct sym_entry *sym_add (int tok_id, char *image, int id_type, int nest_lvl); +struct sym_entry *sym_lkup (char *image); +struct node *sym_node (struct token *tok); +void s_prm_def (struct token *u_ident, struct token *d_ident); +void tnd_char (void); +void tnd_strct (struct token *t); +void tnd_union (struct token *t); +void trans (char *src_file); +long ttol (struct token *t); +char *typ_name (int typ, struct token *tok); +void unuse (struct init_tend *t_lst, int lvl); +void var_args (struct token *ident); +void yyerror (char *s); +int yylex (void); +int yyparse (void); diff --git a/src/rtt/rttsym.c b/src/rtt/rttsym.c new file mode 100644 index 0000000..9e1901b --- /dev/null +++ b/src/rtt/rttsym.c @@ -0,0 +1,722 @@ +/* + * rttsym.c contains symbol table routines. + */ +#include "rtt.h" + +#define HashSize 149 + +/* + * Prototype for static function. + */ +static void add_def (struct node *dcltor); +static void add_s_prm (struct token *ident, int param_num, int flags); +static void dcl_typ (struct node *dcl); +static void dcltor_typ (struct node *dcltor, struct node *tqual); + +word lbl_num = 0; /* next unused label number */ +struct lvl_entry *dcl_stk; /* stack of declaration contexts */ + +char *str_rslt; /* string "result" in string table */ +struct init_tend *tend_lst = NULL; /* list of tended descriptors */ +struct sym_entry *decl_lst = NULL; /* declarations from "declare {...}" */ +struct sym_entry *v_len = NULL; /* entry for length of varargs */ +int il_indx = 0; /* data base symbol table index */ + +static struct sym_entry *sym_tbl[HashSize]; /* symbol table */ + +/* + * The following strings are put in the string table and used for + * recognizing valid tended declarations. + */ +static char *block = "block"; +static char *descrip = "descrip"; + +/* + * init_sym - initialize symbol table. + */ +void init_sym() + { + static int first_time = 1; + int hash_val; + register struct sym_entry *sym; + int i; + + /* + * Initialize the symbol table and declaration stack. When called for + * the first time, put strings in string table. + */ + if (first_time) { + first_time = 0; + for (i = 0; i < HashSize; ++i) + sym_tbl[i] = NULL; + dcl_stk = NewStruct(lvl_entry); + dcl_stk->nest_lvl = 1; + dcl_stk->next = NULL; + block = spec_str(block); + descrip = spec_str(descrip); + } + else { + for (hash_val = 0; hash_val < HashSize; ++ hash_val) { + for (sym = sym_tbl[hash_val]; sym != NULL && + sym->nest_lvl > 0; sym = sym_tbl[hash_val]) { + sym_tbl[hash_val] = sym->next; + free((char *)sym); + } + } + } + dcl_stk->kind_dcl = OtherDcl; + dcl_stk->parms_done = 0; + } + +/* + * sym_lkup - look up a string in the symbol table. Return NULL If it is not + * there. + */ +struct sym_entry *sym_lkup(image) +char *image; + { + register struct sym_entry *sym; + + for (sym = sym_tbl[(unsigned int)(unsigned long)image % HashSize]; + sym != NULL; + sym = sym->next) + if (sym->image == image) + return sym; + return NULL; + } + +/* + * sym_add - add a symbol to the symbol table. For some types of entries + * it is illegal to redefine them. In that case, NULL is returned otherwise + * the entry is returned. + */ +struct sym_entry *sym_add(tok_id, image, id_type, nest_lvl) +int tok_id; +char *image; +int id_type; +int nest_lvl; + { + register struct sym_entry **symp; + register struct sym_entry *sym; + + symp = &sym_tbl[(unsigned int)(unsigned long)image % HashSize]; + while (*symp != NULL && (*symp)->nest_lvl > nest_lvl) + symp = &((*symp)->next); + while (*symp != NULL && (*symp)->nest_lvl == nest_lvl) { + if ((*symp)->image == image) { + /* + * Redeclaration: + * + * An explicit typedef may be given for a built-in typedef + * name. A label appears in multiply gotos and as a label + * on a statement. Assume a global redeclaration is for an + * extern. Return the entry for these situations but don't + * try too hard to detect errors. If actual errors are not + * caught here, the C compiler will find them. + */ + if (tok_id == TypeDefName && ((*symp)->tok_id == C_Integer || + (*symp)->tok_id == TypeDefName)) + return *symp; + if (id_type == Label && (*symp)->id_type == Label) + return *symp; + if ((*symp)->nest_lvl == 1) + return *symp; + return NULL; /* illegal redeclarations */ + } + symp = &((*symp)->next); + } + + /* + * No entry exists for the symbol, create one, fill in its fields, and add + * it to the table. + */ + sym = NewStruct(sym_entry); + sym->tok_id = tok_id; + sym->image = image; + sym->id_type = id_type; + sym->nest_lvl = nest_lvl; + sym->ref_cnt = 1; + sym->il_indx = -1; + sym->may_mod = 0; + if (id_type == Label) + sym->u.lbl_num = lbl_num++; + sym->next = *symp; + *symp = sym; + + return sym; /* success */ + } + +/* + * lbl - make sure the label is in the symbol table and return a node + * referencing the symbol table entry. + */ +struct node *lbl(t) +struct token *t; + { + struct sym_entry *sym; + struct node *n; + + sym = sym_add(Identifier, t->image, Label, 2); + if (sym == NULL) + errt2(t, "conflicting definitions for ", t->image); + n = sym_node(t); + if (n->u[0].sym != sym) + errt2(t, "conflicting definitions for ", t->image); + return n; + } + +/* + * push_cntxt - push a level of declaration context (this may or may not + * be level of declaration nesting). + */ +void push_cntxt(lvl_incr) +int lvl_incr; + { + struct lvl_entry *entry; + + entry = NewStruct(lvl_entry); + entry->nest_lvl = dcl_stk->nest_lvl + lvl_incr; + entry->kind_dcl = OtherDcl; + entry->parms_done = 0; + entry->tended = NULL; + entry->next = dcl_stk; + dcl_stk = entry; + } + +/* + * pop_cntxt - end a level of declaration context + */ +void pop_cntxt() + { + int hash_val; + int old_lvl; + int new_lvl; + register struct sym_entry *sym; + struct lvl_entry *entry; + + /* + * Move the top entry of the stack to the free list. + */ + old_lvl = dcl_stk->nest_lvl; + entry = dcl_stk; + dcl_stk = dcl_stk->next; + free((char *)entry); + + /* + * If this pop reduced the declaration nesting level, remove obsolete + * entries from the symbol table. + */ + new_lvl = dcl_stk->nest_lvl; + if (old_lvl > new_lvl) { + for (hash_val = 0; hash_val < HashSize; ++ hash_val) { + for (sym = sym_tbl[hash_val]; sym != NULL && + sym->nest_lvl > new_lvl; sym = sym_tbl[hash_val]) { + sym_tbl[hash_val] = sym->next; + free_sym(sym); + } + } + unuse(tend_lst, old_lvl); + } + } + +/* + * unuse - mark tended slots in at the given level of declarations nesting + * as being no longer in use, and leave the slots available for reuse + * for declarations that occur in pararallel compound statements. + */ +void unuse(t_lst, lvl) +struct init_tend *t_lst; +int lvl; + { + while (t_lst != NULL) { + if (t_lst->nest_lvl >= lvl) + t_lst->in_use = 0; + t_lst = t_lst->next; + } + } + +/* + * free_sym - remove a reference to a symbol table entry and free storage + * related to it if no references remain. + */ +void free_sym(sym) +struct sym_entry *sym; + { + if (--sym->ref_cnt <= 0) { + switch (sym->id_type) { + case TndDesc: + case TndStr: + case TndBlk: + free_tree(sym->u.tnd_var.init); /* initializer expression */ + } + free((char *)sym); + } + } + +/* + * alloc_tnd - allocated a slot in a tended array for a variable and return + * its index. + */ +int alloc_tnd(typ, init, lvl) +int typ; +struct node *init; +int lvl; + { + register struct init_tend *tnd; + + if (lvl > 2) { + /* + * This declaration occurs in an inner compound statement. There + * may be slots created for parallel compound statement, but were + * freed and can be reused here. + */ + tnd = tend_lst; + while (tnd != NULL && (tnd->in_use || tnd->init_typ != typ)) + tnd = tnd->next; + if (tnd != NULL) { + tnd->in_use = 1; + tnd->nest_lvl = lvl; + return tnd->t_indx; + } + } + + /* + * Allocate a new tended slot, compute its index in the array, and + * set initialization and other information. + */ + tnd = NewStruct(init_tend); + + if (tend_lst == NULL) + tnd->t_indx = 0; + else + tnd->t_indx = tend_lst->t_indx + 1; + tnd->init_typ = typ; + /* + * The initialization from the declaration will only be used to + * set up the tended location if the declaration is in the outermost + * "block". Otherwise a generic initialization will be done during + * the set up and the one from the declaration will be put off until + * the block is entered. + */ + if (lvl == 2) + tnd->init = init; + else + tnd->init = NULL; + tnd->in_use = 1; + tnd->nest_lvl = lvl; + tnd->next = tend_lst; + tend_lst = tnd; + return tnd->t_indx; + } + +/* + * free_tend - put the list of tended descriptors on the free list. + */ +void free_tend() + { + register struct init_tend *tnd, *tnd1; + + for (tnd = tend_lst; tnd != NULL; tnd = tnd1) { + tnd1 = tnd->next; + free((char *)tnd); + } + tend_lst = NULL; + } + +/* + * dst_alloc - the conversion of a parameter is encountered during + * parsing; make sure a place is allocated to act as the destination. + */ +void dst_alloc(cnv_typ, var) +struct node *cnv_typ; +struct node *var; + { + struct sym_entry *sym; + + if (var->nd_id == SymNd) { + sym = var->u[0].sym; + if (sym->id_type & DrfPrm) { + switch (cnv_typ->tok->tok_id) { + case C_Integer: + sym->u.param_info.non_tend |= PrmInt; + break; + case C_Double: + sym->u.param_info.non_tend |= PrmDbl; + break; + } + } + } + } + +/* + * strt_def - the start of an operation definition is encountered during + * parsing; establish an new declaration context and make "result" + * a special identifier. + */ +void strt_def() + { + struct sym_entry *sym; + + push_cntxt(1); + sym = sym_add(Identifier, str_rslt, RsltLoc, dcl_stk->nest_lvl); + sym->u.referenced = 0; + } + +/* + * add_def - update the symbol table for the given declarator. + */ +static void add_def(dcltor) +struct node *dcltor; + { + struct sym_entry *sym; + struct token *t; + int tok_id; + + /* + * find the identifier within the declarator. + */ + for (;;) { + switch (dcltor->nd_id) { + case BinryNd: + /* ')' or '[' */ + dcltor = dcltor->u[0].child; + break; + case ConCatNd: + /* pointer direct-declarator */ + dcltor = dcltor->u[1].child; + break; + case PrefxNd: + /* ( ... ) */ + dcltor = dcltor->u[0].child; + break; + case PrimryNd: + t = dcltor->tok; + if (t->tok_id == Identifier || t->tok_id == TypeDefName) { + /* + * We have found the identifier, add an entry to the + * symbol table based on information in the declaration + * context. + */ + if (dcl_stk->kind_dcl == IsTypedef) + tok_id = TypeDefName; + else + tok_id = Identifier; + sym = sym_add(tok_id, t->image, OtherDcl, dcl_stk->nest_lvl); + if (sym == NULL) + errt2(t, "redefinition of ", t->image); + } + return; + default: + return; + } + } + } + +/* + * id_def - a declarator has been parsed. Determine what to do with it + * based on information put in the declaration context while parsing + * the "storage class type qualifier list". + */ +void id_def(dcltor, init) +struct node *dcltor; +struct node *init; + { + struct node *chld0, *chld1; + struct sym_entry *sym; + + if (dcl_stk->parms_done) + pop_cntxt(); + + /* + * Look in the declaration context (the top of the declaration stack) + * to see if this is a tended declaration. + */ + switch (dcl_stk->kind_dcl) { + case TndDesc: + case TndStr: + case TndBlk: + /* + * Tended variables are either simple identifiers or pointers to + * simple identifiers. + */ + chld0 = dcltor->u[0].child; + chld1 = dcltor->u[1].child; + if (chld1->nd_id != PrimryNd || (chld1->tok->tok_id != Identifier && + chld1->tok->tok_id != TypeDefName)) + errt1(chld1->tok, "unsupported tended declaration"); + if (dcl_stk->kind_dcl == TndDesc) { + /* + * Declared as full tended descriptor - must not be a pointer. + */ + if (chld0 != NULL) + errt1(chld1->tok, "unsupported tended declaration"); + } + else { + /* + * Must be a tended pointer. + */ + if (chld0 == NULL || chld0->nd_id != PrimryNd) + errt1(chld1->tok, "unsupported tended declaration"); + } + + /* + * This is a legal tended declaration, make a symbol table entry + * for it and allocated a tended slot. Add the symbol table + * entry to the list of tended variables in this context. + */ + sym = sym_add(Identifier, chld1->tok->image, dcl_stk->kind_dcl, + dcl_stk->nest_lvl); + if (sym == NULL) + errt2(chld1->tok, "redefinition of ", chld1->tok->image); + sym->u.tnd_var.blk_name = dcl_stk->blk_name; + sym->u.tnd_var.init = init; + sym->t_indx = alloc_tnd(dcl_stk->kind_dcl, init, dcl_stk->nest_lvl); + sym->u.tnd_var.next = dcl_stk->tended; + dcl_stk->tended = sym; + ++sym->ref_cnt; + return; + default: + add_def(dcltor); /* ordinary declaration */ + } + } + +/* + * func_def - a function header has been parsed. Add the identifier for + * the function to the symbol table. + */ +void func_def(head) +struct node *head; + { + /* + * If this is really a function header, the current declaration + * context indicates that a parameter list has been completed. + * Parameter lists at other than at nesting level 2 are part of + * nested declaration information and do not show up here. The + * function parameters must remain in the symbol table, so the + * context is just updated, not popped. + */ + if (!dcl_stk->parms_done) + yyerror("invalid declaration"); + dcl_stk->parms_done = 0; + if (dcl_stk->next->kind_dcl == IsTypedef) + yyerror("a typedef may not be a function definition"); + add_def(head->u[1].child); + } + +/* + * s_prm_def - add symbol table entries for a parameter to an operation. + * Undereferenced and/or dereferenced versions of the parameter may be + * specified. + */ +void s_prm_def(u_ident, d_ident) +struct token *u_ident; +struct token *d_ident; + { + int param_num; + + if (params == NULL) + param_num = 0; + else + param_num = params->u.param_info.param_num + 1; + if (u_ident != NULL) + add_s_prm(u_ident, param_num, RtParm); + if (d_ident != NULL) + add_s_prm(d_ident, param_num, DrfPrm); + } + +/* + * add_s_prm - add a symbol table entry for either a dereferenced or + * undereferenced version of a parameter. Put it on the current + * list of parameters. + */ +static void add_s_prm(ident, param_num, flags) +struct token *ident; +int param_num; +int flags; + { + struct sym_entry *sym; + + sym = sym_add(Identifier, ident->image, flags, dcl_stk->nest_lvl); + if (sym == NULL) + errt2(ident, "redefinition of ", ident->image); + sym->u.param_info.param_num = param_num; + sym->u.param_info.non_tend = 0; + sym->u.param_info.cur_loc = PrmTend; + sym->u.param_info.parm_mod = 0; + sym->u.param_info.next = params; + sym->il_indx = il_indx++; + params = sym; + ++sym->ref_cnt; + } + +/* + * var_args - a variable length parameter list for an operation is parsed. + */ +void var_args(ident) +struct token *ident; + { + struct sym_entry *sym; + + /* + * The last parameter processed represents the variable part of the list; + * update the symbol table entry. It may be dereferenced or undereferenced + * but not both. + */ + sym = params->u.param_info.next; + if (sym != NULL && sym->u.param_info.param_num == + params->u.param_info.param_num) + errt1(ident, "only one version of variable parameter list allowed"); + params->id_type |= VarPrm; + + /* + * Add the identifier for the length of the variable part of the list + * to the symbol table. + */ + sym = sym_add(Identifier, ident->image, VArgLen, dcl_stk->nest_lvl); + if (sym == NULL) + errt2(ident, "redefinition of ", ident->image); + sym->il_indx = il_indx++; + v_len = sym; + ++v_len->ref_cnt; + } + +/* + * d_lst_typ - the end of a "declare {...}" is encountered. Go through a + * declaration list adding storage class, type qualifier, declarator + * and initializer information to the symbol table entry for each + * identifier. Add the entry onto the list associated with the "declare" + */ +void d_lst_typ(dcls) +struct node *dcls; + { + if (dcls == NULL) + return; + for ( ; dcls != NULL && dcls->nd_id == LstNd; dcls = dcls->u[0].child) + dcl_typ(dcls->u[1].child); + dcl_typ(dcls); + } + +/* + * dcl_typ - go through the declarators of a declaration adding the storage + * class, type qualifier, declarator, and initializer information to the + * symbol table entry of each identifier. Add the entry onto the list + * associated with the current "declare {...}". + */ +static void dcl_typ(dcl) +struct node *dcl; + { + struct node *tqual; + struct node *dcltors; + + if (dcl == NULL) + return; + tqual = dcl->u[0].child; + for (dcltors = dcl->u[1].child; dcltors->nd_id == CommaNd; + dcltors = dcltors->u[0].child) + dcltor_typ(dcltors->u[1].child, tqual); + dcltor_typ(dcltors, tqual); + } + +/* + * dcltor_typ- find the identifier in the [initialized] declarator and add + * the storage class, type qualifer, declarator, and initialization + * information to its symbol table entry. Add the entry onto the list + * associated with the current "declare {...}". + */ +static void dcltor_typ(dcltor, tqual) +struct node *dcltor; +struct node *tqual; + { + struct sym_entry *sym; + struct node *part_dcltor; + struct node *init = NULL; + struct token *t; + + if (dcltor->nd_id == BinryNd && dcltor->tok->tok_id == '=') { + init = dcltor->u[1].child; + dcltor = dcltor->u[0].child; + } + part_dcltor = dcltor; + for (;;) { + switch (part_dcltor->nd_id) { + case BinryNd: + /* ')' or '[' */ + part_dcltor = part_dcltor->u[0].child; + break; + case ConCatNd: + /* pointer direct-declarator */ + part_dcltor = part_dcltor->u[1].child; + break; + case PrefxNd: + /* ( ... ) */ + part_dcltor = part_dcltor->u[0].child; + break; + case PrimryNd: + t = part_dcltor->tok; + if (t->tok_id == Identifier || t->tok_id == TypeDefName) { + /* + * The identifier has been found, update its symbol table + * entry. + */ + sym = sym_lkup(t->image); + sym->u.declare_var.tqual = tqual; + sym->u.declare_var.dcltor = dcltor; + sym->u.declare_var.init = init; + ++sym->ref_cnt; + sym->u.declare_var.next = decl_lst; + decl_lst = sym; + } + return; + default: + return; + } + } + } + +/* + * tnd_char - indicate in the current declaration context that a tended + * character (pointer?) declaration has been found. + */ +void tnd_char() + { + dcl_stk->kind_dcl = TndStr; + dcl_stk->blk_name = NULL; + } + +/* + * tnd_strct - indicate in the current declaration context that a tended + * struct declaration has been found and indicate the struct type. + */ +void tnd_strct(t) +struct token *t; + { + char *strct_nm; + + strct_nm = t->image; + free_t(t); + + if (strct_nm == descrip) { + dcl_stk->kind_dcl = TndDesc; + dcl_stk->blk_name = NULL; + return; + } + dcl_stk->kind_dcl = TndBlk; + dcl_stk->blk_name = strct_nm; + } + +/* + * tnd_strct - indicate in the current declaration context that a tended + * union (pointer?) declaration has been found. + */ +void tnd_union(t) +struct token *t; + { + /* + * Only union block pointers may be tended. + */ + if (t->image != block) + yyerror("unsupported tended type"); + free_t(t); + dcl_stk->kind_dcl = TndBlk; + dcl_stk->blk_name = NULL; + } |