C:/Users/Dennis/src/lang/bertrand/BERTRAND/bertrand/match.c

Go to the documentation of this file.
00001 #include "def.h"
00002 #include <string.h>
00003 
00004 #define MAXP 32         /* maximum number of parameters in a rule */
00005 NODE *param_val[MAXP];  /* array of parameter values */
00006 int learn;              /* did I learn anything? */
00007 int bondage;            /* did a variable get bound? */
00008 static SNODE *stack;    /* stack for walking tree */
00009 
00010 #define WR  1           /* walk right next */
00011 #define POP 2           /* pop stack next */
00012 #define HAS_ARG (UNARY | BINARY)        /* is a term that has an argument */
00013 
00014 typedef struct sub_stack {
00015     struct sub_stack *next;
00016     NODE *exp;
00017     } SUB_STACK;
00018 static SUB_STACK *sub_top = NULL;
00019 
00020 /******************************************************************
00021  *
00022  * Push old subject expression on stack, get new subject expression.
00023  *
00024  ******************************************************************/
00025 void
00026 subject_push(old)
00027 NODE *old;              /* old subject expression */
00028 {
00029 char *malloc();
00030 register SUB_STACK *node;
00031 
00032 node = (SUB_STACK *) malloc(sizeof(SUB_STACK));
00033 node->next = sub_top;
00034 node->exp = old;
00035 }
00036 
00037 /******************************************************************
00038  *
00039  * Pop old subject expression off stack.
00040  *
00041  ******************************************************************/
00042 NODE *
00043 subject_pop()
00044 {
00045 void free();
00046 register SUB_STACK *node;
00047 register NODE *exp;
00048 
00049 if (!sub_top) return NULL;
00050 node = sub_top;
00051 sub_top = node->next;
00052 exp = node->exp;
00053 free(node);
00054 return exp;
00055 }
00056 
00057 /******************************************************************
00058  *
00059  * Find a rule that matches an expression.
00060  *
00061  * entry:       an expression
00062  *
00063  * exit:        returns the rule that matched
00064  *              return NULL if no rule matches this expression.
00065  *              Does not try to match against subexpressions.
00066  *
00067  ******************************************************************/
00068 static RULE *
00069 match(exp)
00070 NODE *exp;      /* the expression to match */
00071 {
00072 int match_sub();        /* forward reference */
00073 register RULE *rtt;     /* rule to try */
00074 
00075 /* this assumes that the root of all rule heads are terms */
00076 if (!(exp->op->arity & OP_TERM)) return (RULE *) NULL; 
00077 
00078 for(rtt = exp->op->hash; rtt; rtt = rtt->next) {
00079     if (match_sub(rtt->head, exp)) return rtt;
00080     }
00081 return (RULE *) NULL;   /* no rule matched */
00082 }
00083 
00084 /******************************************************************
00085  *
00086  * See if a parameter with a guard matches its argument
00087  *
00088  ******************************************************************/
00089 
00090 static int
00091 match_types(guard, exp)
00092 OP *guard;              /* type to match */
00093 NODE *exp;              /* expression to match against */
00094 {
00095 register OP *mt = exp->op;
00096 for (; mt; mt = mt->super) if (guard == mt) return TRUE;
00097 return FALSE;
00098 }
00099 
00100 /******************************************************************
00101  *
00102  * Match a single rule against an expression.
00103  * TO DO:       Works recursively, SHOULD USE THE STACK.
00104  *
00105  ******************************************************************/
00106 static int
00107 match_sub(head, exp)
00108 register NODE *head;            /* pattern to match against */
00109 register NODE *exp;             /* subexpression to match */
00110 {
00111 char *arity_name();             /* from ops.c */
00112 extern OP *untyped_prim;        /* from primitive.c */
00113 
00114 if (head->op->arity == OP_STR) {
00115     return (exp->op->arity == OP_STR && 0 == strcmp(
00116         ((STR_NODE *) head)->value, ((STR_NODE *) exp)->value));
00117     }
00118 if (head->op->arity == OP_NUM) {
00119     return (exp->op->arity == OP_NUM &&
00120         ((NUM_NODE *) head)->value == ((NUM_NODE *) exp)->value);
00121     }
00122 if (head->op->arity == OP_NAME) {       /* parameter */
00123     if (head->op == untyped_prim || match_types(head->op, exp)) {
00124         /* bind value to parameter */
00125         ((NAME_NODE *) head)->value = exp;
00126         return TRUE;
00127         }
00128     else return FALSE;
00129     }
00130 if (head->op->arity == NULLARY) {
00131     return ((exp->op->arity == NULLARY) && (head->op == exp->op));
00132     }
00133 if (head->op->arity & UNARY) {
00134     if ((head->op->arity != exp->op->arity) || (head->op != exp->op))
00135         return FALSE;
00136     if (head->op->arity == POSTFIX) return match_sub(
00137         ((TERM_NODE *) head)->left, ((TERM_NODE *) exp)->left);
00138     else return         /* PREFIX and OUTFIX */
00139         match_sub(((TERM_NODE *) head)->right,((TERM_NODE *) exp)->right);
00140     }
00141 if (head->op->arity & BINARY) {
00142 /* Had to change the following because of a bug in the Sun C compiler */
00143 /*  return ((exp->op->arity & BINARY) &&
00144         match_sub(((TERM_NODE *) head)->left, ((TERM_NODE *) exp)->left) &&
00145         match_sub(((TERM_NODE *) head)->right,((TERM_NODE *) exp)->right)); */
00146     if ((!(exp->op->arity & BINARY)) || (head->op != exp->op)) return FALSE;
00147     if (!match_sub(((TERM_NODE *) head)->left, ((TERM_NODE *) exp)->left))
00148         return FALSE;
00149     if (!match_sub(((TERM_NODE *) head)->right,((TERM_NODE *) exp)->right))
00150         return FALSE;
00151     return TRUE;
00152     }
00153 fprintf(stderr, "arity: %s\n", arity_name(exp->op->arity));
00154 error("Unknown arity during pattern match!");
00155 return FALSE;   /* will never execute */
00156 }
00157 
00158 /*************************************************************
00159  *
00160  * Walk the tree, looking for subexpressions that match a rule
00161  *
00162  * exit:        possibly transformed expression
00163  *              sets global variable "learn" if transformed.
00164  *
00165  *************************************************************/
00166 NODE *
00167 walk(subject)
00168 NODE *subject;          /* subject expression */
00169 {
00170 SNODE *st_get();                /* from util.c */
00171 NODE *instantiate();            /* forward reference */
00172 NODE *primitive_execute();      /* from primitives.c */
00173 void expr_free();               /* from expr.c */
00174 NAME_NODE *name_space_insert(); /* from names.c */
00175 void name_free();               /* from names.c */
00176 NODE *expr_copy();              /* from expr.c */
00177 NODE *expr_update();            /* from expr.c */
00178 extern OP *untyped_prim;        /* from primitive.c */
00179 
00180 register NODE *cn = subject;    /* current node */
00181 register SNODE *stn;            /* a stack node */
00182 NAME_NODE *ts;                  /* temp name space pointer */
00183 RULE *mrule;                    /* the rule that matched */
00184 NODE *ib;                       /* instantiated body */
00185 
00186 learn = FALSE;                  /* haven't learned anything yet */
00187 stack = (SNODE *) NULL;         /* initially empty */
00188 
00189 for (;;) {      /* for ever */
00190     if (cn->op->arity == OP_NAME && ((NAME_NODE *)cn)->value) {
00191         fprintf(stderr, "variable: ");
00192         name_print((NAME_NODE *)cn);
00193         fprintf(stderr, "\n");
00194         error("Found loose bound variable in subject expression!");
00195         }
00196     else if (mrule = match(cn)) {       /* found a match */
00197         learn = TRUE;
00198         if ((mrule->verbose + verbose)>1) {
00199             fprintf(stderr, "MATCH: ");
00200             rule_print(mrule);
00201             expr_print(subject);
00202             fprintf(stderr, " ==> ");
00203             }
00204         /* if rule has a tag, and redex is labeled, then type the label */
00205         if ((cn->op->arity & OP_TERM) && (((TERM_NODE *) cn)->label)) {
00206             ((TERM_NODE *) cn)->label->op = (mrule->tag) ?
00207                 (mrule->tag) : untyped_prim;
00208             ts = name_space_insert(mrule->space, ((TERM_NODE *) cn)->label);
00209             }
00210         else {          /* create new (disjoint) name space */
00211             ts = name_space_insert(mrule->space, (NAME_NODE *) NULL);
00212             name_free(ts);      /* root of space is dummy node */
00213             }
00214         if (mrule->body->op->eval > 0) {
00215             ib = primitive_execute(mrule->body->op->eval, cn);  /* primitive */
00216             }
00217         else ib = instantiate(mrule->body);     /* regular rule */
00218         expr_free(cn);
00219         ib = expr_update(ib);   /* remove any bound variables */
00220         if (stack) {
00221             if ((stack->info == WR) || (stack->node->op->arity == POSTFIX))
00222                 ((TERM_NODE *) stack->node)->left = ib;
00223             else ((TERM_NODE *) stack->node)->right = ib;
00224             }
00225         else subject = ib;
00226         if (bondage) {  /* a variable was bound */
00227             subject = expr_update(subject);
00228             bondage = FALSE;
00229             }
00230         if ((mrule->verbose + verbose)>1) {
00231             expr_print(subject);
00232             fprintf(stderr, "\n");
00233             }
00234         return subject;
00235         }
00236     else {      /* walk children */
00237         /* do not walk children if eval function = -4 (usually []) */
00238         if (cn->op->arity & HAS_ARG && cn->op->eval != -4) {
00239             stn = st_get();
00240             stn->next = stack;  /* push on stack */
00241             stack = stn;
00242             stn->node = cn;
00243             if (cn->op->arity & BINARY) {
00244                 stn->info = WR;         /* next action is walk right */
00245                 cn = ((TERM_NODE *) cn)->left;
00246                 }
00247             else {      /* unary */
00248                 stn->info = POP;        /* next action is pop */
00249                 if (cn->op->arity == POSTFIX) cn = ((TERM_NODE *) cn)->left;
00250                 else cn = ((TERM_NODE *) cn)->right;
00251                 }
00252             }
00253         else {          /* terminal node, walk back up stack */
00254             stn = NULL;
00255             do {
00256                 if (stn) st_free(stn);
00257                 stn = stack;
00258                 if (!stn) return subject;
00259                 cn = stn->node;
00260                 stack = stn->next;
00261                 } while (stn->info == POP);
00262             stack = stn;        /* push back, walk right */
00263             cn = ((TERM_NODE *) cn)->right;
00264             stn->info = POP;    /* next move will be a pop */
00265             }
00266         }       /* end of no match at this node */
00267     }           /* end of forever */
00268 }
00269 
00270 /*************************************************************
00271  *
00272  * Instantiate the body of a rule
00273  * Make a copy of the expression, insert parameters,
00274  *  put other names into name space.
00275  *
00276  * exit:        new expression to be inserted into subject expression
00277  *
00278  *************************************************************/
00279 NODE *
00280 instantiate(body)
00281 NODE *body;             /* body of rule */
00282 {
00283 NAME_NODE *name_copy();         /* from names.c */
00284 NODE *expr_copy();              /* from expr.c */
00285 NODE *node_new();               /* from expr.c */
00286 char *arity_name();             /* from ops.c */
00287 
00288 if (!body) error("cannot instantiate null rule body");
00289 if (!body->op) error("missing operator in instantiate");
00290 
00291 if (body->op->arity & OP_TERM) {        /* TERM_NODE */
00292     TERM_NODE *te = (TERM_NODE *) node_new();
00293     te->op = body->op;
00294     if (((TERM_NODE *) body)->label)
00295         te->label = name_copy(((TERM_NODE *) body)->label->value);
00296     else te->label = (NAME_NODE *) NULL;
00297     if (((TERM_NODE *) body)->right)
00298         te->right = instantiate(((TERM_NODE *) body)->right);
00299     else te->right = (NODE *) NULL;
00300     if (((TERM_NODE *) body)->left)
00301         te->left = instantiate(((TERM_NODE *) body)->left);
00302     else te->left = (NODE *) NULL;
00303     return (NODE *) te;
00304     }
00305 if (body->op->arity == OP_NUM) {
00306     NUM_NODE *ne = (NUM_NODE *) node_new();
00307     ne->op = body->op;
00308     ne->value = ((NUM_NODE *) body)->value;
00309     return (NODE *) ne;
00310     }
00311 if (body->op->arity == OP_STR) {
00312     STR_NODE *se = (STR_NODE *) node_new();
00313     se->op = body->op;
00314     /* WARNING: following leaves two pointers to the same string */
00315     se->value = ((STR_NODE *) body)->value;
00316     return (NODE *) se;
00317     }
00318 if (body->op->arity == OP_NAME) {       /* parameter or local name */
00319     return expr_copy(((NAME_NODE *) body)->value);
00320     }
00321 /* if we get here, then there is an error */
00322 fprintf(stderr, "operator: %s, arity: %s\n",
00323     body->op->pname, arity_name(body->op->arity));
00324 error("invalid operator arity in instantiate");
00325 }

Generated on Fri Jan 25 09:58:43 2008 for Bertrand by  doxygen 1.5.4