|
FAUST compiler
0.9.9.6b8
|
00001 00002 /* compiler/patternmatcher/patternmatcher.cpp: implementation of the Faust 00003 rewriting engine */ 00004 00005 #include "tlib.hh" 00006 #include "list.hh" 00007 #include "boxes.hh" 00008 #include "ppbox.hh" 00009 #include "eval.hh" 00010 #include "patternmatcher.hh" 00011 00012 using namespace std; 00013 #include <vector> 00014 #include <list> 00015 #include <set> 00016 #include <utility> 00017 00018 /* Uncomment for debugging output. */ 00019 //#define DEBUG 00020 00021 /* Additional Tree deconstruction operations. */ 00022 00023 /* Check for cons (nonempty list) nodes. */ 00024 00025 static inline bool isCons(Tree x, Tree& h, Tree& t) 00026 { 00027 if (isList(x)) { 00028 h = hd(x); t = tl(x); 00029 return true; 00030 } else 00031 return false; 00032 } 00033 00034 /* Deconstruct a (BDA) op pattern (YO). */ 00035 00036 static inline bool isBoxPatternOp(Tree box, Node& n, Tree& t1, Tree& t2) 00037 { 00038 if ( isBoxPar(box, t1, t2) || 00039 isBoxSeq(box, t1, t2) || 00040 isBoxSplit(box, t1, t2) || 00041 isBoxMerge(box, t1, t2) || 00042 isBoxHGroup(box, t1, t2) || 00043 isBoxVGroup(box, t1, t2) || 00044 isBoxTGroup(box, t1, t2) || 00045 isBoxRec(box, t1, t2) ) 00046 { 00047 n = box->node(); 00048 return true; 00049 } else { 00050 return false; 00051 } 00052 } 00053 00054 /* TA data structures. */ 00055 00056 /* subterm paths */ 00057 00058 typedef vector<int> Path; 00059 00060 /* Subterm at given path in given term tree. */ 00061 00062 static Tree subtree(Tree X, int i, const Path& p) 00063 { 00064 int n = p.size(); 00065 Node op(0); 00066 Tree x0, x1; 00067 if (i < n && isBoxPatternOp(X, op, x0, x1)) 00068 return subtree((p[i]==0)?x0:x1, i+1, p); 00069 else 00070 return X; 00071 } 00072 00073 /* rule markers */ 00074 00075 struct Rule { 00076 int r; // rule number 00077 Tree id; // matched variable (NULL if none) 00078 Path p; // subterm path indicating where variable value is found 00079 00080 Rule(int _r, Tree _id) : r(_r), id(_id), p(Path()) {} 00081 Rule(int _r, Tree _id, const Path& _p) : r(_r), id(_id), p(_p) {} 00082 Rule(const Rule& rule) : r(rule.r), id(rule.id), p(rule.p) {} 00083 00084 Rule& operator = (const Rule& rule) 00085 { r = rule.r; id = rule.id; p = rule.p; return *this; } 00086 00087 bool operator == (const Rule& rule) const 00088 { return r == rule.r; } 00089 bool operator < (const Rule& rule) const 00090 { return r < rule.r; } 00091 00092 #ifdef DEBUG 00093 ostream& print(ostream& fout) const; 00094 #endif 00095 }; 00096 00097 struct State; 00098 00099 /* transitions */ 00100 00101 struct Trans { 00102 Tree x; // symbol or constant (NULL for variable) 00103 Node n; // operator symbol (if arity>0) 00104 int arity; // symbol arity 00105 State *state; // successor state 00106 00107 Trans(Tree _x); 00108 Trans(const Node& _n, int _arity); 00109 Trans(const Trans& trans); 00110 ~Trans(); 00111 00112 Trans& operator = (const Trans& trans); 00113 00114 bool is_var_trans() const { return arity == 0 && x == NULL; } 00115 bool is_cst_trans(Tree &_x) const { _x = x; return arity == 0 && x != NULL; } 00116 bool is_op_trans(Node &_n) const { _n = n; return arity > 0; } 00117 00118 bool operator == (const Trans& trans) const 00119 { return arity == trans.arity && x == trans.x && n == trans.n; } 00120 bool operator < (const Trans& trans) const 00121 { return (arity < trans.arity) ? 1 : 00122 (arity > trans.arity) ? 0 : 00123 (arity == 0) ? (x < trans.x) : 00124 (n.getSym() < trans.n.getSym()); } 00125 00126 #ifdef DEBUG 00127 ostream& print(ostream& fout) const; 00128 #endif 00129 }; 00130 00131 /* states */ 00132 00133 struct State { 00134 int s; // state number 00135 bool match_num; // whether state has a transition on a numeric constant 00136 list<Rule> rules; // rule markers 00137 list<Trans> trans; // transitions (1st transition is on variable if available) 00138 State() : 00139 s(0), match_num(false), rules(list<Rule>()), trans(list<Trans>()) {} 00140 State(const State& state) : 00141 s(state.s), match_num(state.match_num), 00142 rules(state.rules), trans(state.trans) {} 00143 00144 State& operator = (const State& state) 00145 { s = state.s; match_num = state.match_num; 00146 rules = state.rules; trans = state.trans; 00147 return *this; 00148 } 00149 00150 #ifdef DEBUG 00151 ostream& print(ostream& fout) const; 00152 #endif 00153 }; 00154 00155 // these need to come here so that the storage size of struct State is known 00156 00157 Trans::Trans(Tree _x) : 00158 x(_x), n(0), arity(0), state(new State) 00159 { 00160 } 00161 00162 Trans::Trans(const Node& _n, int _arity) : 00163 x(NULL), n(_n), arity(_arity), state(new State) 00164 { 00165 } 00166 00167 Trans::Trans(const Trans& trans) : 00168 x(trans.x), n(trans.n), arity(trans.arity) 00169 { 00170 state = new State(*trans.state); 00171 } 00172 00173 Trans::~Trans() 00174 { 00175 delete state; 00176 } 00177 00178 Trans& Trans::operator = (const Trans& trans) 00179 { 00180 x = trans.x; n = trans.n; arity = trans.arity; 00181 state = new State(*trans.state); 00182 return *this; 00183 } 00184 00185 /* the automaton */ 00186 00187 struct Automaton { 00188 vector<State*> state; 00189 vector<Tree> rhs; 00190 00191 Automaton() : state(vector<State*>()), rhs(vector<Tree>()), s(0) {} 00192 00193 // number of rules 00194 int n_rules() { return rhs.size(); } 00195 // markers of rules still active in state s 00196 const list<Rule>& rules(int s) { return state[s]->rules; } 00197 // transitions in state s 00198 const list<Trans>& trans(int s) { return state[s]->trans; } 00199 // is s a final state? 00200 bool final(int s) { return trans(s).empty(); } 00201 00202 // assign state numbers and build the state table 00203 int s; 00204 void build(State *st); 00205 00206 #ifdef DEBUG 00207 ostream& print(ostream& fout) const; 00208 #endif 00209 }; 00210 00211 void Automaton::build(State *st) 00212 { 00213 state.push_back(st); 00214 st->s = s++; 00215 list<Trans>::const_iterator t; 00216 for (t = st->trans.begin(); t != st->trans.end(); t++) { 00217 Tree x; 00218 double f; 00219 int i; 00220 if (t->is_cst_trans(x) && 00221 (isBoxInt(x, &i) || isBoxReal(x, &f))) 00222 st->match_num = true; 00223 build(t->state); 00224 } 00225 } 00226 00227 /* Debugging output. */ 00228 00229 #ifdef DEBUG 00230 inline ostream& operator << (ostream& s, const Rule& x) 00231 { return x.print(s); } 00232 inline ostream& operator << (ostream& s, const Trans& x) 00233 { return x.print(s); } 00234 inline ostream& operator << (ostream& s, const State& x) 00235 { return x.print(s); } 00236 inline ostream& operator << (ostream& s, const Automaton& x) 00237 { return x.print(s); } 00238 00239 ostream& Rule::print(ostream& fout) const 00240 { 00241 if (id != NULL) 00242 fout << "#" << r << "(" << *id << ")"; 00243 else 00244 fout << "#" << r; 00245 return fout; 00246 } 00247 00248 ostream& Trans::print(ostream& fout) const 00249 { 00250 if (arity > 0) 00251 fout << "\top " << n << ": state " << state->s << endl; 00252 else if (x == NULL) 00253 fout << "\tvar _: state " << state->s << endl; 00254 else 00255 fout << "\tcst " << *x << ": state " << state->s << endl; 00256 return fout; 00257 } 00258 00259 ostream& State::print(ostream& fout) const 00260 { 00261 fout << "state " << s << ":"; 00262 list<Rule>::const_iterator r; 00263 for (r = rules.begin(); r != rules.end(); r++) 00264 fout << " " << *r; 00265 fout << endl; 00266 list<Trans>::const_iterator t; 00267 for (t = trans.begin(); t != trans.end(); t++) 00268 fout << *t; 00269 return fout; 00270 } 00271 00272 ostream& Automaton::print(ostream& fout) const 00273 { 00274 int i, n = rhs.size(); 00275 for (i = 0; i < n; i++) 00276 fout << "rule #" << i << ": " << *rhs[i] << endl; 00277 n = state.size(); 00278 for (i = 0; i < n; i++) 00279 fout << *state[i]; 00280 return fout; 00281 } 00282 #endif 00283 00284 /* Construction algorithm for the pattern matching automaton. 00285 * 00286 * We employ the incremental technique described in Graef: Left-To-Right Tree 00287 * Pattern Matching, Proc. RTA 1991, Springer 1991 (LNCS 488) to construct a 00288 * tree automaton (TA) for the given patterns. The basic outline of the 00289 * technique is as follows. Initially, the automaton is empty. From each 00290 * pattern we produce a trie (considering the pattern as a string of variable 00291 * and function symbols and constants). This trie is then merged with the TA 00292 * obtained so far. The latter process is similar to merging two deterministic 00293 * finite automata, but it also takes into account the variables (see the 00294 * merge_state() routine below). 00295 */ 00296 00297 /* Construct a trie from a term tree. Takes the "start" and returns the "end" 00298 state of the (sub-)trie. */ 00299 00300 static State *make_state(State *state, int r, Tree x, Path& p) 00301 { 00302 Tree id, x0, x1; 00303 Node op(0); 00304 if (isBoxPatternVar(x, id)) { 00305 /* variable */ 00306 Rule rule(r, id, p); 00307 state->rules.push_back(rule); 00308 Trans trans(NULL); 00309 state->trans.push_back(trans); 00310 return state->trans.begin()->state; 00311 } else if (isBoxPatternOp(x, op, x0, x1)) { 00312 /* composite pattern */ 00313 Rule rule(r, NULL); 00314 state->rules.push_back(rule); 00315 Trans trans(op, 2); 00316 state->trans.push_back(trans); 00317 State *next = state->trans.begin()->state; 00318 p.push_back(0); 00319 next = make_state(next, r, x0, p); 00320 p.pop_back(); 00321 p.push_back(1); 00322 next = make_state(next, r, x1, p); 00323 p.pop_back(); 00324 return next; 00325 } else { 00326 /* constant */ 00327 Rule rule(r, NULL); 00328 state->rules.push_back(rule); 00329 Trans trans(x); 00330 state->trans.push_back(trans); 00331 return state->trans.begin()->state; 00332 } 00333 } 00334 00335 /* Take a copy of a state and prefix it with n variable transitions. */ 00336 00337 static State *make_var_state(int n, State *state) 00338 { 00339 if (n <= 0) 00340 return new State(*state); 00341 list<Rule>rules = state->rules; 00342 list<Rule>::iterator r; 00343 for (r = rules.begin(); r != rules.end(); r++) { 00344 r->id = NULL; r->p = Path(); 00345 } 00346 State *prefix = new State, *current = prefix; 00347 while (n-- > 0) { 00348 current->rules = rules; 00349 Trans trans(NULL); 00350 current->trans.push_back(trans); 00351 current = current->trans.begin()->state; 00352 } 00353 *current = *state; 00354 return prefix; 00355 } 00356 00357 /* Merge two tree automata. Merges the tree automaton rooted at state2 into 00358 the automaton rooted at state1. We assume that state2 is in "trie" form, 00359 i.e., each state has at most one transition, which is always guaranteed 00360 here and simplifies the algorithm. */ 00361 00362 static void merge_state(State *state1, State *state2); 00363 00364 static void inline merge_rules(list<Rule>& rules1, list<Rule>& rules2) 00365 { 00366 list<Rule> cprules2 = rules2; 00367 rules1.merge(cprules2); 00368 } 00369 00370 static void merge_trans_var(list<Trans>& trans, State *state) 00371 { 00372 if (!trans.begin()->is_var_trans()) { 00373 /* If we don't have a variable transition in this state yet then create a 00374 new one. */ 00375 Trans tr(NULL); 00376 trans.push_front(tr); 00377 } 00378 list<Trans>::const_iterator t; 00379 Tree x; 00380 Node op(0); 00381 for (t = trans.begin(); t != trans.end(); t++) { 00382 if (t->is_var_trans()) 00383 merge_state(t->state, state); 00384 else if (t->is_cst_trans(x)) { 00385 /* add the completion of the given state for a constant */ 00386 merge_state(t->state, state); 00387 } else if (t->is_op_trans(op)) { 00388 /* add the completion of the given state for an arity>0 op */ 00389 State *state1 = make_var_state(t->arity, state); 00390 merge_state(t->state, state1); 00391 delete state1; 00392 } 00393 } 00394 } 00395 00396 static void merge_trans_cst(list<Trans>& trans, Tree x, State *state) 00397 { 00398 list<Trans>::iterator t0 = trans.begin(), t1 = t0, t; 00399 Tree x1; 00400 if (t0->is_var_trans()) t1++; 00401 for (t = t1; t != trans.end(); t++) { 00402 if (t->is_cst_trans(x1)) { 00403 if (x == x1) { 00404 merge_state(t->state, state); 00405 return; 00406 } else if (x < x1) 00407 break; 00408 } 00409 } 00410 /* no matching transition has been found; add a new one */ 00411 Trans tr(x); 00412 trans.insert(t, tr); t--; 00413 State *state1 = t->state; 00414 *state1 = *state; 00415 if (t1 != t0) { 00416 /* if we have a variable transition in the current state, we also need to 00417 merge its completion for the current symbol/constant */ 00418 merge_state(state1, t0->state); 00419 } 00420 } 00421 00422 static void merge_trans_op(list<Trans>& trans, const Node& op, 00423 int arity, State *state) 00424 { 00425 /* analogous to merge_trans_cst above, but handles the arity>0 case */ 00426 list<Trans>::iterator t0 = trans.begin(), t1 = t0, t; 00427 Node op1(0); 00428 if (t0->is_var_trans()) t1++; 00429 for (t = t1; t != trans.end(); t++) { 00430 if (t->is_op_trans(op1)) { 00431 if (op == op1) { 00432 merge_state(t->state, state); 00433 return; 00434 } else if (op.getSym() < op1.getSym()) 00435 break; 00436 } 00437 } 00438 Trans tr(op, arity); 00439 trans.insert(t, tr); t--; 00440 State *state1 = t->state; 00441 *state1 = *state; 00442 if (t1 != t0) { 00443 State *state2 = make_var_state(arity, t0->state); 00444 merge_state(state1, state2); 00445 delete state2; 00446 } 00447 } 00448 00449 static void merge_trans(list<Trans>& trans1, list<Trans>& trans2) 00450 { 00451 Tree x; 00452 Node op(0); 00453 if (trans2.empty()) 00454 ; 00455 else if (trans1.empty()) { 00456 list<Trans> cptrans2 = trans2; 00457 /* append a copy of trans2 to trans1 */ 00458 trans1.splice(trans1.end(), cptrans2); 00459 } else if (trans2.begin()->is_var_trans()) 00460 /* merge a variable transition */ 00461 merge_trans_var(trans1, trans2.begin()->state); 00462 else if (trans2.begin()->is_cst_trans(x)) 00463 /* merge a constant transition */ 00464 merge_trans_cst(trans1, x, trans2.begin()->state); 00465 else if (trans2.begin()->is_op_trans(op)) 00466 /* merge a BDA op transition */ 00467 merge_trans_op(trans1, op, trans2.begin()->arity, trans2.begin()->state); 00468 } 00469 00470 static void merge_state(State *state1, State *state2) 00471 { 00472 merge_rules(state1->rules, state2->rules); 00473 merge_trans(state1->trans, state2->trans); 00474 } 00475 00476 /* Take the rules of a BoxCase expression and return a pointer to the 00477 corresponding TA automaton (interface operation). */ 00478 00479 Automaton *make_pattern_matcher(Tree R) 00480 /* Tree R encodes the rules of a case box expressions as a Tree object, as 00481 follows: 00482 00483 Rules ::= cons Rule (cons Rule ... nil) 00484 Rule ::= cons Lhs Rhs 00485 Lhs ::= cons Pattern (cons Pattern ... nil) 00486 Pattern ::= Tree (parameter pattern) 00487 Rhs ::= Tree 00488 00489 NOTE: The lists of rules and patterns are actually delivered in reverse 00490 order by the parser, so we have to reverse them on the fly. */ 00491 { 00492 Automaton *A = new Automaton; 00493 int n = len(R), r = n; 00494 State *start = new State; 00495 Tree rule, rest; 00496 vector<Tree> rules(n, (Tree)NULL); 00497 vector< vector<Tree> > testpats(n); 00498 while (isCons(R, rule, rest)) { 00499 rules[--r] = rule; 00500 R = rest; 00501 } 00502 for (r = 0; r < n; r++) { 00503 Tree lhs, rhs; 00504 if (isCons(rules[r], lhs, rhs)) { 00505 Tree pat, rest; 00506 int m = len(lhs), i = m; 00507 vector<Tree> pats(len(lhs), (Tree)NULL); 00508 State *state0 = new State, *state = state0; 00509 A->rhs.push_back(rhs); 00510 while (isCons(lhs, pat, rest)) { 00511 pats[--i] = pat; 00512 lhs = rest; 00513 } 00514 testpats[r] = pats; 00515 for (i = 0; i < m; i++) { 00516 Path p; 00517 state = make_state(state, r, pats[i], p); 00518 } 00519 Rule rule(r, NULL); 00520 state->rules.push_back(rule); 00521 merge_state(start, state0); 00522 delete state0; 00523 } 00524 } 00525 A->build(start); 00526 /* Check for shadowed rules. Note that because of potential nonlinearities 00527 it is *not* enough to just check the rule lists of final states and 00528 determine whether they have multiple matched rules. */ 00529 for (r = 0; r < n; r++) { 00530 int s = 0, m = testpats[r].size(); 00531 Tree C; 00532 vector<Tree> E(n, nil); 00533 /* try to match the lhs of rule #r */ 00534 for (int i = 0; i < m; i++) { 00535 s = apply_pattern_matcher(A, s, testpats[r][i], C, E); 00536 if (s < 0) break; 00537 } 00538 if (A->final(s)) { 00539 list<Rule>::const_iterator ru; 00540 for (ru = A->rules(s).begin(); ru != A->rules(s).end(); ru++) 00541 if (!isBoxError(E[ru->r])) 00542 if (ru->r < r) { 00543 /* Lhs of rule #r matched a higher-priority rule, so rule #r may 00544 be shadowed. */ 00545 Tree lhs1, rhs1, lhs2, rhs2; 00546 if (isCons(rules[ru->r], lhs1, rhs1) && isCons(rules[r], lhs2, rhs2)) { 00547 cerr << "WARNING : shadowed pattern-matching rule: " 00548 << boxpp(reverse(lhs2)) << " => " << boxpp(rhs2) << ";" 00549 << " previous rule was: " 00550 << boxpp(reverse(lhs1)) << " => " << boxpp(rhs1) << ";" 00551 << endl; 00552 } else { 00553 cerr << "INTERNAL ERROR : " << __FILE__ << ":" << __LINE__ << endl; 00554 exit(1); 00555 } 00556 } else if (ru->r >= r) 00557 break; 00558 } 00559 } 00560 #ifdef DEBUG 00561 cerr << "automaton " << A << endl << *A << "end automaton" << endl; 00562 #endif 00563 return A; 00564 } 00565 00566 /* Helper type to represent variable substitutions which are recorded during 00567 matching. Each variable is associated with the path pointing at the subterm 00568 of the argument where the substitution of the matched variable is to be 00569 found. */ 00570 00571 struct Assoc { 00572 Tree id; 00573 Path p; 00574 Assoc(Tree _id, const Path& _p) : id(_id), p(_p) {} 00575 }; 00576 typedef list<Assoc> Subst; 00577 00578 /* add all substitutions for a given state */ 00579 00580 static void add_subst(vector<Subst>& subst, Automaton *A, int s) 00581 { 00582 list<Rule> rules = A->rules(s); 00583 list<Rule>::const_iterator r; 00584 for (r = rules.begin(); r != rules.end(); r++) 00585 if (r->id != NULL) 00586 subst[r->r].push_back(Assoc(r->id, r->p)); 00587 } 00588 00589 /* Process a given term tree X starting from state s, modify variable 00590 substitutions accordingly. Returns the resulting state, or -1 if no 00591 match. This does all the grunt work of matching. */ 00592 00593 static int apply_pattern_matcher_internal(Automaton *A, int s, Tree X, 00594 vector<Subst>& subst) 00595 { 00596 /* FIXME: rewrite this non-recursively? */ 00597 if (s >= 0) { 00598 list<Trans>::const_iterator t; 00599 if (A->state[s]->match_num) 00600 /* simplify possible numeric argument on the fly */ 00601 X = simplifyPattern(X); 00602 /* first check for applicable non-variable transitions */ 00603 for (t = A->trans(s).begin(); t != A->trans(s).end(); t++) { 00604 Tree x; 00605 Node op(0), op1(0); 00606 if (t->is_var_trans()) 00607 continue; 00608 else if (t->is_cst_trans(x)) { 00609 if (X==x) { 00610 /* transition on constant */ 00611 #ifdef DEBUG 00612 cerr << "state " << s << ", " << *x << ": goto state " << t->state->s << endl; 00613 #endif 00614 add_subst(subst, A, s); 00615 s = t->state->s; 00616 return s; 00617 } 00618 } else if (t->is_op_trans(op)) { 00619 Tree x0, x1; 00620 if (isBoxPatternOp(X, op1, x0, x1) && op == op1) { 00621 /* transition on operation symbol */ 00622 #ifdef DEBUG 00623 cerr << "state " << s << ", " << op << ": goto state " << t->state->s << endl; 00624 #endif 00625 add_subst(subst, A, s); 00626 s = t->state->s; 00627 if (s >= 0) 00628 s = apply_pattern_matcher_internal(A, s, x0, subst); 00629 if (s >= 0) 00630 s = apply_pattern_matcher_internal(A, s, x1, subst); 00631 return s; 00632 } 00633 } 00634 } 00635 /* check for variable transition (is always first in the list of 00636 transitions) */ 00637 t = A->trans(s).begin(); 00638 if (t->is_var_trans()) { 00639 #ifdef DEBUG 00640 cerr << "state " << s << ", _: goto state " << t->state->s << endl; 00641 #endif 00642 add_subst(subst, A, s); 00643 s = t->state->s; 00644 } else { 00645 #ifdef DEBUG 00646 cerr << "state " << s << ", *** match failed ***" << endl; 00647 #endif 00648 s = -1; 00649 } 00650 } 00651 return s; 00652 } 00653 00654 /* Apply the pattern matcher to a single argument, starting from a given state 00655 (interface operation). Returns the resulting state, modifies the variable 00656 bindings E accordingly, and sets C to the resulting closure if a final 00657 state is reached. Result will be -1 to indicate a matching failure, and C 00658 will be set to nil if no final state has been reached yet. */ 00659 00660 int apply_pattern_matcher(Automaton *A, // automaton 00661 int s, // start state 00662 Tree X, // arg to be matched 00663 Tree& C, // output closure (if any) 00664 vector<Tree>& E) // modified output environments 00665 { 00666 int n = A->n_rules(); 00667 vector<Subst> subst(n, Subst()); 00668 /* perform matching, record variable substitutions */ 00669 #ifdef DEBUG 00670 cerr << "automaton " << A << ", state " << s << ", start match on arg: " << *X << endl; 00671 #endif 00672 s = apply_pattern_matcher_internal(A, s, X, subst); 00673 C = nil; 00674 if (s < 0) 00675 /* failed match */ 00676 return s; 00677 /* process variable substitutions */ 00678 list<Rule>::const_iterator r; 00679 for (r = A->rules(s).begin(); r != A->rules(s).end(); r++) { 00680 // all rules still active in state s 00681 if (!isBoxError(E[r->r])) { // and still viable 00682 Subst::const_iterator assoc; 00683 for (assoc = subst[r->r].begin(); assoc != subst[r->r].end(); assoc++) { 00684 Tree Z, Z1 = subtree(X, 0, assoc->p); 00685 if (searchIdDef(assoc->id, Z, E[r->r])) { 00686 if (Z != Z1) { 00687 /* failed nonlinearity, add to the set of nonviable rules */ 00688 #ifdef DEBUG 00689 cerr << "state " << s << ", rule #" << r->r << ": " << 00690 *assoc->id << " := " << *Z1 << " *** failed *** old value: " << 00691 *Z << endl; 00692 #endif 00693 E[r->r] = boxError(); 00694 } 00695 } else { 00696 /* bind a variable for the current rule */ 00697 #ifdef DEBUG 00698 cerr << "state " << s << ", rule #" << r->r << ": " << 00699 *assoc->id << " := " << *Z1 << endl; 00700 #endif 00701 E[r->r] = pushValueDef(assoc->id, Z1, E[r->r]); 00702 } 00703 } 00704 } 00705 } 00706 if (A->final(s)) { 00707 /* if in a final state then return the right-hand side together with the 00708 corresponding variable environment */ 00709 for (r = A->rules(s).begin(); r != A->rules(s).end(); r++) // all rules matched in state s 00710 if (!isBoxError(E[r->r])) { // and still viable 00711 /* return the rhs of the matched rule */ 00712 C = closure(A->rhs[r->r], nil, nil, E[r->r]); 00713 #ifdef DEBUG 00714 cerr << "state " << s << ", complete match yields rhs #" << r->r << 00715 ": " << *A->rhs[r->r] << endl; 00716 #endif 00717 return s; 00718 } 00719 /* if none of the rules were matched then declare a failed match */ 00720 #ifdef DEBUG 00721 cerr << "state " << s << ", *** match failed ***" << endl; 00722 #endif 00723 return -1; 00724 } 00725 #ifdef DEBUG 00726 cerr << "state " << s << ", successful incomplete match" << endl; 00727 #endif 00728 return s; 00729 }
1.8.0