Пример #1
0
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;
}
Пример #2
0
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;
}
Пример #3
0
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;
}
Пример #4
0
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;
}
Пример #5
0
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;
}
Пример #6
0
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;
}
Пример #7
0
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;
}
Пример #8
0
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;
}
Пример #9
0
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;
}
Пример #10
0
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;
}
Пример #11
0
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;
}
Пример #12
0
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;
}
Пример #13
0
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;
}
Пример #14
0
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;
}
Пример #15
0
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;
}
Пример #16
0
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;
}
Пример #17
0
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;
}
Пример #18
0
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;
}
Пример #19
0
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;
}
Пример #20
0
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;
}
Пример #21
0
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;
}