bl791's picture
download
raw
46.8 kB
/* ------------------------------------------------------------------------- */
/* "express" : The expression evaluator */
/* */
/* Part of Inform release 5 */
/* */
/* ------------------------------------------------------------------------- */
#include "header.h"
int sys_functions[16];
extern int replace_sf(char *b)
{ int x=-1;
word(b,2);
On_("parent") x=0;
On_("sibling") x=1;
On_("younger") x=2;
On_("child") x=3;
On_("eldest") x=4;
On_("random") x=5;
On_("prop_len") x=6;
On_("prop_addr") x=7;
On_("prop") x=8;
On_("children") x=9;
On_("youngest") x=10;
On_("elder") x=11;
On_("indirect") x=12;
if (x==-1) return(0);
sys_functions[x]=1;
return(1);
}
/* ------------------------------------------------------------------------- */
/* 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=0, prefix=0, postfix=0;
if ((a>=5)&&(actual_version==3))
{ error("A function may be called with at most 3 arguments");
return;
}
if ((a>=9)&&(actual_version>3))
{ error("A function may be called with at most 7 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==OR_NODE)
{ if ((strcmp(tree[above_dryad].op,"je")==0)
|| (strcmp(tree[above_dryad].op,"vje")==0))
{ if (tree[above_dryad].arity < 5)
{ tree[above_dryad].arity++; rflag=1; }
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)
{ if (tree_size==MAX_EXPRESSION_NODES) goto TooComplex;
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;
}
}
else
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)
|| ((tree[above_dryad].priority==prio)
&& (type==ARITH_NODE)
&& (tree[above_dryad].type==ARITH_NODE)))
{ 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;
if (tree_size==MAX_EXPRESSION_NODES) goto TooComplex;
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");
return;
TooComplex:
memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES);
}
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==',') || (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_("in") Op_(COND_NODE, "jin", 3);
else OnS_("notin") Op_(NCOND_NODE, "jin", 3);
else OnS_("has") Op_(COND_NODE, "test_attr", 3);
else OnS_("hasnt") Op_(NCOND_NODE, "test_attr", 3);
else OnS_("far") error("'far' is obselete and withdrawn");
else OnS_("near") error("'near' is obselete and withdrawn");
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";
if (tree_size==MAX_EXPRESSION_NODES) goto TooComplexToo;
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";
if (tree_size==MAX_EXPRESSION_NODES) goto TooComplexToo;
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))
{ error("Expected condition but found expression");
return(-2);
}
if (etrace_mode>=1)
{ if (next_token==-1) printf("Completed: line used up: ");
else
{ word(sub_buffer,next_token);
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]);
#define SysF_(x,n) if ((strcmp(sub_buffer,x)==0)&&(sys_functions[n]==0))
SysF_("parent",0) { sysfun_arity=1; tree[i].op="get_parent"; }
SysF_("sibling",1) { sysfun_arity=1; tree[i].op="get_sibling";
dummy_branch_flag=1; }
SysF_("younger",2) { sysfun_arity=1; tree[i].op="get_sibling";
dummy_branch_flag=1; }
SysF_("child",3) { sysfun_arity=1; tree[i].op="get_child";
dummy_branch_flag=1; }
SysF_("eldest",4) { sysfun_arity=1; tree[i].op="get_child";
dummy_branch_flag=1; }
SysF_("random",5) { sysfun_arity=1; tree[i].op="random"; }
SysF_("prop_len",6) { sysfun_arity=1; tree[i].op="get_prop_len"; }
SysF_("prop_addr",7) { sysfun_arity=2; tree[i].op="get_prop_addr"; }
SysF_("prop",8) { sysfun_arity=2; tree[i].op="get_prop"; }
SysF_("children",9)
{ 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;
}
SysF_("youngest",10)
{ 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;
}
SysF_("elder",11)
{ 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;
}
SysF_("indirect",12)
{ 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 (call_args>3) rewrite[8]='2'; else rewrite[8]=' ';
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 (call_args>3) rewrite[8]='2'; else rewrite[8]=' ';
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);
TooComplexToo:
memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES);
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);
}
extern void init_express_vars(void)
{ int i;
dryad_veil = -1;
condition_context = 0;
assign_context = 0;
for (i=0;i<16;i++) sys_functions[i]=0;
#ifdef ALLOCATE_BIG_ARRAYS
tree = NULL;
#endif
}

Xet Storage Details

Size:
46.8 kB
·
Xet hash:
cf8af5fafa08d6566dc187bdcdbef9a3178418ba738e1d4d46318f8a86fb21c6

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.