| /* | |
| * pred.c -- source for predicate detection, manipulation | |
| * | |
| * SOFTWARE RIGHTS | |
| * | |
| * We reserve no LEGAL rights to the Purdue Compiler Construction Tool | |
| * Set (PCCTS) -- PCCTS is in the public domain. An individual or | |
| * company may do whatever they wish with source code distributed with | |
| * PCCTS or the code generated by PCCTS, including the incorporation of | |
| * PCCTS, or its output, into commerical software. | |
| * | |
| * We encourage users to develop software with PCCTS. However, we do ask | |
| * that credit is given to us for developing PCCTS. By "credit", | |
| * we mean that if you incorporate our source code into one of your | |
| * programs (commercial product, research project, or otherwise) that you | |
| * acknowledge this fact somewhere in the documentation, research report, | |
| * etc... If you like PCCTS and have developed a nice tool with the | |
| * output, please mention that you developed it using PCCTS. In | |
| * addition, we ask that this header remain intact in our source code. | |
| * As long as these guidelines are kept, we expect to continue enhancing | |
| * this system and expect to make other tools available as they are | |
| * completed. | |
| * | |
| * ANTLR 1.33 | |
| * Terence Parr | |
| * Parr Research Corporation | |
| * with Purdue University and AHPCRC, University of Minnesota | |
| * 1989-2001 | |
| */ | |
| #include <stdio.h> | |
| #include "pcctscfg.h" | |
| #include "set.h" | |
| #include "syn.h" | |
| #include "hash.h" | |
| #include "generic.h" | |
| #include "dlgdef.h" | |
| #include <ctype.h> | |
| #ifdef __USE_PROTOS | |
| static void complete_context_sets(RuleRefNode *, Predicate *); | |
| static void complete_context_trees(RuleRefNode *, Predicate *); | |
| #else | |
| static void complete_context_sets(); | |
| static void complete_context_trees(); | |
| #endif | |
| char *PRED_AND_LIST = "AND"; | |
| char *PRED_OR_LIST = "OR"; | |
| /* | |
| * In C mode, return the largest constant integer found as the | |
| * sole argument to LATEXT(i). | |
| * | |
| * In C++ mode, return the largest constant integer found as the | |
| * sole argument to LT(i) given that the char before is nonalpha. | |
| */ | |
| int | |
| #ifdef __USE_PROTOS | |
| predicateLookaheadDepth(ActionNode *a) | |
| #else | |
| predicateLookaheadDepth(a) | |
| ActionNode *a; | |
| #endif | |
| { | |
| int max_k=0; | |
| if (a->predEntry != NULL) { | |
| MR_pred_depth(a->predEntry->pred,&max_k); | |
| goto PREDENTRY_EXIT; | |
| } | |
| if ( GenCC ) | |
| { | |
| /* scan for LT(i) */ | |
| int k = 0; | |
| char *p = a->action; | |
| while ( p!=NULL ) | |
| { | |
| p = strstr(p, "LT("); | |
| if ( p!=NULL ) | |
| { | |
| if ( p>=a->action && !isalpha(*(p-1)) ) | |
| { | |
| k = atoi(p+strlen("LT(")); | |
| if ( k>max_k ) max_k=k; | |
| } | |
| p += strlen("LT("); | |
| } | |
| } | |
| } | |
| else { | |
| /* scan for LATEXT(i) */ | |
| int k = 0; | |
| char *p = a->action; | |
| while ( p!=NULL ) | |
| { | |
| p = strstr(p, "LATEXT("); | |
| if ( p!=NULL ) | |
| { | |
| p += strlen("LATEXT("); | |
| k = atoi(p); | |
| if ( k>max_k ) max_k=k; | |
| } | |
| } | |
| } | |
| if (max_k==0) { | |
| max_k = 1; /* MR33 Badly designed if didn't set max_k when CLL_k = 1 */ | |
| if (CLL_k > 1) /* MR27 Don't warn if max(k,ck) == 1 */ | |
| { | |
| if ( !a->frmwarned ) | |
| { | |
| a->frmwarned = 1; | |
| warnFL(eMsg1("predicate: %s missing, bad, or with i=0; assuming i=1", | |
| GenCC?"LT(i)":"LATEXT(i)"), | |
| FileStr[a->file], a->line); | |
| } | |
| } | |
| } | |
| /* MR10 */ if ( max_k > CLL_k) { | |
| /* MR10 */ if ( !a->frmwarned ) | |
| /* MR10 */ { | |
| /* MR10 */ a->frmwarned = 1; | |
| /* MR11 */ errFL(eMsgd2("predicate refers to lookahead token %d. Semantic lookahead is limited to max(k,ck)==%d", | |
| /* MR10 */ max_k,CLL_k), | |
| /* MR10 */ FileStr[a->file],a->line); | |
| /* MR10 */ if (max_k >= OutputLL_k) { | |
| /* MR10 */ if (!GenCC) { | |
| /* MR10 */ errFL(eMsgd(" the lookahead buffer size in C mode is %d token(s) (including the one just recognized)", | |
| /* MR10 */ OutputLL_k), | |
| /* MR10 */ FileStr[a->file],a->line); | |
| /* MR10 */ }; | |
| /* MR10 */ }; | |
| /* MR10 */ }; | |
| /* MR10 */ max_k= CLL_k; | |
| /* MR10 */ }; | |
| PREDENTRY_EXIT: | |
| return max_k; | |
| } | |
| /* Find all predicates in a block of alternatives. DO NOT find predicates | |
| * behind the block because that predicate could depend on things set in | |
| * one of the nonoptional blocks | |
| */ | |
| Predicate * | |
| #ifdef __USE_PROTOS | |
| find_in_aSubBlk( Junction *alt ) | |
| #else | |
| find_in_aSubBlk( alt ) | |
| Junction *alt; | |
| #endif | |
| { | |
| Predicate *a, *head=NULL, *tail=NULL, *root=NULL; | |
| Junction *p = alt; | |
| if (MRhoisting) { | |
| return MR_find_in_aSubBlk(alt); | |
| }; | |
| for (; p!=NULL; p=(Junction *)p->p2) | |
| { | |
| /* ignore empty alts */ | |
| if ( p->p1->ntype != nJunction || | |
| ((Junction *)p->p1)->jtype != EndBlk ) | |
| { | |
| a = find_predicates(p->p1); /* get preds for this alt */ | |
| if ( a==NULL ) continue; | |
| /* make an OR list of predicates */ | |
| if ( head==NULL ) | |
| { | |
| root = new_pred(); | |
| root->expr = PRED_OR_LIST; | |
| head = tail = a; | |
| root->down = head; | |
| } | |
| else { | |
| tail->right = a; | |
| a->left = tail; | |
| a->up = tail->up; | |
| tail = a; | |
| } | |
| } | |
| } | |
| /* if just one pred, remove OR root */ | |
| if ( root!=NULL && root->down->right == NULL ) | |
| { | |
| Predicate *d = root->down; | |
| free( (char *) root); | |
| return d; | |
| } | |
| return root; | |
| } | |
| Predicate * | |
| #ifdef __USE_PROTOS | |
| find_in_aOptBlk( Junction *alt ) | |
| #else | |
| find_in_aOptBlk( alt ) | |
| Junction *alt; | |
| #endif | |
| { | |
| return find_in_aSubBlk( alt ); | |
| } | |
| Predicate * | |
| #ifdef __USE_PROTOS | |
| find_in_aLoopBegin( Junction *alt ) | |
| #else | |
| find_in_aLoopBegin( alt ) | |
| Junction *alt; | |
| #endif | |
| { | |
| return find_in_aSubBlk( (Junction *) alt->p1 ); /* get preds in alts */ | |
| } | |
| Predicate * | |
| #ifdef __USE_PROTOS | |
| find_in_aPlusBlk( Junction *alt ) | |
| #else | |
| find_in_aPlusBlk( alt ) | |
| Junction *alt; | |
| #endif | |
| { | |
| require(alt!=NULL&&alt->p2!=NULL, "invalid aPlusBlk"); | |
| return find_in_aSubBlk( alt ); | |
| } | |
| /* Look for a predicate; | |
| * | |
| * Do not pass anything but Junction nodes; no Actions, Tokens, RuleRefs. | |
| * This means that a "hoisting distance" of zero is the only distance | |
| * allowable. Init actions are ignored. | |
| * | |
| * WARNING: | |
| * Assumes no (..)? block after predicate for the moment. | |
| * Does not check to see if pred is in production that can generate | |
| * a sequence contained in the set of ambiguous tuples. | |
| * | |
| * Return the predicate found if any. | |
| */ | |
| Predicate * | |
| #ifdef __USE_PROTOS | |
| find_predicates( Node *alt ) | |
| #else | |
| find_predicates( alt ) | |
| Node *alt; | |
| #endif | |
| { | |
| #ifdef DBG_PRED | |
| Junction *j; | |
| RuleRefNode *r; | |
| TokNode *t; | |
| #endif | |
| Predicate *pred; | |
| if ( alt==NULL ) return NULL; | |
| #ifdef DBG_PRED | |
| switch ( alt->ntype ) | |
| { | |
| case nJunction : | |
| j = (Junction *) alt; | |
| fprintf(stderr, "Junction(in %s)", j->rname); | |
| switch ( j->jtype ) | |
| { | |
| case aSubBlk : | |
| fprintf(stderr,"aSubBlk\n"); | |
| break; | |
| case aOptBlk : | |
| fprintf(stderr,"aOptBlk\n"); | |
| break; | |
| case aLoopBegin : | |
| fprintf(stderr,"aLoopBeginBlk\n"); | |
| break; | |
| case aLoopBlk : | |
| fprintf(stderr,"aLoopBlk\n"); | |
| break; | |
| case aPlusBlk : | |
| fprintf(stderr,"aPlusBlk\n"); | |
| break; | |
| case EndBlk : | |
| fprintf(stderr,"EndBlk\n"); | |
| break; | |
| case RuleBlk : | |
| fprintf(stderr,"RuleBlk\n"); | |
| break; | |
| case Generic : | |
| fprintf(stderr,"Generic\n"); | |
| break; | |
| case EndRule : | |
| fprintf(stderr,"EndRule\n"); | |
| break; | |
| } | |
| break; | |
| case nRuleRef : | |
| r = (RuleRefNode *) alt; | |
| fprintf(stderr, "RuleRef(in %s)\n", r->rname); | |
| break; | |
| case nToken : | |
| t = (TokNode *) alt; | |
| fprintf(stderr, "TokenNode(in %s)%s\n", t->rname, TokenString(t->token)); | |
| break; | |
| case nAction : | |
| fprintf(stderr, "Action\n"); | |
| break; | |
| } | |
| #endif | |
| switch ( alt->ntype ) | |
| { | |
| case nJunction : | |
| { | |
| Predicate *a, *b; | |
| Junction *p = (Junction *) alt; | |
| /* lock nodes */ | |
| if ( p->jtype==aLoopBlk || p->jtype==RuleBlk || | |
| p->jtype==aPlusBlk || p->jtype==EndRule ) | |
| { | |
| require(p->pred_lock!=NULL, "rJunc: lock array is NULL"); | |
| if ( p->pred_lock[1] ) | |
| { | |
| return NULL; | |
| } | |
| p->pred_lock[1] = TRUE; | |
| } | |
| switch ( p->jtype ) | |
| { | |
| case aSubBlk : | |
| a = find_in_aSubBlk(p); | |
| return a; /* nothing is visible past this guy */ | |
| case aOptBlk : | |
| a = find_in_aOptBlk(p); | |
| return a; | |
| case aLoopBegin : | |
| a = find_in_aLoopBegin(p); | |
| return a; | |
| case aLoopBlk : | |
| a = find_in_aSubBlk(p); | |
| p->pred_lock[1] = FALSE; | |
| return a; | |
| case aPlusBlk : | |
| a = find_in_aPlusBlk(p); | |
| p->pred_lock[1] = FALSE; | |
| return a; /* nothing is visible past this guy */ | |
| case RuleBlk : | |
| a = find_predicates(p->p1); | |
| p->pred_lock[1] = FALSE; | |
| return a; | |
| case Generic : | |
| a = find_predicates(p->p1); | |
| b = find_predicates(p->p2); | |
| if ( p->pred_lock!=NULL ) p->pred_lock[1] = FALSE; | |
| if ( a==NULL ) return b; | |
| if ( b==NULL ) return a; | |
| /* otherwise OR the two preds together */ | |
| { | |
| fatal_internal("hit unknown situation during predicate hoisting"); | |
| } | |
| case EndBlk : | |
| case EndRule : /* Find no predicates after a rule ref */ | |
| return NULL; | |
| default: | |
| fatal_internal("this cannot be printed\n"); | |
| break; | |
| } | |
| } | |
| case nAction : | |
| { | |
| ActionNode *p = (ActionNode *) alt; | |
| if ( p->noHoist) return NULL; /* MR12c */ | |
| if ( p->init_action ) return find_predicates(p->next); | |
| if ( p->is_predicate ) | |
| { | |
| Tree *t=NULL; | |
| #ifdef DBG_PRED | |
| fprintf(stderr, "predicate: <<%s>>?\n", p->action); | |
| #endif | |
| if ( p->guardpred!=NULL ) | |
| { | |
| pred = predicate_dup(p->guardpred); | |
| MR_guardPred_plainSet(p,pred); /* MR12c */ | |
| } | |
| else | |
| { | |
| pred = new_pred(); | |
| pred->k = predicateLookaheadDepth(p); | |
| pred->source = p; | |
| pred->expr = p->action; | |
| if ( HoistPredicateContext && pred->k > 1 ) | |
| { | |
| /* MR30 No need to use first_item_is_guess_block_extra | |
| since we know this is an action, not a (...)* or | |
| (...)+ block. | |
| */ | |
| if ( first_item_is_guess_block((Junction *)p->next) ) | |
| { | |
| warnFL("cannot compute context of predicate in front of (..)? block", | |
| FileStr[p->file], p->line); | |
| } | |
| else | |
| { | |
| ConstrainSearch = 0; | |
| /* MR11 */ if (p->ampersandPred != NULL) { | |
| /* MR11 */ TRAV(p, | |
| /* MR11 */ pred->k, | |
| /* MR11 */ &(pred->completionTree), t); | |
| /* MR11 */ } else { | |
| TRAV(p->next, | |
| pred->k, | |
| &(pred->completionTree), t); | |
| }; | |
| pred->tcontext = t; | |
| MR_check_pred_too_long(pred,pred->completionTree); | |
| #ifdef DBG_PRED | |
| fprintf(stderr, "LL(%d) context:", pred->k); | |
| preorder(t); | |
| fprintf(stderr, "\n"); | |
| #endif | |
| } | |
| } | |
| else if ( HoistPredicateContext && pred->k == 1 ) | |
| { | |
| pred->scontext[1] = empty; | |
| /* MR30 No need to use first_item_is_guess_block_extra | |
| since we know this is an action. | |
| */ | |
| if ( first_item_is_guess_block((Junction *)p->next) ) | |
| { | |
| warnFL("cannot compute context of predicate in front of (..)? block", | |
| FileStr[p->file], p->line); | |
| } | |
| else | |
| { | |
| REACH((Junction *)p->next, | |
| 1, | |
| &(pred->completionSet), | |
| pred->scontext[1]); | |
| MR_check_pred_too_long(pred,pred->completionSet); | |
| #ifdef DBG_PRED | |
| fprintf(stderr, "LL(1) context:"); | |
| s_fprT(stderr, pred->scontext[1]); | |
| fprintf(stderr, "\n"); | |
| #endif | |
| } | |
| } | |
| } | |
| { | |
| Predicate *d = find_predicates(p->next); | |
| Predicate *root; | |
| /* Warning: Doesn't seem like the up pointers will all be set correctly; | |
| * TJP: that's ok, we're not using them now. | |
| */ | |
| if ( d!=NULL ) | |
| { | |
| root = new_pred(); | |
| root->expr = PRED_AND_LIST; | |
| root->down = pred; | |
| pred->right = d; | |
| pred->up = root; | |
| d->left = pred; | |
| d->up = pred->up; | |
| return root; | |
| } | |
| } | |
| return pred; | |
| } | |
| return NULL; | |
| } | |
| case nRuleRef : | |
| { | |
| Predicate *a; | |
| RuleRefNode *p = (RuleRefNode *) alt; | |
| Junction *r; | |
| Junction *save_MR_RuleBlkWithHalt; | |
| RuleEntry *q = (RuleEntry *) hash_get(Rname, p->text); | |
| if ( q == NULL ) | |
| { | |
| warnFL( eMsg1("rule %s not defined",p->text), FileStr[p->file], p->line ); | |
| return NULL; | |
| } | |
| r = RulePtr[q->rulenum]; | |
| if ( r->pred_lock[1] ) | |
| { | |
| /* infinite left-recursion; ignore 'cause LL sup 1 (k) analysis | |
| * must have seen it earlier. | |
| */ | |
| return NULL; | |
| } | |
| /* MR10 There should only be one halt set at a time. */ | |
| /* MR10 Life would have been easier with a global variable */ | |
| /* MR10 (at least for this particular need) */ | |
| /* MR10 Unset the old one and set the new one, later undo. */ | |
| require(r->end->halt == FALSE,"should only have one halt at a time"); | |
| /* MR10 */ require(MR_RuleBlkWithHalt == NULL || | |
| /* MR10 */ (MR_RuleBlkWithHalt->jtype == RuleBlk && MR_RuleBlkWithHalt->end->halt == TRUE), | |
| /* MR10 */ "RuleBlkWithHalt->end not RuleBlk or does not have halt set"); | |
| /* MR10 */ if (MR_RuleBlkWithHalt != NULL) { | |
| /* MR10 */ MR_RuleBlkWithHalt->end->halt=FALSE; | |
| /* MR10 */ }; | |
| /*** fprintf(stderr,"\nSetting halt on junction #%d\n",r->end->seq); ***/ | |
| require(r->end->halt == FALSE,"rule->end->halt already set"); | |
| save_MR_RuleBlkWithHalt=MR_RuleBlkWithHalt; | |
| /* MR10 */ MR_pointerStackPush(&MR_RuleBlkWithHaltStack,MR_RuleBlkWithHalt); | |
| /* MR10 */ MR_pointerStackPush(&MR_PredRuleRefStack,p); | |
| r->end->halt = TRUE; | |
| /* MR10 */ MR_RuleBlkWithHalt=r; | |
| a = find_predicates((Node *)r); | |
| require(r->end->halt == TRUE,"rule->end->halt not set"); | |
| r->end->halt = FALSE; | |
| /* MR10 */ MR_pointerStackPop(&MR_PredRuleRefStack); | |
| /* MR10 */ MR_RuleBlkWithHalt=(Junction *) MR_pointerStackPop(&MR_RuleBlkWithHaltStack); | |
| require (MR_RuleBlkWithHalt==save_MR_RuleBlkWithHalt, | |
| "RuleBlkWithHaltStack not consistent"); | |
| /* MR10 */ require(MR_RuleBlkWithHalt == NULL || | |
| /* MR10 */ (MR_RuleBlkWithHalt->jtype == RuleBlk && MR_RuleBlkWithHalt->end->halt == FALSE), | |
| /* MR10 */ "RuleBlkWithHalt->end not RuleBlk or has no halt set"); | |
| /* MR10 */ if (MR_RuleBlkWithHalt != NULL) { | |
| /* MR10 */ MR_RuleBlkWithHalt->end->halt=TRUE; | |
| /* MR10 */ }; | |
| /*** fprintf(stderr,"\nRestoring halt on junction #%d\n",r->end->seq); ***/ | |
| if ( a==NULL ) return NULL; | |
| /* attempt to compute the "local" FOLLOW just like in normal lookahead | |
| * computation if needed | |
| */ | |
| complete_context_sets(p,a); | |
| complete_context_trees(p,a); | |
| /* MR10 */ MR_cleanup_pred_trees(a); | |
| return a; | |
| } | |
| case nToken : | |
| break; | |
| } | |
| return NULL; | |
| } | |
| #ifdef __USE_PROTOS | |
| Predicate *MR_find_predicates_and_supp(Node *alt) | |
| #else | |
| Predicate *MR_find_predicates_and_supp(alt) | |
| Node *alt; | |
| #endif | |
| { | |
| Predicate *p; | |
| p=find_predicates(alt); | |
| p=MR_suppressK(alt,p); | |
| return p; | |
| } | |
| Predicate * | |
| #ifdef __USE_PROTOS | |
| new_pred( void ) | |
| #else | |
| new_pred( ) | |
| #endif | |
| { | |
| Predicate *p = (Predicate *) calloc(1,sizeof(Predicate)); /* MR10 */ | |
| require(p!=NULL, "new_pred: cannot alloc predicate"); | |
| p->scontext[0]=empty; | |
| p->scontext[1]=empty; | |
| p->completionTree=empty; | |
| p->completionSet=empty; | |
| p->plainSet=empty; | |
| return p; | |
| } | |
| static void | |
| #ifdef __USE_PROTOS | |
| complete_context_sets( RuleRefNode *p, Predicate *a ) | |
| #else | |
| complete_context_sets( p, a ) | |
| RuleRefNode *p; | |
| Predicate *a; | |
| #endif | |
| { | |
| set rk2, b; | |
| int k2; | |
| #ifdef DBG_PRED | |
| fprintf(stderr, "enter complete_context_sets\n"); | |
| #endif | |
| for (; a!=NULL; a=a->right) | |
| { | |
| if ( a->expr == PRED_AND_LIST || a->expr == PRED_OR_LIST ) | |
| { | |
| complete_context_sets(p,a->down); | |
| continue; | |
| } | |
| rk2 = b = empty; | |
| while ( !set_nil(a->completionSet) ) | |
| { | |
| k2 = set_int(a->completionSet); | |
| set_rm(k2, a->completionSet); | |
| REACH(p->next, k2, &rk2, b); | |
| set_orin(&(a->scontext[1]), b); | |
| set_free(b); | |
| } | |
| set_orin(&(a->completionSet), rk2);/* remember what we couldn't do */ | |
| set_free(rk2); | |
| #ifdef DBG_PRED | |
| fprintf(stderr, "LL(1) context for %s(addr 0x%x) after ruleref:", a->expr, a); | |
| s_fprT(stderr, a->scontext[1]); | |
| fprintf(stderr, "\n"); | |
| #endif | |
| /* complete_context_sets(p, a->down);*/ | |
| } | |
| #ifdef DBG_PRED | |
| fprintf(stderr, "exit complete_context_sets\n"); | |
| #endif | |
| } | |
| static void | |
| #ifdef __USE_PROTOS | |
| complete_context_trees( RuleRefNode *p, Predicate *a ) | |
| #else | |
| complete_context_trees( p, a ) | |
| RuleRefNode *p; | |
| Predicate *a; | |
| #endif | |
| { | |
| set rk2; | |
| int k2; | |
| Tree *u; | |
| #ifdef DBG_PRED | |
| fprintf(stderr, "enter complete_context_trees\n"); | |
| #endif | |
| for (; a!=NULL; a=a->right) | |
| { | |
| if ( a->expr == PRED_AND_LIST || a->expr == PRED_OR_LIST ) | |
| { | |
| complete_context_trees(p, a->down); | |
| continue; | |
| } | |
| rk2 = empty; | |
| /* any k left to do? if so, link onto tree */ | |
| while ( !set_nil(a->completionTree) ) | |
| { | |
| k2 = set_int(a->completionTree); | |
| set_rm(k2, a->completionTree); | |
| u = NULL; | |
| TRAV(p->next, k2, &rk2, u); | |
| /* any subtrees missing k2 tokens, add u onto end */ | |
| a->tcontext = tlink(a->tcontext, u, k2); | |
| Tfree(u); /* MR10 */ | |
| } | |
| set_orin(&(a->completionTree), rk2);/* remember what we couldn't do */ | |
| set_free(rk2); | |
| #ifdef DBG_PRED | |
| fprintf(stderr, "LL(i<%d) context after ruleref:", LL_k); | |
| preorder(a->tcontext); | |
| fprintf(stderr, "\n"); | |
| #endif | |
| /* complete_context_trees(p, a->down);*/ | |
| } | |
| #ifdef DBG_PRED | |
| fprintf(stderr, "exit complete_context_trees\n"); | |
| #endif | |
| } | |
| /* Walk a list of predicates and return the set of all tokens in scontext[1]'s */ | |
| set | |
| #ifdef __USE_PROTOS | |
| covered_set( Predicate *p ) | |
| #else | |
| covered_set( p ) | |
| Predicate *p; | |
| #endif | |
| { | |
| set a; | |
| a = empty; | |
| for (; p!=NULL; p=p->right) | |
| { | |
| if ( p->expr == PRED_AND_LIST || p->expr == PRED_OR_LIST ) | |
| { | |
| set_orin(&a, covered_set(p->down)); | |
| continue; | |
| } | |
| set_orin(&a, p->scontext[1]); | |
| set_orin(&a, covered_set(p->down)); | |
| } | |
| return a; | |
| } | |
| /* MR10 predicate_free() | |
| MR10 Don't free the leaf nodes since they are part of the action node | |
| */ | |
| #ifdef __USE_PROTOS | |
| void predicate_free(Predicate *p) | |
| #else | |
| void predicate_free(p) | |
| Predicate *p; | |
| #endif | |
| { | |
| if (p == NULL) return; | |
| predicate_free(p->right); | |
| predicate_free(p->down); | |
| if (p->cloned || | |
| p->source == NULL || | |
| p->source->guardpred == NULL || | |
| p->expr == PRED_AND_LIST || | |
| p->expr == PRED_OR_LIST) { | |
| set_free(p->scontext[1]); | |
| set_free(p->completionSet); | |
| set_free(p->completionTree); | |
| set_free(p->plainSet); | |
| Tfree(p->tcontext); | |
| free( (char *) p); | |
| } else { | |
| p->right=NULL; | |
| p->down=NULL; /* MR13 *** debug */ | |
| }; | |
| } | |
| /* MR10 predicate_dup() */ | |
| #ifdef __USE_PROTOS | |
| Predicate * predicate_dup_xxx(Predicate *p,int contextToo) | |
| #else | |
| Predicate * predicate_dup_xxx(p,contextToo) | |
| Predicate *p; | |
| int contextToo; | |
| #endif | |
| { | |
| Predicate *q; | |
| if (p == NULL) return NULL; | |
| q=new_pred(); | |
| q->down=predicate_dup(p->down); | |
| q->right=predicate_dup(p->right); | |
| /* | |
| don't replicate expr - it is read-only | |
| and address comparison is used to look | |
| for identical predicates. | |
| */ | |
| q->expr=p->expr; | |
| q->k=p->k; | |
| q->source=p->source; | |
| q->cloned=1; | |
| q->ampersandStyle=p->ampersandStyle; | |
| q->inverted=p->inverted; | |
| q->predEntry=p->predEntry; | |
| q->plainSet=set_dup(p->plainSet); | |
| if (contextToo) { | |
| q->tcontext=tdup(p->tcontext); | |
| q->scontext[0]=set_dup(p->scontext[0]); | |
| q->scontext[1]=set_dup(p->scontext[1]); | |
| q->completionTree=set_dup(p->completionTree); | |
| q->completionSet=set_dup(p->completionSet); | |
| }; | |
| /* don't need to dup "redundant" */ | |
| return q; | |
| } | |
| #ifdef __USE_PROTOS | |
| Predicate * predicate_dup_without_context(Predicate *p) | |
| #else | |
| Predicate * predicate_dup_without_context(p) | |
| Predicate *p; | |
| #endif | |
| { | |
| return predicate_dup_xxx(p,0); | |
| } | |
| #ifdef __USE_PROTOS | |
| Predicate * predicate_dup(Predicate *p) | |
| #else | |
| Predicate * predicate_dup(p) | |
| Predicate *p; | |
| #endif | |
| { | |
| return predicate_dup_xxx(p,1); | |
| } | |