home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-09-23 | 44.4 KB | 1,134 lines |
- /* ------------------------------------------------------------------------- */
- /* "express" : The expression evaluator */
- /* */
- /* Part of Inform release 5 */
- /* */
- /* ------------------------------------------------------------------------- */
-
- #include "header.h"
-
- /* ------------------------------------------------------------------------- */
- /* Definition of expression tree branch */
- /* ------------------------------------------------------------------------- */
-
- typedef struct treenode {
- int up; /* Node above */
- int word; /* Token number in source line */
- int type; /* Type of node (there are eight: see above) */
- int priority; /* Eg, + has a low priority, * a higher one */
- int label_number; /* For code blocks in && and || expressions */
- int yes_label; /* Condition true */
- int no_label; /* Condition false */
- int arity; /* Number of branches expected */
- int b[MAX_ARITY]; /* Nodes below (the branches)... */
- int branches_made; /* ...from 0 up to this-1 */
- char *op; /* Name of opcode to achieve this operation */
- } treenode;
-
- #ifndef ALLOCATE_BIG_ARRAYS
- static treenode tree[MAX_EXPRESSION_NODES];
- #else
- static treenode *tree;
- #endif
-
- extern void express_allocate_arrays(void)
- {
- #ifdef ALLOCATE_BIG_ARRAYS
- tree = my_calloc(sizeof(treenode), MAX_EXPRESSION_NODES,
- "expression tree");
- #endif
- }
-
- extern void express_free_arrays(void)
- {
- #ifdef ALLOCATE_BIG_ARRAYS
- my_free(tree, "expression tree");
- #endif
- }
-
- /* ------------------------------------------------------------------------- */
- /* Compiler expression and assignment evaluator */
- /* ------------------------------------------------------------------------- */
- /* */
- /* This is easily the most complicated algorithm in Inform, for two */
- /* reasons - firstly, because I invented it in a hurry and know absolutely */
- /* nothing about compiler theory, and second, because it tries to avoid */
- /* recursion which uses the C stack. (Some machines to which Inform has */
- /* been ported have had problems with the size of the C stack.) */
- /* */
- /* The code generator is also complicated by some awkward features of the */
- /* Z-machine: for instance, the safe way to extract property lengths is */
- /* tricky to get right. Anyway, enough excuses: */
- /* */
- /* The algorithm first makes a tree out of the expression and then */
- /* clears it off again by clipping off nodes and stacking up corresponding */
- /* assembly lines. This needs to be in the right order, since the stack */
- /* can't very conveniently be re-ordered. */
- /* */
- /* The algorithm is iterative rather than recursive. In the first phase, */
- /* we imagine a tree gradually growing as a dryad scampers over it. She */
- /* is either resting on a leaf already grown, or else hovering in midair */
- /* over the space where one will grow. Every so often she casts an easy */
- /* spell to grow a leaf where she is, or a more powerful one to grow her */
- /* leaf into a branch, and she then clambers along or down. */
- /* */
- /* The dryad is also sometimes awaiting a comma, since she knows that the */
- /* line 45+1, ... ends with the comma, whereas i=fn(j,k) does not. Sadly */
- /* she can get distracted while waiting, for instance in the expression */
- /* (after reading j) i=fn(j+5*(l+1),2), but being conscientious she ties */
- /* her veil where she was so as to be able to find the place again later. */
- /* */
- /* To follow her movements, try Informing with full expression tracing on */
- /* (using "etrace full"): to look simply at the tree she grows, and the */
- /* code it results in, try just "etrace". */
- /* */
- /* The main data structure (treenode) is commented at the top of the file. */
- /* (Most of the variables have been more sensibly named since early */
- /* releases: in particular now you can't see the woods[] for the tree[].) */
- /* ------------------------------------------------------------------------- */
-
- #define ROOT_NODE -4
- #define BLANK_NODE -3
- #define CDONE_NODE -2
- #define SP_NODE -1
- #define LEAF_NODE 0
- #define STORE_NODE 1
- #define ARITH_NODE 2
- #define FCALL_NODE 3
- #define COND_NODE 4
- #define NCOND_NODE 5
- #define LOGICAND_NODE 6
- #define LOGICOR_NODE 7
- #define OR_NODE 8
- #define ALTERA_NODE 9
- #define ALTERB_NODE 10
-
- static int tree_size, dryad, resting, comma_mode, dryad_veil=-1,
- sofar_empty;
-
- /* ------------------------------------------------------------------------- */
- /* Pretty printing (for diagnostics) */
- /* ------------------------------------------------------------------------- */
-
- static void show_leaf(int ln, int depth)
- { char sl_buffer[100];
- int j;
- for (j=0; j<2*depth+2; j++) printf(" ");
- if (ln==-1) { printf("..\n"); return; }
- else if (etrace_mode==1) printf("%02d ",ln);
- switch(tree[ln].type)
- { case ROOT_NODE: printf("<root>"); break;
- case BLANK_NODE: printf("<blank>"); break;
- case CDONE_NODE: printf("<condition done>"); break;
- case SP_NODE: printf("<sp>"); break;
- case LEAF_NODE: word(sl_buffer,tree[ln].word);
- printf("%s",sl_buffer); break;
- default: printf("%s",tree[ln].op); break;
- }
- if (etrace_mode==1)
- { if (tree[ln].priority!=0)
- { printf(" (%d)",tree[ln].priority); }
- if (tree[ln].type>=STORE_NODE)
- { switch(tree[ln].type)
- { case STORE_NODE: printf(" [assignment] "); break;
- case ARITH_NODE: printf(" [arithmetic] "); break;
- case FCALL_NODE: printf(" [function call] "); break;
- case COND_NODE: printf(" [condition] "); break;
- case NCOND_NODE: printf(" [negated condition] "); break;
- case LOGICAND_NODE: printf(" [conjunction] "); break;
- case LOGICOR_NODE: printf(" [disjunction] "); break;
- case OR_NODE: printf(" [or] "); break;
- case ALTERA_NODE: printf(" [read then alter] "); break;
- case ALTERB_NODE: printf(" [alter then read] "); break;
- }
- }
- printf(" ^%d ",tree[ln].up);
- if (ln==dryad) printf("(dryad here) ");
- }
- if ((tree[ln].type==LOGICAND_NODE)
- ||(tree[ln].type==LOGICOR_NODE))
- printf(" {%d/%d/%d} ",tree[ln].label_number,
- tree[ln].yes_label, tree[ln].no_label);
- printf("\n");
- for (j=0; j<tree[ln].arity; j++)
- { if (j<tree[ln].branches_made) show_leaf(tree[ln].b[j],depth+1);
- else show_leaf(-1,depth+1);
- }
- }
-
- static void show_tree(char *c)
- { printf("%s\n",c); show_leaf(tree[0].b[0],0);
- if (etrace_mode==1)
- { printf("The dryad is at %d and is %s%s\n",
- dryad,(resting==1)?"resting":"hovering in midair",
- (comma_mode==0)?"":"\nwhile waiting for a comma");
- if (dryad_veil!=-1)
- printf("with her veil tied to %d\n",dryad_veil);
- }
- }
-
- /* ------------------------------------------------------------------------- */
- /* Growing the tree */
- /* ------------------------------------------------------------------------- */
-
- static void grow_branch(int a, int wn, int type, char *opcde, int prio)
- { int i, above_dryad, rflag, prefix=0, postfix=0;
-
- if (a>=MAX_ARITY)
- { error("A function may be called with at most 3 arguments");
- return;
- }
-
- above_dryad=tree[dryad].up;
-
- if ((a==1)&&(type!=FCALL_NODE)&&(sofar_empty==1))
- { prefix=1;
- if (type==ALTERA_NODE) type=ALTERB_NODE;
- }
- if (type==ALTERA_NODE) postfix=1;
- if ((a==1)&&(type==FCALL_NODE)) postfix=1;
-
- if (etrace_mode==1) printf("%s%s%s operator '%s'\n",
- (prefix==1)?"prefix":"",(postfix==1)?"postfix":"",
- ((prefix==0)&&(postfix==0))?"infix":"",opcde);
- sofar_empty=1;
-
- if ((resting==0)&&(comma_mode==0)&&(prefix==0))
- { error("Operator has too few arguments"); return;
- }
-
- if ( ((type==LOGICAND_NODE)
- && (tree[tree[above_dryad].up].type==LOGICAND_NODE))
- || ((type==LOGICOR_NODE)
- && (tree[tree[above_dryad].up].type==LOGICOR_NODE))
- || ((type==OR_NODE) && (strcmp(tree[above_dryad].op,"je")==0))
- || ((type==OR_NODE) && (strcmp(tree[above_dryad].op,"vje")==0)) )
- { if ((type==LOGICAND_NODE) || (type==LOGICOR_NODE))
- above_dryad=tree[above_dryad].up;
- if (tree[above_dryad].arity < MAX_ARITY)
- { tree[above_dryad].arity++; rflag=1; }
- if (type==OR_NODE)
- { tree[above_dryad].op="vje";
- if (tree[above_dryad].arity==5)
- { error("At most three values can be separated by 'or'");
- rflag=0;
- }
- }
- if (rflag==1)
- { dryad=tree_size++;
- tree[dryad].up=above_dryad;
- tree[dryad].type=BLANK_NODE;
- tree[above_dryad].b[tree[above_dryad].arity-1]=dryad;
- resting=0;
- return;
- }
- }
-
- if (type==OR_NODE)
- error("'or' can only be used with the conditions '==' and '~='");
-
- if (comma_mode==1)
- { comma_mode=0;
- if (prefix==0) dryad_veil=dryad;
- }
-
- while (tree[above_dryad].priority>prio)
- { dryad=above_dryad; above_dryad=tree[dryad].up;
- }
-
- if (prefix==0)
- { while (tree[dryad].type== BLANK_NODE)
- { for (i=1; i<tree[above_dryad].arity; i++)
- if (tree[above_dryad].b[i]==dryad)
- { dryad=tree[above_dryad].b[i-1]; break; }
- }
- }
-
- if (prefix==1) tree[above_dryad].branches_made++;
-
- for (i=0; i<tree[above_dryad].arity; i++)
- if (tree[above_dryad].b[i]==dryad)
- tree[above_dryad].b[i]=tree_size;
-
- tree[dryad].up=tree_size;
- tree[tree_size].b[0]=dryad;
- tree[tree_size].up=above_dryad;
-
- dryad=tree_size++;
-
- tree[dryad].arity=a;
- tree[dryad].word=wn;
- tree[dryad].branches_made=1;
- if (prefix==1) tree[dryad].branches_made=0;
- tree[dryad].type=type;
- tree[dryad].op=opcde;
- tree[dryad].priority=prio;
- tree[dryad].no_label=-2;
- tree[dryad].yes_label=-2;
- if ((type==LOGICAND_NODE) || (type==LOGICOR_NODE))
- tree[dryad].label_number=no_dummy_labels++;
-
- for (i=1; i<a; i++)
- { tree[dryad].b[i]=tree_size;
- tree[tree_size].type= BLANK_NODE;
- tree[tree_size].arity=0;
- tree[tree_size].branches_made=0;
- tree[tree_size].priority=0;
- tree[tree_size++].up=dryad;
- }
- if ((prefix==0)&&(postfix==0))
- { if (etrace_mode==1) printf("Magic = %d\n",dryad);
- dryad=tree[dryad].b[1]; resting=0; }
- if (prefix==1)
- { dryad=tree[dryad].b[0]; resting=0; }
- if (postfix==1)
- { dryad=tree[dryad].b[0]; resting=1; }
-
- if (etrace_mode==1) show_tree("grow_branch to");
- }
-
- static void grow_leaf(int wn)
- { int above_dryad;
-
- above_dryad=tree[dryad].up;
-
- tree[dryad].arity=0;
- tree[dryad].word=wn;
- tree[dryad].branches_made=0;
- tree[dryad].type=LEAF_NODE;
- tree[dryad].priority=0;
-
- tree[above_dryad].branches_made++;
- if (tree[above_dryad].branches_made<tree[above_dryad].arity)
- { dryad=tree[above_dryad].b[tree[above_dryad].branches_made];
- resting=0;
- }
- else resting=1;
-
- if (etrace_mode==1) show_tree("grow_leaf to");
- return;
- }
-
- static void fix_yesno_labels(int n, int flag)
- { int i;
- if ((tree[n].type!=LOGICOR_NODE)&&(tree[n].type!=LOGICAND_NODE))
- return;
- if (flag==1)
- {
- tree[n].yes_label = tree[tree[n].up].yes_label;
- tree[n].no_label = tree[tree[n].up].no_label;
- }
- else
- switch(tree[tree[n].up].type)
- { case ROOT_NODE:
- tree[n].yes_label = no_dummy_labels-1;
- tree[n].no_label = -1;
- break;
- case LOGICAND_NODE:
- tree[n].yes_label = tree[n].label_number;
- tree[n].no_label = tree[tree[n].up].no_label;
- break;
- case LOGICOR_NODE:
- tree[n].yes_label = tree[tree[n].up].yes_label;
- tree[n].no_label = tree[n].label_number;
- break;
- }
- for (i=0; i<tree[n].branches_made; i++)
- fix_yesno_labels(tree[n].b[i], (i==tree[n].branches_made-1)?1:0);
- }
-
- /* ------------------------------------------------------------------------- */
- /* Main expression (and assignment) evaluator routine: */
- /* */
- /* expression(from) compiles code to evaluate the expression starting at */
- /* token from, leaves next_token at the first not part of the expression */
- /* (or -1 if the line was all used up); and returns */
- /* */
- /* -3 if the result was thrown away (eg. a void context function call) */
- /* -2 if there is no result (eg, from "i=4" there is none) */
- /* -1 if the result is on the stack */
- /* n if the result is the constant term in token n */
- /* ------------------------------------------------------------------------- */
-
- static void eword(char *b, int bn)
- { if (tree[bn].type==SP_NODE) strcpy(b,"sp");
- else word(b,tree[bn].word);
- /* printf("Eword %d -> %d <%s>\n",bn,tree[bn].word,b); */
- }
-
- #define Op_(type,name,priority) grow_branch(2,token-1,type,name,\
- priority+current_priority)
- #define Op1_(type,name,priority) grow_branch(1,token-1,type,name,\
- priority+current_priority)
- #define OnCS_(x) if ((condition_context==1)&&(strcmp(sub_buffer,x)==0))
- #define OnBS_(x) if ((bracket_level>0)&&(strcmp(sub_buffer,x)==0))
-
- int next_token, void_context, condition_context=0,
- assign_context=0, lines_compiled;
- char condition_label[64];
- static int brackets[MAX_EXPRESSION_BRACKETS], bracket_level;
-
- static void estack_line(char *rewrite)
- { if (etrace_mode>=1) printf("%2d %s\n",++lines_compiled,rewrite+1);
- stack_line(rewrite);
- }
-
- extern int expression(int fromword)
- { int c, i, j, k, t, token, current_priority=0, wd_tk,
- sysfun_arity, dummy_branch_flag,
- call_level, call_flag, call_args, call_i, tosp_flag,
- revise_flag, last_was_leaf,
- its_void=0, thrown_away_flag=0, indirect_flag=0,
- last_was_comma=0, last_was_openb=0;
-
- /* --------------------------------------------------------------------- */
- /* 1. A little optimisation: can we tell at once this will not be a */
- /* full-blown expression, but just a single constant term? */
- /* --------------------------------------------------------------------- */
-
- t=word_token(fromword);
- if ((t!=OPENB_SEP) && (t!=MINUS_SEP) && (condition_context==0)
- && (t!=DEC_SEP) && (t!=INC_SEP))
- { word(sub_buffer,fromword+1); c=sub_buffer[0];
- if ((c==0) || (isalpha(c)) || (isdigit(c)) || (c=='#') || (c==','))
- { next_token=fromword+1; if (c==0) next_token=-1;
- return(fromword);
- }
- }
-
- /* --------------------------------------------------------------------- */
- /* 2. Initially the tree is just a root node plus one blank branch */
- /* --------------------------------------------------------------------- */
-
- tree[0].up= -1; tree[0].type= ROOT_NODE; tree[0].b[0]=1;
- tree[0].arity=1; tree[0].branches_made=0; tree[0].priority=0;
-
- tree[1].up=0; tree[1].type= BLANK_NODE; tree[1].priority=0;
-
- tree_size=2; comma_mode=0;
- dryad=1; resting=0; sofar_empty=1; last_was_leaf=0;
-
- bracket_level=0;
- token=fromword;
- revise_flag=0;
-
- if (etrace_mode==1) printf("\n++++++++++++++++++++++++++++++\n");
- if (etrace_mode>=1)
- { printf("\nEvaluating expression %s%s%sat:\n ",
- (void_context==1)?"(in void context) ":"",
- (condition_context==1)?"(in condition context) ":"",
- (assign_context==1)?"(in assignment context) ":"");
- for (i=0; (i==0)||(sub_buffer[0]!=0); i++)
- { word(sub_buffer,fromword+i); printf("%s ",sub_buffer);
- }
- printf("\n");
- }
-
- lines_compiled=0;
-
- /* --------------------------------------------------------------------- */
- /* 3. Grow the tree */
- /* --------------------------------------------------------------------- */
-
- do
- { token++;
- wd_tk = word_token(token-1); sub_buffer[0]=0;
- if (wd_tk==-1) { word(sub_buffer,token-1);
- if (sub_buffer[0]==0) break;
- }
-
- if (last_was_comma>0) last_was_comma--;
- if (last_was_openb>0) last_was_openb--;
-
- if (etrace_mode==1)
- printf("Dryad reads '%s'\nSofar_empty=%d\n",sub_buffer,sofar_empty);
-
- switch(wd_tk)
- {
- case SETEQUALS_SEP:
- Op_(STORE_NODE, "store", 3);
- revise_flag=1; its_void=1; last_was_openb=2; break;
-
- case PLUS_SEP: Op_(ARITH_NODE, "add", 4); break;
-
- case MINUS_SEP:
- if (sofar_empty==0)
- Op_(ARITH_NODE, "sub", 4);
- else
- Op1_(ARITH_NODE, "sub 0", 8);
- break;
-
- case TIMES_SEP: Op_(ARITH_NODE, "mul", 5); break;
-
- case DIVIDE_SEP: Op_(ARITH_NODE, "div", 5); break;
-
- case REMAINDER_SEP: Op_(ARITH_NODE, "mod", 5); break;
-
- case ARTAND_SEP: Op_(ARITH_NODE, "and", 5); break;
-
- case ARTOR_SEP: Op_(ARITH_NODE, "or", 5); break;
-
- case ARROW_SEP: Op_(ARITH_NODE, "loadb", 6); break;
-
- case DARROW_SEP: Op_(ARITH_NODE, "loadw", 6); break;
-
- case PROPERTY_SEP: Op_(ARITH_NODE, "get_prop", 7); break;
-
- case PROPADD_SEP: Op_(ARITH_NODE, "get_prop_addr", 7); break;
-
- case PROPNUM_SEP: Op_(ARITH_NODE, "_get_prop_len", 7);
- revise_flag=1; break;
-
- case INC_SEP: Op1_(ALTERA_NODE, "inc", 9); break;
-
- case DEC_SEP: Op1_(ALTERA_NODE, "dec", 9); break;
-
- case OPENB_SEP:
- current_priority+=10;
- last_was_openb=2;
- if (last_was_leaf==0)
- { if (bracket_level==MAX_EXPRESSION_BRACKETS)
- { error("Brackets '(' too deeply nested");
- goto BigBreak; }
- brackets[bracket_level++]=1;
- }
- else
- { sofar_empty=1; brackets[bracket_level++]=0;
- j=token; call_args=2; call_level=bracket_level;
- word(sub_buffer,token);
- OnS_(")") call_args=1;
- else
- do { word(sub_buffer,j++);
- if (sub_buffer[0]==0)
- { error("Missing bracket ')' in function call");
- goto BigBreak;
- }
- if ((strcmp(sub_buffer,",")==0)
- &&(bracket_level==call_level))
- call_args++;
- OnS_("(") call_level++;
- OnS_(")") call_level--;
- } while (call_level>=bracket_level);
- grow_branch(call_args,token-1,FCALL_NODE,"call",
- 1+current_priority);
- comma_mode=1;
- }
- sofar_empty=1;
- break;
-
- case CLOSEB_SEP:
- if (bracket_level--==0) goto BigBreak;
- current_priority-=10;
- break;
-
- case COMMA_SEP:
- if (bracket_level<=0) goto DefaultCase;
- if (brackets[bracket_level-1]==1)
- error("Spurious comma ','");
- comma_mode=1; sofar_empty=1; last_was_comma=2;
- if (tree[dryad].type!=BLANK_NODE)
- { while (tree[dryad].type!=ROOT_NODE)
- { while (tree[dryad].type!=FCALL_NODE)
- dryad=tree[dryad].up;
- if (tree[dryad].branches_made<tree[dryad].arity)
- { dryad=tree[dryad].b[tree[dryad].branches_made];
- goto FoundNewPlace;
- }
- dryad=tree[dryad].up;
- }
- error("Misplaced comma ','"); return(-2);
- FoundNewPlace: resting=0;
- }
- if (etrace_mode==1) show_tree("Comma to");
- break;
-
- default:
- DefaultCase:
- goto TryFurther;
- }
- goto AtomDone;
-
- TryFurther:
-
- if (condition_context==1)
- { switch(wd_tk)
- { case GREATER_SEP: Op_(COND_NODE, "jg", 3); break;
- case LESS_SEP: Op_(COND_NODE, "jl", 3); break;
- case CONDEQUALS_SEP:
- Op_(COND_NODE, "je", 3); break;
- case NOTEQUAL_SEP: Op_(NCOND_NODE, "je", 3); break;
- case GE_SEP: Op_(NCOND_NODE, "jl", 3); break;
- case LE_SEP: Op_(NCOND_NODE, "jg", 3); break;
- case LOGAND_SEP: Op_(LOGICAND_NODE, "&&", 2); break;
- case LOGOR_SEP: Op_(LOGICOR_NODE, "||", 2); break;
- default:
-
- OnS_("or") Op_(OR_NODE, "or", 2);
- else OnS_("far") Op_(NCOND_NODE, "same_parent", 3);
- else OnS_("hasnt") Op_(NCOND_NODE, "test_attr", 3);
- else OnS_("near") Op_(COND_NODE, "same_parent", 3);
- else OnS_("has") Op_(COND_NODE, "test_attr", 3);
- else OnS_("in") { Op_(COND_NODE, "in", 3);
- revise_flag=1; }
- else OnS_("notin"){Op_(NCOND_NODE, "in", 3);
- revise_flag=1; }
- else goto TryYetFurther;
- }
- last_was_openb=2;
- goto AtomDone;
- }
-
- TryYetFurther:
-
- if (resting==1)
- { if (sub_buffer[0]=='-')
- { Op_(ARITH_NODE,"add",4);
- grow_leaf(token-1); sofar_empty=0;
- }
- else
- { if (bracket_level>0)
- error("Operator has too many arguments");
- goto BigBreak;
- }
- }
- else if (tree[dryad].type==BLANK_NODE)
- {
- if ((sub_buffer[0]=='-')&&(last_was_openb==0)&&(last_was_comma==0))
- { Op_(ARITH_NODE,"add",4);
- grow_leaf(token-1); sofar_empty=0;
- goto AtomDone;
- }
-
- sofar_empty=0; grow_leaf(token-1); last_was_leaf=1;
- goto UnlessItWas;
- }
- else
- if (sub_buffer[0]=='-')
- { Op_(ARITH_NODE,"add",4);
- grow_leaf(token-1); sofar_empty=0;
- }
- else goto BigBreak;
-
-
- AtomDone:
- last_was_leaf=0;
- UnlessItWas: ;
- } while (1==1);
-
- BigBreak:
- if ((wd_tk==-1)&&(sub_buffer[0]==0)) next_token= -1;
- else next_token=token-1;
-
- if (bracket_level>0) error("Too many brackets '(' in expression");
-
- /* --------------------------------------------------------------------- */
- /* 4. If necessary, revise the tree to allow for get_prop_len and the */
- /* different contexts of the "=" assignment */
- /* --------------------------------------------------------------------- */
-
- if (revise_flag==1)
- {
- for (i=0; i<tree_size; i++)
- { j=tree[i].b[0];
- if ((tree[i].type==STORE_NODE)&&(tree[j].type==ARITH_NODE)
- &&(tree[i].op!=NULL)&&(strcmp(tree[i].op,"store")==0))
- { k=0;
- if (tree[j].op!=NULL)
- { if (strcmp(tree[j].op,"get_prop")==0) k=1;
- if (strcmp(tree[j].op,"loadb")==0) k=2;
- if (strcmp(tree[j].op,"loadw")==0) k=3;
- }
- if (k!=0)
- {
- if (etrace_mode==1)
- printf("Sub type %d nodes %d and %d\n",k,i,j);
- if (etrace_mode==1) show_tree("Substituting from");
- tree[j].b[tree[j].arity++] = tree[i].b[1];
- tree[j].branches_made++;
- tree[j].type=STORE_NODE;
- tree[j].up=tree[i].up;
- tree[i]=tree[j];
- switch(k)
- { case 1: tree[i].op="put_prop"; break;
- case 2: tree[i].op="storeb"; break;
- case 3: tree[i].op="storew"; break;
- }
- if (etrace_mode==1) show_tree("Substituting to");
- }
- }
- if ((tree[i].op!=NULL)&&(strcmp(tree[i].op,"_get_prop_len")==0))
- {
- tree[i].op="get_prop_addr";
- tree[tree_size]=tree[i];
- tree[tree_size].up=i;
- tree[i].b[0]=tree_size;
- tree[i].arity=1;
- tree[i].branches_made=1;
- tree[i].op="get_prop_len";
- tree_size++;
- if (etrace_mode==1) show_tree("Fixing a _get_prop_len to");
- }
-
- if (((tree[i].type==COND_NODE)||(tree[i].type==NCOND_NODE))
- &&(tree[i].op!=NULL)&&(strcmp(tree[i].op,"in")==0))
- { if (etrace_mode==1) show_tree("Substituting 'in' from");
- j=tree[i].b[0];
- tree[i].op="je";
- tree[tree_size]=tree[j];
- tree[tree_size].up=j;
- tree[j].b[0]=tree_size;
- tree[j].arity=1;
- tree[j].type=ARITH_NODE;
- tree[j].branches_made=1;
- tree[j].op="get_parent";
- tree_size++;
- if (etrace_mode==1) show_tree("Substituting to");
- }
- }
- }
-
- if (condition_context==1)
- { fix_yesno_labels(tree[0].b[0],0);
- }
-
- if (etrace_mode>=1) show_tree("Made the tree:");
-
- /* --------------------------------------------------------------------- */
- /* 5. Recursively cut off branches into assembly language */
- /* --------------------------------------------------------------------- */
-
- if (etrace_mode==2) printf("Compiling code:\n");
-
- do
- { i=0;
- DownDown:
- if ((tree[i].type!=LOGICAND_NODE)&&(tree[i].type!=LOGICOR_NODE))
- { for (j=tree[i].branches_made-1; j>=0; j--)
- { t=tree[tree[i].b[j]].type;
- if ((t!=LEAF_NODE)&&(t!=SP_NODE)&&(t!=CDONE_NODE))
- { i=tree[i].b[j]; goto DownDown;
- }
- }
- }
- else
- { for (j=0; j<tree[i].branches_made; j++)
- { t=tree[tree[i].b[j]].type;
- if ((t!=LEAF_NODE)&&(t!=SP_NODE)&&(t!=CDONE_NODE))
- { i=tree[i].b[j]; goto DownDown;
- }
- }
- }
-
- if (etrace_mode==1) printf("Detaching %d\n",i);
-
- if (i==0)
- { if (tree[tree[0].b[0]].type==SP_NODE) j=-1;
- else if (tree[tree[0].b[0]].type==CDONE_NODE) j=-3;
- else j=tree[tree[0].b[0]].word;
- if (its_void==1) j=-2;
-
- if ((condition_context==0)&&(j==-3))
- { error("Unexpected condition"); return(-2); }
-
- if ((condition_context==1)&&(j!=-3))
- { printf("Expected condition but found expression\n");
- error("Expected condition but found expression");
- return(-2);
- }
-
- if (etrace_mode>=1)
- { word(sub_buffer,next_token);
- if (next_token==-1) printf("Completed: line used up: ");
- else printf("Completed: next word '%s': ",sub_buffer);
- if (j>=0) word(sub_buffer,j);
- if (thrown_away_flag==1) printf("result thrown away\n");
- else if (j==-1) printf("result on stack\n");
- else if (j==-2) printf("no resulting value\n");
- else if (j==-3) printf("a condition\n");
- else printf("result in %s\n",sub_buffer);
- }
- if (thrown_away_flag==1) return(-3);
- return(j);
- }
-
- if (tree[i].branches_made<tree[i].arity)
- error("Operator has too few arguments");
-
- sysfun_arity=0; dummy_branch_flag=0;
- if (tree[i].type==FCALL_NODE)
- { indirect_flag=0;
- InV5
- { tree[i].op="call_**";
- call_args=tree[i].branches_made-1;
- }
- call_i=i; call_flag=1;
- eword(sub_buffer,tree[i].b[0]);
- OnS_("parent") { sysfun_arity=1; tree[i].op="get_parent"; }
- OnS_("sibling") { sysfun_arity=1; tree[i].op="get_sibling";
- dummy_branch_flag=1; }
- OnS_("younger") { sysfun_arity=1; tree[i].op="get_sibling";
- dummy_branch_flag=1; }
- OnS_("child") { sysfun_arity=1; tree[i].op="get_child";
- dummy_branch_flag=1; }
- OnS_("eldest") { sysfun_arity=1; tree[i].op="get_child";
- dummy_branch_flag=1; }
- OnS_("random") { sysfun_arity=1; tree[i].op="random"; }
- OnS_("prop_len") { sysfun_arity=1; tree[i].op="get_prop_len"; }
- OnS_("prop_addr") { sysfun_arity=2; tree[i].op="get_prop_addr"; }
- OnS_("prop") { sysfun_arity=2; tree[i].op="get_prop"; }
- OnS_("children")
- { if (2!=tree[i].branches_made)
- error("'children' takes a single argument");
- estack_line( "@store temp_global 0");
- eword(sub_buffer,
- tree[i].b[1]);
- sprintf(rewrite, "@get_child %s sp ~_x%d",
- sub_buffer,
- no_dummy_labels+1);
- estack_line(rewrite);
- sprintf(rewrite, "@._x%d",
- no_dummy_labels++);
- estack_line(rewrite);
- estack_line( "@inc temp_global");
- sprintf(rewrite, "@get_sibling sp sp _x%d",
- no_dummy_labels-1);
- estack_line(rewrite);
- sprintf(rewrite, "@._x%d",
- no_dummy_labels++);
- estack_line(rewrite);
- sprintf(rewrite, "@add sp temp_global sp");
- estack_line(rewrite);
- tree[i].type=SP_NODE;
- tree[i].word=-1;
- goto Detached;
- }
- OnS_("youngest")
- { if (2!=tree[i].branches_made)
- error("'youngest' takes a single argument");
- eword(sub_buffer,tree[i].b[1]);
- sprintf(rewrite, "@get_child %s temp_global ~_x%d",
- sub_buffer,
- no_dummy_labels+1);
- estack_line(rewrite);
- estack_line( "@push temp_global");
- sprintf(rewrite, "@._x%d",
- no_dummy_labels++);
- estack_line(rewrite);
- estack_line( "@store temp_global sp");
- sprintf(rewrite, "@get_sibling temp_global sp _x%d",
- no_dummy_labels-1);
- estack_line(rewrite);
- sprintf(rewrite, "@._x%d",no_dummy_labels++);
- estack_line(rewrite);
- sprintf(rewrite, "@push temp_global");
- estack_line(rewrite);
- tree[i].type=SP_NODE;
- tree[i].word=-1;
- goto Detached;
- }
- OnS_("elder")
- { if (2!=tree[i].branches_made)
- error("'elder' takes a single argument");
- eword(sub_buffer,tree[i].b[1]);
- sprintf(rewrite, "@store temp_global %s",
- sub_buffer);
- estack_line(rewrite);
- estack_line( "@store temp_global3 0");
- estack_line( "@get_parent temp_global sp");
- sprintf(rewrite, "@get_child sp temp_global2 _x%d",
- no_dummy_labels);
- estack_line(rewrite);
- sprintf(rewrite, "@._x%d",no_dummy_labels++);
- estack_line(rewrite);
- sprintf(rewrite, "@je temp_global temp_global2 _x%d",
- no_dummy_labels);
- estack_line(rewrite);
- estack_line( "@store temp_global3 temp_global2");
- sprintf(rewrite, "@get_sibling temp_global2 temp_global2 _x%d",
- no_dummy_labels-1);
- estack_line(rewrite);
- sprintf(rewrite, "@._x%d",
- no_dummy_labels++);
- estack_line(rewrite);
- sprintf(rewrite, "@push temp_global3");
- estack_line(rewrite);
- tree[i].type=SP_NODE;
- tree[i].word=-1;
- goto Detached;
- }
-
- OnS_("indirect")
- { if (tree[i].branches_made<2)
- { error("'indirect' takes at least one argument"); }
- sysfun_arity=1; tree[i].op="icall"; indirect_flag=1;
- }
- else
- if (sysfun_arity!=0)
- { if (sysfun_arity+1!=tree[i].branches_made)
- { error("Wrong number of arguments to system function");
- }
- }
- }
- else call_flag=0;
-
- t=tree[i].type;
-
- if ((t==LOGICAND_NODE)||(t==LOGICOR_NODE))
- { for (j=0; j<tree[i].branches_made; j++)
- { if (tree[tree[i].b[j]].type != CDONE_NODE)
- { error("Expected condition but found expression");
- return(-2);
- }
- }
- sprintf(rewrite,"@._x%d",tree[i].label_number);
- estack_line(rewrite);
- tree[i].type=CDONE_NODE;
- goto Detached;
- }
-
- if (t==ALTERB_NODE)
- { if (tree[tree[i].b[0]].type!=LEAF_NODE)
- { error("'++' and '--' can only apply directly to variables");
- return(-2);
- }
- eword(sub_buffer,tree[i].b[0]);
- sprintf(rewrite,"@%s %s",tree[i].op,sub_buffer);
- estack_line(rewrite);
- tree[i].type=LEAF_NODE;
- tree[i].word=tree[tree[i].b[0]].word;
- tree[i].arity=0;
- tree[i].branches_made=0;
- if (tree[i].up==0)
- if (assign_context==1) its_void=1;
- goto Detached;
- }
- if (t==ALTERA_NODE)
- { if (tree[tree[i].b[0]].type!=LEAF_NODE)
- { error("'++' and '--' can only apply directly to variables");
- return(-2);
- }
- if ((tree[i].up==0)&&(assign_context==1))
- { eword(sub_buffer,tree[i].b[0]);
- sprintf(rewrite,"@%s %s",tree[i].op,sub_buffer);
- estack_line(rewrite);
- tree[i].type=LEAF_NODE;
- tree[i].word=tree[tree[i].b[0]].word;
- tree[i].arity=0;
- tree[i].branches_made=0;
- if (assign_context==1) its_void=1;
- goto Detached;
- }
- eword(sub_buffer,tree[i].b[0]);
- sprintf(rewrite,"@push %s",sub_buffer);
- estack_line(rewrite);
- sprintf(rewrite,"@%s %s",tree[i].op,sub_buffer);
- estack_line(rewrite);
- tree[i].type=SP_NODE;
- tree[i].arity=0;
- tree[i].branches_made=0;
- goto Detached;
- }
-
- if (strcmp(tree[i].op,"get_prop_len")==0)
- { eword(sub_buffer,tree[i].b[0]);
- sprintf(rewrite,"@store temp_global %s",sub_buffer);
- estack_line(rewrite);
- sprintf(rewrite,"@jz temp_global _x%d",no_dummy_labels);
- estack_line(rewrite);
- sprintf(rewrite,"@get_prop_len temp_global temp_global");
- estack_line(rewrite);
- sprintf(rewrite,"@._x%d",no_dummy_labels++);
- estack_line(rewrite);
-
- if ((tree[tree[i].up].op!=NULL) &&
- (strcmp(tree[tree[i].up].op,"store")==0))
- { word(sub_buffer,tree[tree[tree[i].up].b[0]].word);
- i=tree[i].up; t=STORE_NODE;
- sprintf(rewrite,"@store %s temp_global",sub_buffer);
- }
- else sprintf(rewrite,"@push temp_global");
-
- }
- else
- {
- sprintf(rewrite,"@%s ",tree[i].op);
-
- for (j=(sysfun_arity>0)?1:0; j<tree[i].branches_made; j++)
- { eword(sub_buffer,tree[i].b[j]);
- sprintf(rewrite+strlen(rewrite),"%s ",sub_buffer);
- }
-
- if ((sub_buffer[0]=='-') && (tree[i].op!=NULL)
- && (strcmp(tree[i].op,"add")==0))
- { eword(sub_buffer,tree[i].b[0]);
- sprintf(rewrite,"@sub %s ",sub_buffer);
- eword(sub_buffer,tree[i].b[1]);
- sprintf(rewrite+strlen(rewrite),"%s ",sub_buffer+1);
- }
-
- if ((t==ARITH_NODE)||(t==FCALL_NODE))
- { if ((tree[tree[i].up].op!=NULL) &&
- (strcmp(tree[tree[i].up].op,"store")==0))
- { word(sub_buffer,tree[tree[tree[i].up].b[0]].word);
- i=tree[i].up; t=STORE_NODE;
- }
- else sprintf(sub_buffer,"sp");
- sprintf(rewrite+strlen(rewrite),"%s",sub_buffer);
- }
- }
-
- if (dummy_branch_flag==1)
- { sprintf(rewrite+strlen(rewrite)," _x%d",no_dummy_labels);
- }
- if ((t==COND_NODE)||(t==NCOND_NODE))
- { int pflag, lnumber, lat, tup;
- tup=tree[i].up; lat=tree[tup].label_number;
- switch(tree[tup].type)
- { case ROOT_NODE: lnumber=-1; pflag=0; break;
- case LOGICAND_NODE:
- if (tree[tup].b[tree[tup].branches_made-1]!=i)
- { lnumber=tree[tup].no_label; pflag=0; }
- else
- { if (lat==tree[tup].yes_label)
- { lnumber=tree[tup].no_label; pflag=0; }
- else
- { lnumber=tree[tup].yes_label; pflag=1; }
- }
- break;
- case LOGICOR_NODE:
- if (tree[tup].b[tree[tup].branches_made-1]!=i)
- { lnumber=tree[tup].yes_label; pflag=1; }
- else
- { if (lat==tree[tup].no_label)
- { lnumber=tree[tup].yes_label; pflag=1; }
- else
- { lnumber=tree[tup].no_label; pflag=0; }
- }
- break;
- default:
- error("Attempt to use a condition as a value");
- return(-2);
- }
- if (pflag==0)
- sprintf(rewrite+strlen(rewrite),"?%s",
- (t==COND_NODE)?"~":"");
- else
- sprintf(rewrite+strlen(rewrite),"?%s",
- (t!=COND_NODE)?"~":"");
- if (lnumber==-1)
- sprintf(rewrite+strlen(rewrite),"%s",
- condition_label);
- else
- sprintf(rewrite+strlen(rewrite),"_x%d",
- lnumber);
- }
-
- if (call_flag==1)
- { tosp_flag=0;
- if (strcmp(sub_buffer,"sp")==0) tosp_flag=1;
-
- InV3
- {
- if ((tosp_flag==1)&&(void_context==1)&&(tree[call_i].up==0))
- { sprintf(rewrite+(strlen(rewrite)-2), "temp_global");
- thrown_away_flag=1;
- }
- }
-
- if (actual_version == 4)
- {
- if (sysfun_arity==0)
- { rewrite[7]='s';
- switch(call_args)
- { case 0: rewrite[6]='1'; break;
- case 1: rewrite[6]='2'; break;
- default: rewrite[6]='v'; break;
- }
- if ((tosp_flag==1)&&(void_context==1)&&(tree[call_i].up==0))
- { sprintf(rewrite+(strlen(rewrite)-2), "temp_global");
- thrown_away_flag=1;
- }
- }
- if (indirect_flag==1)
- if ((tosp_flag==1)&&(void_context==1)&&(tree[call_i].up==0))
- { sprintf(rewrite+(strlen(rewrite)-2), "temp_global");
- thrown_away_flag=1;
- }
- }
-
- if (actual_version >= 5)
- {
- if (sysfun_arity==0)
- { rewrite[7]='s';
- switch(call_args)
- { case 0: rewrite[6]='1'; break;
- case 1: rewrite[6]='2'; break;
- default: rewrite[6]='v'; break;
- }
- if ((tosp_flag==1)&&(void_context==1)&&(tree[call_i].up==0))
- { rewrite[7]='n';
- rewrite[strlen(rewrite)-3]=0;
- thrown_away_flag=1;
- }
- }
- if (indirect_flag==1)
- if ((tosp_flag==1)&&(void_context==1)&&(tree[call_i].up==0))
- { sprintf(rewrite+(strlen(rewrite)-2), "temp_global");
- thrown_away_flag=1;
- }
- }
- }
-
- estack_line(rewrite);
-
- if (dummy_branch_flag==1)
- { sprintf(rewrite,"@._x%d",no_dummy_labels++);
- estack_line(rewrite);
- }
-
- if (t==STORE_NODE) tree[i]=tree[tree[i].b[0]];
- else
- { tree[i].arity=0;
- tree[i].type= SP_NODE;
- tree[i].branches_made=0;
- }
- switch(t)
- { default: tree[i].type = SP_NODE; break;
- case COND_NODE:
- case NCOND_NODE:
- case LOGICOR_NODE:
- case LOGICAND_NODE: tree[i].type = CDONE_NODE; break;
- }
-
- Detached:
- if (etrace_mode==1) show_tree("to");
- } while (1==1);
- return(1);
- }
-
- extern void assignment(int from, int flag)
- { int i;
- next_token=from;
- do
- { assign_context=1; i=expression(next_token); assign_context=0;
- if ((i!=-2)&&(i!=from))
- { error("Expected an assignment but found an expression");
- return;
- }
- if (i==from)
- { word(sub_buffer,from);
- if (flag==1)
- error_named("Expected an assignment, command, directive \
- or opcode but found",sub_buffer);
- else
- error_named("Expected an assignment but found",sub_buffer);
- return;
- }
- if (next_token==-1) return;
- word(sub_buffer,next_token);
- if (strcmp(sub_buffer,",")!=0) return;
- next_token++;
- } while (1==1);
- }
-
-