The Machine Perception Toolbox

[Introduction]- [News]- [Download]- [Screenshots]- [Manual (pdf)]- [Forums]- [API Reference]- [Repository ]

 

Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

rules.c

Go to the documentation of this file.
00001 /*
00002  * Copyright 1993, 1995 Christopher Seiwald.
00003  *
00004  * This file is part of Jam - see jam.c for Copyright information.
00005  */
00006 
00007 # include "jam.h"
00008 # include "lists.h"
00009 # include "parse.h"
00010 # include "variable.h"
00011 # include "rules.h"
00012 # include "newstr.h"
00013 # include "hash.h"
00014 # include "modules.h"
00015 # include "search.h"
00016 # include "lists.h"
00017 # include "pathsys.h"
00018 # include "timestamp.h"
00019 
00020 /*  This file is ALSO:
00021  *  (C) Copyright David Abrahams 2001. Permission to copy, use,
00022  *  modify, sell and distribute this software is granted provided this
00023  *  copyright notice appears in all copies. This software is provided
00024  *  "as is" without express or implied warranty, and with no claim as
00025  *  to its suitability for any purpose.
00026  */
00027 
00028 /*
00029  * rules.c - access to RULEs, TARGETs, and ACTIONs
00030  *
00031  * External routines:
00032  *
00033  *    bindrule() - return pointer to RULE, creating it if necessary
00034  *    bindtarget() - return pointer to TARGET, creating it if necessary
00035  *    touchtarget() - mark a target to simulate being new
00036  *    targetlist() - turn list of target names into a TARGET chain
00037  *    targetentry() - add a TARGET to a chain of TARGETS
00038  *    actionlist() - append to an ACTION chain
00039  *    addsettings() - add a deferred "set" command to a target
00040 #ifndef OPT_FIX_TARGET_VARIABLES_EXT
00041  *    usesettings() - set all target specific variables
00042 #endif
00043  *    pushsettings() - set all target specific variables
00044  *    popsettings() - reset target specific variables to their pre-push values
00045  *    freesettings() - delete a settings list
00046  *    donerules() - free RULE and TARGET tables
00047  *
00048  * 04/12/94 (seiwald) - actionlist() now just appends a single action.
00049  * 08/23/94 (seiwald) - Support for '+=' (append to variable)
00050  */
00051 
00052 static void set_rule_actions( RULE* rule, rule_actions* actions );
00053 static void set_rule_body( RULE* rule, argument_list* args, PARSE* procedure );
00054 static struct hash *targethash = 0;
00055 
00056 typedef struct _located_target LOCATED_TARGET ;
00057 
00058 struct _located_target {
00059     char* file_name;
00060     TARGET* target;
00061 };
00062 static struct hash *located_targets = 0;
00063 
00064 
00065 
00066 
00067 /*
00068  * enter_rule() - return pointer to RULE, creating it if necessary in
00069  * target_module.
00070  */
00071 static RULE *
00072 enter_rule( char *rulename, module_t *target_module )
00073 {
00074     RULE rule, *r = &rule;
00075 
00076     r->name = rulename;
00077 
00078     if ( hashenter( demand_rules( target_module ), (HASHDATA **)&r ) )
00079     {
00080         r->name = newstr( rulename );   /* never freed */
00081         r->procedure = (PARSE *)0;
00082         r->module = 0;
00083         r->actions = 0;
00084         r->arguments = 0;
00085         r->exported = 0;
00086         r->module = target_module;
00087     }
00088     return r;
00089 }
00090 
00091 /*
00092  * define_rule() - return pointer to RULE, creating it if necessary in
00093  * target_module. Prepare it to accept a body or action originating in
00094  * src_module.
00095  */
00096 static RULE *
00097 define_rule( module_t *src_module, char *rulename, module_t *target_module )
00098 {
00099     RULE *r = enter_rule( rulename, target_module );
00100 
00101     if ( r->module != src_module ) /* if the rule was imported from elsewhere, clear it now */
00102     {
00103         set_rule_body( r, 0, 0 ); 
00104         set_rule_actions( r, 0 );
00105         r->module = src_module; /* r will be executed in the source module */
00106     }
00107 
00108     return r;
00109 }
00110 
00111 void
00112 rule_free( RULE* r )
00113 {
00114     freestr( r->name );
00115     r->name = "";
00116     parse_free( r->procedure );
00117     r->procedure = 0;
00118         if ( r->arguments )
00119             args_free( r->arguments );
00120     r->arguments = 0;
00121     if ( r->actions )
00122                 actions_free( r->actions );
00123     r->actions = 0;
00124 }
00125 
00126 /*
00127  * bindtarget() - return pointer to TARGET, creating it if necessary
00128  */
00129 
00130 TARGET *
00131 bindtarget( const char *targetname )
00132 {
00133         TARGET target, *t = ⌖
00134 
00135         if( !targethash )
00136             targethash = hashinit( sizeof( TARGET ), "targets" );
00137 
00138     /* Perforce added const everywhere. No time to merge that change. */
00139         t->name = (char*)targetname;
00140 
00141         if( hashenter( targethash, (HASHDATA **)&t ) )
00142         {
00143             memset( (char *)t, '\0', sizeof( *t ) );
00144             t->name = newstr( (char*)targetname );      /* never freed */
00145             t->boundname = t->name;             /* default for T_FLAG_NOTFILE */
00146         }
00147 
00148         return t;
00149 }
00150 
00151 
00152 static void bind_explicitly_located_target(void* xtarget, void* data)
00153 {
00154     TARGET* t = (TARGET*)xtarget;
00155     if (! (t->flags & T_FLAG_NOTFILE) )
00156     {
00157         /* Check if there's a setting for LOCATE */
00158         SETTINGS* s = t->settings;
00159         for(; s ; s = s->next)
00160         {            
00161             if (strcmp(s->symbol, "LOCATE") == 0) 
00162             {
00163                 pushsettings(t->settings);
00164                 /* We're binding a target with explicit LOCATE. So
00165                    third argument is of now use: nothing will be returned
00166                    through it. */
00167                 t->boundname = search( t->name, &t->time, 0 );
00168                 popsettings(t->settings);
00169                 break;
00170             }
00171         }
00172     }
00173 }
00174 
00175 void bind_explicitly_located_targets()
00176 {
00177     if (targethash)
00178         hashenumerate(targethash, bind_explicitly_located_target, (void*)0);
00179 }
00180 
00181 /* TODO: this is probably not a good idea to use functions in other modules like
00182   that. */
00183 void call_bind_rule(char* target, char* boundname);
00184 
00185 TARGET* search_for_target ( char * name, LIST* search_path )
00186 {
00187     PATHNAME f[1];
00188     string buf[1];
00189     LOCATED_TARGET lt, *lta = <
00190     time_t time;
00191     int found = 0;
00192     TARGET* result;
00193 
00194     string_new( buf );
00195 
00196         path_parse( name, f );
00197 
00198     f->f_grist.ptr = 0;
00199     f->f_grist.len = 0;
00200 
00201     while( search_path )
00202     {
00203         f->f_root.ptr = search_path->string;
00204         f->f_root.len = strlen( search_path->string );
00205 
00206         string_truncate( buf, 0 );
00207         path_build( f, buf, 1 );
00208 
00209         lt.file_name = buf->value ;
00210 
00211         if (! located_targets )
00212             located_targets = hashinit( sizeof(LOCATED_TARGET),
00213                                         "located targets" );
00214 
00215 
00216         if ( hashcheck( located_targets, (HASHDATA **)&lta ) )
00217         {
00218             return lta->target;
00219         }
00220 
00221         timestamp( buf->value, &time );
00222         if (time)
00223         {
00224             found = 1;
00225             break;
00226         }
00227 
00228         search_path = list_next( search_path );
00229     }
00230 
00231     if ( ! found )
00232     {
00233         f->f_root.ptr = 0;
00234         f->f_root.len = 0;
00235 
00236         string_truncate( buf, 0 );
00237         path_build( f, buf, 1 );
00238 
00239         timestamp( buf->value, &time );        
00240     }
00241 
00242     result = bindtarget( name );
00243     result->boundname = newstr( buf->value );
00244     result->time = time;
00245     result->binding = time ? T_BIND_EXISTS : T_BIND_MISSING;
00246 
00247     call_bind_rule( result->name, result->boundname );
00248     
00249     string_free( buf );
00250 
00251     return result;
00252 
00253 }
00254 
00255 /*
00256  * copytarget() - make a new target with the old target's name
00257  *
00258  * Not entered into hash table -- for internal nodes.
00259  */
00260 
00261 TARGET *
00262 copytarget( const TARGET *ot )
00263 {
00264         TARGET *t;
00265 
00266         t = (TARGET *)malloc( sizeof( *t ) );
00267         memset( (char *)t, '\0', sizeof( *t ) );
00268         t->name = copystr( ot->name );
00269         t->boundname = t->name;
00270 
00271         t->flags |= T_FLAG_NOTFILE | T_FLAG_INTERNAL;
00272 
00273         return t;
00274 }
00275 
00276 /*
00277  * touchtarget() - mark a target to simulate being new
00278  */
00279 
00280 void
00281 touchtarget( char *t )
00282 {
00283         bindtarget( t )->flags |= T_FLAG_TOUCHED;
00284 }
00285 
00286 /*
00287  * targetlist() - turn list of target names into a TARGET chain
00288  *
00289  * Inputs:
00290  *      chain   existing TARGETS to append to
00291  *      targets list of target names
00292  */
00293 
00294 TARGETS *
00295 targetlist( 
00296         TARGETS *chain,
00297         LIST    *targets )
00298 {
00299         for( ; targets; targets = list_next( targets ) )
00300             chain = targetentry( chain, bindtarget( targets->string ) );
00301 
00302         return chain;
00303 }
00304 
00305 /*
00306  * targetentry() - add a TARGET to a chain of TARGETS
00307  *
00308  * Inputs:
00309  *      chain   exisitng TARGETS to append to
00310  *      target  new target to append
00311  */
00312 
00313 TARGETS *
00314 targetentry( 
00315         TARGETS *chain,
00316         TARGET  *target )
00317 {
00318         TARGETS *c;
00319 
00320         c = (TARGETS *)malloc( sizeof( TARGETS ) );
00321         c->target = target;
00322 
00323         if( !chain ) chain = c;
00324         else chain->tail->next = c;
00325         chain->tail = c;
00326         c->next = 0;
00327 
00328         return chain;
00329 }
00330 
00331 /*
00332  * targetchain() - append two TARGET chains
00333  *
00334  * Inputs:
00335  *      chain   exisitng TARGETS to append to
00336  *      target  new target to append
00337  */
00338 
00339 TARGETS *
00340 targetchain( 
00341         TARGETS *chain,
00342         TARGETS *targets )
00343 {
00344         TARGETS *c;
00345 
00346         if( !targets )
00347             return chain;
00348         else if( !chain )
00349             return targets;
00350 
00351         chain->tail->next = targets;
00352         chain->tail = targets->tail;
00353 
00354         return chain;
00355 }
00356 
00357 /*
00358  * actionlist() - append to an ACTION chain
00359  */
00360 
00361 ACTIONS *
00362 actionlist(
00363         ACTIONS *chain,
00364         ACTION  *action )
00365 {
00366         ACTIONS *actions = (ACTIONS *)malloc( sizeof( ACTIONS ) );
00367 
00368         actions->action = action;
00369 
00370         if( !chain ) chain = actions;
00371         else chain->tail->next = actions;
00372         chain->tail = actions;
00373         actions->next = 0;
00374 
00375         return chain;
00376 }
00377 
00378 static SETTINGS* settings_freelist;
00379 
00380 /*
00381  * addsettings() - add a deferred "set" command to a target
00382  *
00383  * Adds a variable setting (varname=list) onto a chain of settings
00384  * for a particular target.  Replaces the previous previous value,
00385  * if any, unless 'append' says to append the new list onto the old.
00386  * Returns the head of the chain of settings.
00387  */
00388 
00389 SETTINGS *
00390 addsettings(
00391         SETTINGS *head,
00392         int     append,
00393         char    *symbol,
00394         LIST    *value )
00395 {
00396         SETTINGS *v;
00397         
00398         /* Look for previous setting */
00399 
00400         for( v = head; v; v = v->next )
00401             if( !strcmp( v->symbol, symbol ) )
00402                 break;
00403 
00404         /* If not previously set, alloc a new. */
00405         /* If appending, do so. */
00406         /* Else free old and set new. */
00407 
00408         if( !v )
00409         {
00410         v = settings_freelist;
00411         
00412         if ( v )
00413             settings_freelist = v->next;
00414         else
00415             v = (SETTINGS *)malloc( sizeof( *v ) );
00416         
00417             v->symbol = newstr( symbol );
00418             v->value = value;
00419             v->next = head;
00420             head = v;
00421         }
00422         else if( append )
00423         {
00424             v->value = list_append( v->value, value );
00425         }
00426         else
00427         {
00428             list_free( v->value );
00429             v->value = value;
00430         } 
00431 
00432         /* Return (new) head of list. */
00433 
00434         return head;
00435 }
00436 
00437 /*
00438  * pushsettings() - set all target specific variables
00439  */
00440 
00441 void
00442 pushsettings( SETTINGS *v )
00443 {
00444         for( ; v; v = v->next )
00445             v->value = var_swap( v->symbol, v->value );
00446 }
00447 
00448 /*
00449  * popsettings() - reset target specific variables to their pre-push values
00450  */
00451 
00452 void
00453 popsettings( SETTINGS *v )
00454 {
00455         pushsettings( v );      /* just swap again */
00456 }
00457 
00458 /*
00459  * copysettings() - duplicate a settings list, returning the new copy
00460  */
00461 SETTINGS*
00462 copysettings( SETTINGS *head )
00463 {
00464     SETTINGS *copy = 0, *v;
00465 
00466     for (v = head; v; v = v->next)
00467         copy = addsettings(copy, 0, v->symbol, list_copy(0, v->value));
00468 
00469     return copy;
00470 }
00471 
00472 /*
00473  *    freetargets() - delete a targets list
00474  */
00475 void freetargets( TARGETS *chain )
00476 {
00477     while( chain )
00478     {
00479         TARGETS* n = chain->next;
00480         free( chain );
00481         chain = n;
00482     }
00483 }
00484 
00485 /*
00486  *    freeactions() - delete an action list
00487  */
00488 void freeactions( ACTIONS *chain )
00489 {
00490     while( chain )
00491     {
00492         ACTIONS* n = chain->next;
00493         free( chain );
00494         chain = n;
00495     }
00496 }
00497 
00498 
00499 /*
00500  *    freesettings() - delete a settings list
00501  */
00502 
00503 void
00504 freesettings( SETTINGS *v )
00505 {
00506         while( v )
00507         {
00508             SETTINGS *n = v->next;
00509 
00510             freestr( v->symbol );
00511             list_free( v->value );
00512         v->next = settings_freelist;
00513         settings_freelist = v;
00514 
00515             v = n;
00516         }
00517 }
00518 
00519 static void freetarget( void *xt, void *data )
00520 {
00521     TARGET* t = (TARGET *)xt;
00522     if ( t->settings )
00523         freesettings( t->settings );
00524     if ( t->depends )
00525         freetargets( t->depends );
00526     if ( t->includes )
00527         freetarget( t->includes, (void*)0);
00528     if ( t->actions )
00529         freeactions( t->actions );
00530 }
00531 
00532 /*
00533  * donerules() - free TARGET tables
00534  */
00535 
00536 void
00537 donerules()
00538 {
00539      hashenumerate( targethash, freetarget, 0 );
00540         hashdone( targethash );
00541     while ( settings_freelist )
00542     {
00543         SETTINGS* n = settings_freelist->next;
00544         free( settings_freelist );
00545         settings_freelist = n;
00546     }
00547 }
00548 
00549 /*
00550  * args_new() - make a new reference-counted argument list
00551  */
00552 argument_list* args_new()
00553 {
00554     argument_list* r = (argument_list*)malloc( sizeof(argument_list) );
00555     r->reference_count = 0;
00556     lol_init(r->data);
00557     return r;
00558 }
00559 
00560 /*
00561  * args_refer() - add a new reference to the given argument list
00562  */
00563 void args_refer( argument_list* a )
00564 {
00565     ++a->reference_count;
00566 }
00567 
00568 /*
00569  * args_free() - release a reference to the given argument list
00570  */
00571 void args_free( argument_list* a )
00572 {
00573     if (--a->reference_count <= 0)
00574     {
00575         lol_free(a->data);
00576         free(a);
00577     }
00578 }
00579 
00580 /*
00581  * actions_refer() - add a new reference to the given actions
00582  */
00583 void actions_refer(rule_actions* a)
00584 {
00585     ++a->reference_count;
00586 }
00587 
00588 /*
00589  * actions_free() - release a reference to the given actions
00590  */
00591 void actions_free(rule_actions* a)
00592 {
00593     if (--a->reference_count <= 0)
00594     {
00595         freestr(a->command);
00596         list_free(a->bindlist);
00597         free(a);
00598     }
00599 }
00600 
00601 /*
00602  * set_rule_body() - set the argument list and procedure of the given rule
00603  */
00604 static void set_rule_body( RULE* rule, argument_list* args, PARSE* procedure )
00605 {
00606     if ( args )
00607         args_refer( args );
00608     if ( rule->arguments )
00609         args_free( rule->arguments );
00610     rule->arguments = args;
00611     
00612     if ( procedure )
00613         parse_refer( procedure );
00614     if ( rule->procedure )
00615         parse_free( rule->procedure );
00616     rule->procedure = procedure;
00617 }
00618 
00619 /*
00620  * global_name() - given a rule, return the name for a corresponding rule in the global module
00621  */
00622 static char* global_rule_name( RULE* r )
00623 {
00624     if ( r->module == root_module() )
00625     {
00626         return r->name;
00627     }
00628     else
00629     {
00630         char name[4096] = "";
00631         strncat(name, r->module->name, sizeof(name) - 1);
00632         strncat(name, r->name, sizeof(name) - 1 );
00633         return newstr(name);
00634     }
00635 }
00636 
00637 /*
00638  * global_rule() - given a rule, produce the corresponding entry in the global module
00639  */
00640 static RULE* global_rule( RULE* r )
00641 {
00642     if ( r->module == root_module() )
00643     {
00644         return r;
00645     }
00646     else
00647     {
00648         char* name = global_rule_name( r );
00649         RULE* result = define_rule( r->module, name, root_module() );
00650         freestr(name);
00651         return result;
00652     }
00653 }
00654 
00655 /*
00656  * new_rule_body() - make a new rule named rulename in the given
00657  * module, with the given argument list and procedure. If exported is
00658  * true, the rule is exported to the global module as
00659  * modulename.rulename.
00660  */
00661 RULE* new_rule_body( module_t* m, char* rulename, argument_list* args, PARSE* procedure, int exported )
00662 {
00663     RULE* local = define_rule( m, rulename, m );
00664     local->exported = exported;
00665     set_rule_body( local, args, procedure );
00666     
00667     /* Mark the procedure with the global rule name, regardless of
00668      * whether the rule is exported. That gives us something
00669      * reasonably identifiable that we can use, e.g. in profiling
00670      * output. Only do this once, since this could be called multiple
00671      * times with the same procedure.
00672      */
00673     if ( procedure->rulename == 0 )
00674         procedure->rulename = global_rule_name( local );
00675 
00676     return local;
00677 }
00678 
00679 static void set_rule_actions( RULE* rule, rule_actions* actions )
00680 {
00681     if ( actions )
00682         actions_refer( actions );
00683     if ( rule->actions )
00684         actions_free( rule->actions );
00685     rule->actions = actions;
00686     
00687 }
00688 
00689 static rule_actions* actions_new( char* command, LIST* bindlist, int flags )
00690 {
00691     rule_actions* result = (rule_actions*)malloc(sizeof(rule_actions));
00692     result->command = copystr( command );
00693     result->bindlist = bindlist;
00694     result->flags = flags;
00695     result->reference_count = 0;
00696     return result;
00697 }
00698 
00699 RULE* new_rule_actions( module_t* m, char* rulename, char* command, LIST* bindlist, int flags )
00700 {
00701     RULE* local = define_rule( m, rulename, m );
00702     RULE* global = global_rule( local );
00703     set_rule_actions( local, actions_new( command, bindlist, flags ) );
00704     set_rule_actions( global, local->actions );
00705     return local;
00706 }
00707 
00708 /* Looks for a rule in the specified module, and returns it, if found.
00709    First checks if the rule is present in the module's rule table.
00710    Second, if name of the rule is in the form name1.name2 and name1 is in 
00711    the list of imported modules, look in module 'name1' for rule 'name2'.
00712 */
00713 RULE *lookup_rule( char *rulename, module_t *m, int local_only )
00714 {
00715     RULE rule, *r = &rule, *result = 0;
00716     module_t* original_module = m;
00717     r->name = rulename;
00718 
00719     if (m->class_module)
00720         m = m->class_module;
00721 
00722     if (m->rules && hashcheck( m->rules, (HASHDATA **)&r ) )
00723         result = r;
00724     else if (!local_only && m->imported_modules) {
00725         /* Try splitting the name into module and rule. */
00726         char *p = strchr(r->name, '.') ;
00727         if (p) {
00728             *p = '\0';
00729             /* Now, r->name keeps the module name, and p+1 keeps the rule name. */
00730             if (hashcheck( m->imported_modules, (HASHDATA **)&r))
00731             {
00732                 result = lookup_rule(p+1, bindmodule(rulename), 1);
00733             }
00734             *p = '.';
00735         }        
00736     }
00737 
00738     if (result)
00739     {
00740         if (local_only && !result->exported)
00741             result = 0;
00742         else
00743         {
00744             /* Lookup started in class module. We've found a rule in class module,
00745                which is marked for execution in that module, or in some instances.
00746                Mark it for execution in the instance where we've started lookup.
00747             */
00748             int execute_in_class = (result->module == m);
00749             int execute_in_some_instance = 
00750             (result->module->class_module && result->module->class_module == m);
00751             if (original_module != m && (execute_in_class || execute_in_some_instance))
00752                 result->module = original_module;            
00753         }
00754     }
00755 
00756     return result;
00757         
00758 }
00759 
00760 
00761 RULE *bindrule( char *rulename, module_t* m)
00762 {
00763     RULE *result;
00764 
00765     result = lookup_rule(rulename, m, 0);
00766     if (!result)
00767         result = lookup_rule(rulename, root_module(), 0);
00768     /* We've only one caller, 'evaluate_rule', which will complain about 
00769        calling underfined rule. We could issue the error
00770        here, but we don't have necessary information, such as frame.
00771     */
00772     if (!result)
00773         result = enter_rule( rulename, root_module() );
00774 
00775     return result;
00776 }
00777 
00778 RULE* import_rule( RULE* source, module_t* m, char* name )
00779 {
00780     RULE* dest = define_rule( source->module, name, m );
00781     set_rule_body( dest, source->arguments, source->procedure );
00782     set_rule_actions( dest, source->actions );
00783     return dest;
00784 }

Generated on Mon Nov 8 17:07:52 2004 for MPT by  doxygen 1.3.9.1