LIST * compile_switch( PARSE *parse, LOL *args, int *jmp ) { LIST *nt = (*parse->left->func)( parse->left, args, jmp ); LIST *result = 0; if( DEBUG_COMPILE ) { debug_compile( 0, "switch" ); list_print( nt ); printf( "\n" ); } /* Step through cases */ for( parse = parse->right; parse; parse = parse->right ) { if( !glob( parse->left->string, list_first(nt) ? list_value(list_first(nt)) : "" ) ) { /* Get & exec parse tree for this case */ parse = parse->left->left; result = (*parse->func)( parse, args, jmp ); break; } } list_free( nt ); return result; }
LIST * compile_set( PARSE *parse, LOL *args, int *jmp ) { LIST *nt = (*parse->left->func)( parse->left, args, jmp ); LIST *ns = (*parse->right->func)( parse->right, args, jmp ); LISTITEM *l; if( DEBUG_COMPILE ) { debug_compile( 0, "set" ); list_print( nt ); printf( " %s ", set_names[ parse->num ] ); list_print( ns ); printf( "\n" ); } /* Call var_set to set variable */ /* var_set keeps ns, so need to copy it */ for( l = list_first(nt); l; l = list_next( l ) ) var_set( list_value(l), list_copy( L0, ns ), parse->num ); list_free( nt ); return ns; }
LIST * compile_switch( PARSE * parse, FRAME * frame ) { LIST * nt = parse_evaluate( parse->left, frame ); LIST * result = 0; if ( DEBUG_COMPILE ) { debug_compile( 0, "switch", frame ); list_print( nt ); printf( "\n" ); } /* Step through cases. */ for ( parse = parse->right; parse; parse = parse->right ) { if ( !glob( parse->left->string, nt ? nt->string : "" ) ) { /* Get & exec parse tree for this case. */ parse = parse->left->left; result = parse_evaluate( parse, frame ); break; } } list_free( nt ); return result; }
LIST * compile_on( PARSE *parse, FRAME *frame ) { LIST *nt = parse_evaluate( parse->left, frame ); LIST *result = 0; if( DEBUG_COMPILE ) { debug_compile( 0, "on", frame ); list_print( nt ); printf( "\n" ); } if( nt ) { TARGET *t = bindtarget( nt->string ); pushsettings( t->settings ); result = parse_evaluate( parse->right, frame ); popsettings( t->settings ); } list_free( nt ); return result; }
LIST * compile_setcomp( PARSE *parse, LOL *args, int *jmp ) { RULE *rule = bindrule( parse->string ); LIST *params = 0; PARSE *p; /* Build param list */ for( p = parse->left; p; p = p->left ) params = list_append( params, p->string, 1 ); if( DEBUG_COMPILE ) { debug_compile( 0, "rule" ); printf( "%s ", parse->string ); list_print( params ); printf( "\n" ); } /* Free old one, if present */ if( rule->procedure ) parse_free( rule->procedure ); if( rule->params ) list_free( rule->params ); rule->procedure = parse->right; rule->params = params; /* we now own this parse tree */ /* don't let parse_free() release it */ parse_refer( parse->right ); return L0; }
LIST * compile_settings( PARSE *parse, FRAME *frame ) { LIST *nt = parse_evaluate( parse->left, frame ); LIST *ns = parse_evaluate( parse->third, frame ); LIST *targets = parse_evaluate( parse->right, frame ); LIST *ts; int append = parse->num == ASSIGN_APPEND; if( DEBUG_COMPILE ) { debug_compile( 0, "set", frame); list_print( nt ); printf( " on " ); list_print( targets ); printf( " %s ", append ? "+=" : "=" ); list_print( ns ); printf( "\n" ); } /* Call addsettings to save variable setting */ /* addsettings keeps ns, so need to copy it */ /* Pass append flag to addsettings() */ for( ts = targets; ts; ts = list_next( ts ) ) { TARGET *t = bindtarget( ts->string ); LIST *l; for( l = nt; l; l = list_next( l ) ) t->settings = addsettings( t->settings, append, l->string, list_copy( (LIST*)0, ns ) ); } list_free( nt ); list_free( targets ); return ns; }
LIST * compile_include( PARSE *parse, FRAME *frame ) { LIST *nt = parse_evaluate( parse->left, frame ); if( DEBUG_COMPILE ) { debug_compile( 0, "include", frame); list_print( nt ); printf( "\n" ); } if( nt ) { TARGET *t = bindtarget( nt->string ); /* DWA 2001/10/22 - Perforce Jam clears the arguments here, which * prevents an included file from being treated as part of the body * of a rule. I didn't see any reason to do that, so I lifted the * restriction. */ /* Bind the include file under the influence of */ /* "on-target" variables. Though they are targets, */ /* include files are not built with make(). */ pushsettings( t->settings ); /* We don't expect that file to be included is generated by some action. Therefore, pass 0 as third argument. */ t->boundname = search( t->name, &t->time, 0 ); popsettings( t->settings ); parse_file( t->boundname, frame ); } list_free( nt ); return L0; }
LIST * compile_settings( PARSE *parse, LOL *args, int *jmp ) { LIST *nt = (*parse->left->func)( parse->left, args, jmp ); LIST *ns = (*parse->third->func)( parse->third, args, jmp ); LIST *targets = (*parse->right->func)( parse->right, args, jmp ); LISTITEM *ts; if( DEBUG_COMPILE ) { debug_compile( 0, "set" ); list_print( nt ); printf( "on " ); list_print( targets ); printf( " %s ", set_names[ parse->num ] ); list_print( ns ); printf( "\n" ); } /* Call addsettings to save variable setting */ /* addsettings keeps ns, so need to copy it */ /* Pass append flag to addsettings() */ for( ts = list_first(targets); ts; ts = list_next( ts ) ) { TARGET *t = bindtarget( list_value(ts) ); LISTITEM *l; for( l = list_first(nt); l; l = list_next( l ) ) t->settings = addsettings( t->settings, parse->num, list_value(l), list_copy( NULL, ns ) ); } list_free( nt ); list_free( targets ); return ns; }
LIST * compile_local( PARSE *parse, LOL *args, int *jmp ) { LISTITEM *l; SETTINGS *s = 0; LIST *nt = (*parse->left->func)( parse->left, args, jmp ); LIST *ns = (*parse->right->func)( parse->right, args, jmp ); LIST *result; if( DEBUG_COMPILE ) { debug_compile( 0, "local" ); list_print( nt ); printf( " = " ); list_print( ns ); printf( "\n" ); } /* Initial value is ns */ for( l = list_first(nt); l; l = list_next( l ) ) s = addsettings( s, 0, list_value(l), list_copy( NULL, ns ) ); list_free( ns ); list_free( nt ); /* Note that callees of the current context get this "local" */ /* variable, making it not so much local as layered. */ pushsettings( s ); result = (*parse->third->func)( parse->third, args, jmp ); popsettings( s ); freesettings( s ); return result; }
LIST * compile_local( PARSE *parse, FRAME *frame ) { LIST *l; SETTINGS *s = 0; LIST *nt = parse_evaluate( parse->left, frame ); LIST *ns = parse_evaluate( parse->right, frame ); LIST *result; if( DEBUG_COMPILE ) { debug_compile( 0, "local", frame); list_print( nt ); printf( " = " ); list_print( ns ); printf( "\n" ); } /* Initial value is ns */ for( l = nt; l; l = list_next( l ) ) s = addsettings( s, 0, l->string, list_copy( (LIST*)0, ns ) ); list_free( ns ); list_free( nt ); /* Note that callees of the current context get this "local" */ /* variable, making it not so much local as layered. */ pushsettings( s ); result = parse_evaluate( parse->third, frame ); popsettings( s ); freesettings( s ); return result; }
LIST * compile_include( PARSE *parse, LOL *args, int *jmp ) { LIST *nt = (*parse->left->func)( parse->left, args, jmp ); if( DEBUG_COMPILE ) { debug_compile( 0, "include" ); list_print( nt ); printf( "\n" ); } if( nt && list_first(nt) ) { TARGET *t = bindtarget( list_value(list_first(nt)) ); /* Bind the include file under the influence of */ /* "on-target" variables. Though they are targets, */ /* include files are not built with make(). */ /* Needn't copysettings(), as search sets no vars. */ pushsettings( t->settings ); t->boundname = search( t->name, &t->time ); popsettings( t->settings ); /* Don't parse missing file if NOCARE set */ if( t->time || !( t->flags & T_FLAG_NOCARE ) ) parse_file( t->boundname ); } list_free( nt ); return L0; }
LIST * compile_set( PARSE *parse, FRAME *frame ) { LIST *nt = parse_evaluate( parse->left, frame ); LIST *ns = parse_evaluate( parse->right, frame ); LIST *l; int setflag; char *trace; switch( parse->num ) { case ASSIGN_SET: setflag = VAR_SET; trace = "="; break; case ASSIGN_APPEND: setflag = VAR_APPEND; trace = "+="; break; case ASSIGN_DEFAULT: setflag = VAR_DEFAULT; trace = "?="; break; default: setflag = VAR_SET; trace = ""; break; } if( DEBUG_COMPILE ) { debug_compile( 0, "set", frame); list_print( nt ); printf( " %s ", trace ); list_print( ns ); printf( "\n" ); } /* Call var_set to set variable */ /* var_set keeps ns, so need to copy it */ for( l = nt; l; l = list_next( l ) ) var_set( l->string, list_copy( L0, ns ), setflag ); list_free( nt ); return ns; }
LIST * compile_set( PARSE * parse, FRAME * frame ) { LIST * nt = parse_evaluate( parse->left, frame ); LIST * ns = parse_evaluate( parse->right, frame ); LIST * l; char const * trace; int setflag = assign_var_mode( parse->num, &trace ); if ( DEBUG_COMPILE ) { debug_compile( 0, "set", frame ); list_print( nt ); printf( " %s ", trace ); list_print( ns ); printf( "\n" ); } /* Call var_set to set variable. var_set keeps ns, so need to copy it. */ for ( l = nt; l; l = list_next( l ) ) var_set( l->string, list_copy( L0, ns ), setflag ); list_free( nt ); return ns; }
LIST * compile_settings( PARSE * parse, FRAME * frame ) { LIST * nt = parse_evaluate( parse->left, frame ); LIST * ns = parse_evaluate( parse->third, frame ); LIST * targets = parse_evaluate( parse->right, frame ); LIST * ts; char const * trace; int setflag = assign_var_mode( parse->num, &trace ); if ( DEBUG_COMPILE ) { debug_compile( 0, "set", frame ); list_print( nt ); printf( " on " ); list_print( targets ); printf( " %s ", trace ); list_print( ns ); printf( "\n" ); } /* Call addsettings() to save variable setting. addsettings() keeps ns, so * need to copy it. Pass append flag to addsettings(). */ for ( ts = targets; ts; ts = list_next( ts ) ) { TARGET * t = bindtarget( ts->string ); LIST * l; for ( l = nt; l; l = list_next( l ) ) t->settings = addsettings( t->settings, setflag, l->string, list_copy( (LIST *)0, ns ) ); } list_free( nt ); list_free( targets ); return ns; }
LIST * compile_on( PARSE *parse, LOL *args, int *jmp ) { LIST *nt = (*parse->left->func)( parse->left, args, jmp ); LIST *result = 0; if( DEBUG_COMPILE ) { debug_compile( 0, "on" ); list_print( nt ); printf( "\n" ); } /* * Copy settings, so that 'on target var on target = val' * doesn't set var globally. */ if( nt && list_first(nt) ) { TARGET *t = bindtarget( list_value(list_first(nt)) ); SETTINGS *s = copysettings( t->settings ); pushsettings( s ); result = (*parse->right->func)( parse->right, args, jmp ); popsettings( s ); freesettings( s ); } list_free( nt ); return result; }
LIST * evaluate_rule( char * rulename, FRAME * frame ) { LIST * result = L0; RULE * rule; profile_frame prof[1]; module_t * prev_module = frame->module; LIST * l; { LOL arg_context_, * arg_context = &arg_context_; if ( !frame->prev ) lol_init(arg_context); else arg_context = frame->prev->args; l = var_expand( L0, rulename, rulename+strlen(rulename), arg_context, 0 ); } if ( !l ) { backtrace_line( frame->prev ); printf( "warning: rulename %s expands to empty string\n", rulename ); backtrace( frame->prev ); return result; } rulename = l->string; rule = bindrule( l->string, frame->module ); #ifdef HAVE_PYTHON if ( rule->python_function ) { /* The below messing with modules is due to the way modules are * implemented in Jam. Suppose we are in module M1 now. The global * variable map actually holds 'M1' variables, and M1->variables hold * global variables. * * If we call Python right away, Python calls back Jam and then Jam * does 'module M1 { }' then Jam will try to swap the current global * variables with M1->variables. The result will be that global * variables map will hold global variables, and any variable settings * we do will go to the global module, not M1. * * By restoring basic state, where the global variable map holds global * variable, we make sure any future 'module M1' entry will work OK. */ LIST * result; module_t * m = python_module(); frame->module = m; exit_module( prev_module ); enter_module( m ); result = call_python_function( rule, frame ); exit_module( m ); enter_module ( prev_module ); return result; } #endif /* Drop the rule name. */ l = list_pop_front( l ); /* Tack the rest of the expansion onto the front of the first argument. */ frame->args->list[0] = list_append( l, lol_get( frame->args, 0 ) ); if ( DEBUG_COMPILE ) { /* Try hard to indicate in which module the rule is going to execute. */ if ( rule->module != frame->module && rule->procedure != 0 && strcmp( rulename, rule->procedure->rulename ) ) { char buf[256] = ""; strncat( buf, rule->module->name, sizeof( buf ) - 1 ); strncat( buf, rule->name, sizeof( buf ) - 1 ); debug_compile( 1, buf, frame ); } else { debug_compile( 1, rulename, frame ); } lol_print( frame->args ); printf( "\n" ); } if ( rule->procedure && rule->module != prev_module ) { /* Propagate current module to nested rule invocations. */ frame->module = rule->module; /* Swap variables. */ exit_module( prev_module ); enter_module( rule->module ); } /* Record current rule name in frame. */ if ( rule->procedure ) { frame->rulename = rulename; /* And enter record profile info. */ if ( DEBUG_PROFILE ) profile_enter( rule->procedure->rulename, prof ); } /* Check traditional targets $(<) and sources $(>). */ if ( !rule->actions && !rule->procedure ) { backtrace_line( frame->prev ); printf( "rule %s unknown in module %s\n", rule->name, frame->module->name ); backtrace( frame->prev ); exit( 1 ); } /* If this rule will be executed for updating the targets then construct the * action for make(). */ if ( rule->actions ) { TARGETS * t; ACTION * action; /* The action is associated with this instance of this rule. */ action = (ACTION *)BJAM_MALLOC( sizeof( ACTION ) ); memset( (char *)action, '\0', sizeof( *action ) ); action->rule = rule; action->targets = targetlist( (TARGETS *)0, lol_get( frame->args, 0 ) ); action->sources = targetlist( (TARGETS *)0, lol_get( frame->args, 1 ) ); /* If we have a group of targets all being built using the same action * then we must not allow any of them to be used as sources unless they * had all already been built in the first place or their joined action * has had a chance to finish its work and build all of them anew. * * Without this it might be possible, in case of a multi-process build, * for their action, triggered by buiding one of the targets, to still * be running when another target in the group reports as done in order * to avoid triggering the same action again and gets used prematurely. * * As a quick-fix to achieve this effect we make all the targets list * each other as 'included targets'. More precisely, we mark the first * listed target as including all the other targets in the list and vice * versa. This makes anyone depending on any of those targets implicitly * depend on all of them, thus making sure none of those targets can be * used as sources until all of them have been built. Note that direct * dependencies could not have been used due to the 'circular * dependency' issue. * * TODO: Although the current implementation solves the problem of one * of the targets getting used before its action completes its work it * also forces the action to run whenever any of the targets in the * group is not up to date even though some of them might not actually * be used by the targets being built. We should see how we can * correctly recognize such cases and use that to avoid running the * action if possible and not rebuild targets not actually depending on * targets that are not up to date. * * TODO: Using the 'include' feature might have side-effects due to * interaction with the actual 'inclusion scanning' system. This should * be checked. */ if ( action->targets ) { TARGET * t0 = action->targets->target; for ( t = action->targets->next; t; t = t->next ) { target_include( t->target, t0 ); target_include( t0, t->target ); } } /* Append this action to the actions of each target. */ for ( t = action->targets; t; t = t->next ) t->target->actions = actionlist( t->target->actions, action ); } /* Now recursively compile any parse tree associated with this rule. * parse_refer()/parse_free() call pair added to ensure rule not freed * during use. */ if ( rule->procedure ) { SETTINGS * local_args = collect_arguments( rule, frame ); PARSE * parse = rule->procedure; parse_refer( parse ); pushsettings( local_args ); result = parse_evaluate( parse, frame ); popsettings( local_args ); freesettings( local_args ); parse_free( parse ); } if ( frame->module != prev_module ) { exit_module( frame->module ); enter_module( prev_module ); } if ( DEBUG_PROFILE && rule->procedure ) profile_exit( prof ); if ( DEBUG_COMPILE ) debug_compile( -1, 0, frame); return result; }
LIST * compile_eval( PARSE * parse, FRAME * frame ) { LIST * ll; LIST * lr; LIST * s; LIST * t; int status = 0; /* Short circuit lr eval for &&, ||, and 'in'. */ ll = parse_evaluate( parse->left, frame ); lr = 0; switch ( parse->num ) { case EXPR_AND: case EXPR_IN : if ( ll ) goto eval; break; case EXPR_OR : if ( !ll ) goto eval; break; default: eval: lr = parse_evaluate( parse->right, frame ); } /* Now eval. */ switch ( parse->num ) { case EXPR_NOT: if ( !ll ) status = 1; break; case EXPR_AND: if ( ll && lr ) status = 1; break; case EXPR_OR : if ( ll || lr ) status = 1; break; case EXPR_IN: /* "a in b": make sure each of ll is equal to something in lr. */ for ( t = ll; t; t = list_next( t ) ) { for ( s = lr; s; s = list_next( s ) ) if ( !strcmp( t->string, s->string ) ) break; if ( !s ) break; } /* No more ll? Success. */ if ( !t ) status = 1; break; case EXPR_EXISTS: if ( lcmp( ll, L0 ) != 0 ) status = 1; break; case EXPR_EQUALS: if ( lcmp( ll, lr ) == 0 ) status = 1; break; case EXPR_NOTEQ : if ( lcmp( ll, lr ) != 0 ) status = 1; break; case EXPR_LESS : if ( lcmp( ll, lr ) < 0 ) status = 1; break; case EXPR_LESSEQ: if ( lcmp( ll, lr ) <= 0 ) status = 1; break; case EXPR_MORE : if ( lcmp( ll, lr ) > 0 ) status = 1; break; case EXPR_MOREEQ: if ( lcmp( ll, lr ) >= 0 ) status = 1; break; } if ( DEBUG_IF ) { debug_compile( 0, "if", frame ); list_print( ll ); printf( "(%d) ", status ); list_print( lr ); printf( "\n" ); } /* Find something to return. */ /* In odd circumstances (like "" = "") */ /* we'll have to return a new string. */ if ( !status ) t = 0; else if ( ll ) t = ll, ll = 0; else if ( lr ) t = lr, lr = 0; else t = list_new( L0, newstr( "1" ) ); if ( ll ) list_free( ll ); if ( lr ) list_free( lr ); return t; }
LIST * evaluate_rule( char *rulename, FRAME *frame ) { LIST *result = L0; RULE *rule; profile_frame prof[1]; module_t *prev_module = frame->module; LIST *l; { LOL arg_context_, *arg_context = &arg_context_; if ( !frame->prev ) lol_init(arg_context); else arg_context = frame->prev->args; l = var_expand( L0, rulename, rulename+strlen(rulename), arg_context, 0 ); } if ( !l ) { backtrace_line( frame->prev ); printf( "warning: rulename %s expands to empty string\n", rulename ); backtrace( frame->prev ); return result; } rulename = l->string; rule = bindrule( l->string, frame->module ); #ifdef HAVE_PYTHON if (rule->python_function) { return call_python_function(rule, frame); } #endif /* drop the rule name */ l = list_pop_front( l ); /* tack the rest of the expansion onto the front of the first argument */ frame->args->list[0] = list_append( l, lol_get( frame->args, 0 ) ); if ( DEBUG_COMPILE ) { /* Try hard to indicate in which module the rule is going to execute */ if ( rule->module != frame->module && rule->procedure != 0 && strcmp(rulename, rule->procedure->rulename) ) { char buf[256] = ""; strncat( buf, rule->module->name, sizeof(buf) - 1 ); strncat( buf, rule->name, sizeof(buf) - 1 ); debug_compile( 1, buf, frame); } else { debug_compile( 1, rulename, frame); } lol_print( frame->args ); printf( "\n" ); } if ( rule->procedure && rule->module != prev_module ) { /* propagate current module to nested rule invocations */ frame->module = rule->module; /* swap variables */ exit_module( prev_module ); enter_module( rule->module ); } /* record current rule name in frame */ if ( rule->procedure ) { frame->rulename = rulename; /* and enter record profile info */ if ( DEBUG_PROFILE ) profile_enter( rule->procedure->rulename, prof ); } /* Check traditional targets $(<) and sources $(>) */ if( !rule->actions && !rule->procedure ) { backtrace_line( frame->prev ); printf( "rule %s unknown in module %s\n", rule->name, frame->module->name ); backtrace( frame->prev ); exit(1); } /* If this rule will be executed for updating the targets */ /* then construct the action for make(). */ if( rule->actions ) { TARGETS *t; ACTION *action; /* The action is associated with this instance of this rule */ action = (ACTION *)malloc( sizeof( ACTION ) ); memset( (char *)action, '\0', sizeof( *action ) ); action->rule = rule; action->targets = targetlist( (TARGETS *)0, lol_get( frame->args, 0 ) ); action->sources = targetlist( (TARGETS *)0, lol_get( frame->args, 1 ) ); /* Append this action to the actions of each target */ for( t = action->targets; t; t = t->next ) t->target->actions = actionlist( t->target->actions, action ); } /* Now recursively compile any parse tree associated with this rule */ /* refer/free to ensure rule not freed during use */ if( rule->procedure ) { SETTINGS *local_args = collect_arguments( rule, frame ); PARSE *parse = rule->procedure; parse_refer( parse ); pushsettings( local_args ); result = parse_evaluate( parse, frame ); popsettings( local_args ); freesettings( local_args ); parse_free( parse ); } if ( frame->module != prev_module ) { exit_module( frame->module ); enter_module( prev_module ); } if ( DEBUG_PROFILE && rule->procedure ) profile_exit( prof ); if( DEBUG_COMPILE ) debug_compile( -1, 0, frame); return result; }
LIST * evaluate_rule( const char *rulename, LOL *args, LIST *result, int *jmp ) { RULE *rule = bindrule( rulename ); if( DEBUG_COMPILE ) { debug_compile( 1, rulename ); lol_print( args ); printf( "\n" ); } /* Check traditional targets $(<) and sources $(>) */ if( !rule->actions && !rule->procedure ) printf( "warning: unknown rule %s\n", rule->name ); /* If this rule will be executed for updating the targets */ /* then construct the action for make(). */ if( rule->actions ) { TARGETS *t; ACTION *action; /* The action is associated with this instance of this rule */ action = (ACTION *)malloc( sizeof( ACTION ) ); memset( (char *)action, '\0', sizeof( *action ) ); action->rule = rule; action->targets = targetlist( (TARGETS *)0, lol_get( args, 0 ) ); action->sources = targetlist( (TARGETS *)0, lol_get( args, 1 ) ); /* Append this action to the actions of each target */ for( t = action->targets; t; t = t->next ) t->target->actions = actionlist( t->target->actions, action ); } /* Now recursively compile any parse tree associated with this rule */ if( rule->procedure ) { PARSE *parse = rule->procedure; SETTINGS *s = 0; LIST *l; int i; # ifdef OPT_RULE_PROFILING_EXT struct timeval startTime, endTime; if ( DEBUG_PROFILE_RULES ) gettimeofday(&startTime, 0); # endif /* build parameters as local vars */ for( l = rule->params, i = 0; l; l = l->next, i++ ) s = addsettings( s, 0, l->string, list_copy( L0, lol_get( args, i ) ) ); /* Run rule. */ /* Bring in local params. */ /* refer/free to ensure rule not freed during use. */ parse_refer( parse ); pushsettings( s ); result = list_append( result, (*parse->func)( parse, args, jmp ) ); popsettings( s ); freesettings( s ); parse_free( parse ); # ifdef OPT_RULE_PROFILING_EXT if ( DEBUG_PROFILE_RULES ) { gettimeofday(&endTime, 0); rule->invocations++; rule->invocation_time += (endTime.tv_sec - startTime.tv_sec) * (int64_t)1000000 + (endTime.tv_usec - startTime.tv_usec); } # endif } if( DEBUG_COMPILE ) debug_compile( -1, 0 ); return result; }
LIST * compile_eval( PARSE *parse, LOL *args, int *jmp ) { LIST *ll, *lr, *t; int status = 0; /* Short circuit lr eval for &&, ||, and 'in' */ ll = (*parse->left->func)( parse->left, args, jmp ); lr = 0; switch( parse->num ) { case EXPR_AND: case EXPR_IN: if( ll ) goto eval; break; case EXPR_OR: if( !ll ) goto eval; break; default: eval: lr = (*parse->right->func)( parse->right, args, jmp ); } /* Now eval */ switch( parse->num ) { case EXPR_NOT: if( !ll ) status = 1; break; case EXPR_AND: if( ll && lr ) status = 1; break; case EXPR_OR: if( ll || lr ) status = 1; break; case EXPR_IN: /* "a in b": make sure each of */ /* ll is equal to something in lr. */ status = list_in(ll, lr); break; case EXPR_EXISTS: if( lcmp( ll, L0 ) != 0 ) status = 1; break; case EXPR_EQUALS: if( lcmp( ll, lr ) == 0 ) status = 1; break; case EXPR_NOTEQ: if( lcmp( ll, lr ) != 0 ) status = 1; break; case EXPR_LESS: if( lcmp( ll, lr ) < 0 ) status = 1; break; case EXPR_LESSEQ: if( lcmp( ll, lr ) <= 0 ) status = 1; break; case EXPR_MORE: if( lcmp( ll, lr ) > 0 ) status = 1; break; case EXPR_MOREEQ: if( lcmp( ll, lr ) >= 0 ) status = 1; break; } if( DEBUG_IF ) { debug_compile( 0, "if" ); list_print( ll ); printf( "(%d) ", status ); list_print( lr ); printf( "\n" ); } /* Find something to return. */ /* In odd circumstances (like "" = "") */ /* we'll have to return a new string. */ if( !status ) t = 0; else if( ll ) t = ll, ll = 0; else if( lr ) t = lr, lr = 0; else t = list_append( L0, "1", 0 ); if( ll ) list_free( ll ); if( lr ) list_free( lr ); return t; }
LIST * evaluate_rule( const char *rulename, LOL *args, LIST *result ) { #ifdef OPT_EXPAND_RULE_NAMES_EXT RULE *rule; char *expanded; char *c; int i; BUFFER buff; buffer_init( &buff ); if( (i = var_string( rulename, &buff, 0, args, ' ' )) < 0 ) { printf( "Failed to expand rule %s -- expansion too long\n", rulename ); exit( EXITBAD ); } expanded = buffer_ptr( &buff ); while ( expanded[0] == ' ' ) expanded++; while ( (c = strrchr(expanded, ' ')) ) *c = '\0'; if( DEBUG_COMPILE ) { debug_compile( 1, rulename ); if ( strcmp(rulename, expanded) ) printf( "-> %s ", expanded ); lol_print( args ); printf( "\n" ); } rule = bindrule( expanded ); #else RULE *rule = bindrule( rulename ); if( DEBUG_COMPILE ) { debug_compile( 1, rulename ); lol_print( args ); printf( "\n" ); } #endif #ifdef OPT_LOAD_MISSING_RULE_EXT if( !rule->actions && !rule->procedure ) { if( ruleexists( "FindMissingRule" ) ) { LOL lol; LIST *args = list_append( L0, expanded, 0 ); LIST *result; lol_init( &lol ); lol_add( &lol, args ); result = evaluate_rule( "FindMissingRule", &lol, L0 ); lol_free( &lol ); if( list_first( result ) ) { rule = bindrule( list_value( list_first( result ) ) ); } list_free( result ); } } #endif /* OPT_LOAD_MISSING_RULE_EXT */ /* Check traditional targets $(<) and sources $(>) */ #ifdef OPT_IMPROVED_WARNINGS_EXT if( !rule->actions && !rule->procedure && !globs.silence ) printf( "warning: unknown rule %s %s\n", rule->name, file_and_line()); #else if( !rule->actions && !rule->procedure ) printf( "warning: unknown rule %s\n", rule->name ); #endif /* If this rule will be executed for updating the targets */ /* then construct the action for make(). */ if( rule->actions ) { TARGETS *t; ACTION *action; /* The action is associated with this instance of this rule */ action = (ACTION *)malloc( sizeof( ACTION ) ); memset( (char *)action, '\0', sizeof( *action ) ); action->rule = rule; #ifdef OPT_BUILTIN_NEEDS_EXT action->targets = targetlist( (TARGETS *)0, lol_get( args, 0 ), 0 ); action->sources = targetlist( (TARGETS *)0, lol_get( args, 1 ), 0 ); action->autosettings = targetlist( (TARGETS *)0, lol_get( args, 2 ), 0 ); #else action->targets = targetlist( (TARGETS *)0, lol_get( args, 0 ) ); action->sources = targetlist( (TARGETS *)0, lol_get( args, 1 ) ); #endif #ifdef OPT_USE_CHECKSUMS_EXT action->extratargets = targetlist( (TARGETS *)0, lol_get( args, 3 ), 0 ); #endif /* OPT_USE_CHECKSUMS_EXT */ #ifdef OPT_CLEAN_GLOBS_EXT { TARGETS* targets; for ( targets = action->targets; targets; targets = targets->next ) { if ( !( targets->target->flags & T_FLAG_NOTFILE ) ) add_used_target_to_hash( targets->target ); } } #endif /* OPT_CLEAN_GLOBS_EXT */ /* Append this action to the actions of each target */ #ifdef OPT_MULTIPASS_EXT action->pass = actionpass; for( t = action->targets; t; t = t->next ) { t->target->progress = T_MAKE_INIT; t->target->actions = actionlist( t->target->actions, action ); } #else for( t = action->targets; t; t = t->next ) t->target->actions = actionlist( t->target->actions, action ); #endif } /* Now recursively compile any parse tree associated with this rule */ if( rule->procedure ) { PARSE *parse = rule->procedure; SETTINGS *s = 0; int jmp = JMP_NONE; LISTITEM *l; int i; /* build parameters as local vars */ for( l = list_first(rule->params), i = 0; l; l = list_next(l), i++ ) s = addsettings( s, 0, list_value(l), list_copy( L0, lol_get( args, i ) ) ); /* Run rule. */ /* Bring in local params. */ /* refer/free to ensure rule not freed during use. */ parse_refer( parse ); pushsettings( s ); result = list_appendList( result, (*parse->func)( parse, args, &jmp ) ); popsettings( s ); freesettings( s ); parse_free( parse ); } if( DEBUG_COMPILE ) debug_compile( -1, 0 ); #ifdef OPT_EXPAND_RULE_NAMES_EXT buffer_free( &buff ); #endif return result; }