⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 compile.c

📁 C++的一个好库。。。现在很流行
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * Copyright 1993, 2000 Christopher Seiwald.
 *
 * This file is part of Jam - see jam.c for Copyright information.
 */

/*  This file is ALSO:
 *  Copyright 2001-2004 David Abrahams.
 *  Distributed under the Boost Software License, Version 1.0.
 *  (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 */

# include "jam.h"

# include "lists.h"
# include "parse.h"
# include "compile.h"
# include "variable.h"
# include "expand.h"
# include "rules.h"
# include "newstr.h"
# include "make.h"
# include "search.h"
# include "hdrmacro.h"
# include "hash.h"
# include "modules.h"
# include "strings.h"
# include "builtins.h"
# include "class.h"

# include <time.h>
# include <assert.h>
# include <string.h>
# include <stdarg.h>

/*
 * compile.c - compile parsed jam statements
 *
 * External routines:
 *
 *  compile_append() - append list results of two statements
 *	compile_eval() - evaluate if to determine which leg to compile
 *  compile_foreach() - compile the "for x in y" statement
 *  compile_if() - compile 'if' rule
 *  compile_while() - compile 'while' rule
 *  compile_include() - support for 'include' - call include() on file
 *  compile_list() - expand and return a list 
 *  compile_local() - declare (and set) local variables
 *  compile_null() - do nothing -- a stub for parsing
 *  compile_on() - run rule under influence of on-target variables
 *  compile_rule() - compile a single user defined rule
 *  compile_rules() - compile a chain of rules
 *  compile_set() - compile the "set variable" statement
 *  compile_setcomp() - support for `rule` - save parse tree 
 *  compile_setexec() - support for `actions` - save execution string 
 *  compile_settings() - compile the "on =" (set variable on exec) statement
 *  compile_switch() - compile 'switch' rule
 *
 * Internal routines:
 *
 *  debug_compile() - printf with indent to show rule expansion.
 *  evaluate_rule() - execute a rule invocation
 *
 *  builtin_depends() - DEPENDS/INCLUDES rule
 *  builtin_echo() - ECHO rule
 *  builtin_exit() - EXIT rule
 *  builtin_flags() - NOCARE, NOTFILE, TEMPORARY rule
 *
 * 02/03/94 (seiwald) - Changed trace output to read "setting" instead of 
 *          the awkward sounding "settings".
 * 04/12/94 (seiwald) - Combined build_depends() with build_includes().
 * 04/12/94 (seiwald) - actionlist() now just appends a single action.
 * 04/13/94 (seiwald) - added shorthand L0 for null list pointer
 * 05/13/94 (seiwald) - include files are now bound as targets, and thus
 *          can make use of $(SEARCH)
 * 06/01/94 (seiwald) - new 'actions existing' does existing sources
 * 08/23/94 (seiwald) - Support for '+=' (append to variable)
 * 12/20/94 (seiwald) - NOTIME renamed NOTFILE.
 * 01/22/95 (seiwald) - Exit rule.
 * 02/02/95 (seiwald) - Always rule; LEAVES rule.
 * 02/14/95 (seiwald) - NoUpdate rule.
 * 09/11/00 (seiwald) - new evaluate_rule() for headers().
 * 09/11/00 (seiwald) - compile_xxx() now return LIST *.
 *          New compile_append() and compile_list() in
 *          support of building lists here, rather than
 *          in jamgram.yy.
 * 01/10/00 (seiwald) - built-ins split out to builtin.c.
 */

static void debug_compile( int which, char *s, FRAME* frame );
int glob( char *s, char *c );
/* Internal functions from builtins.c */
void backtrace( FRAME *frame );
void backtrace_line( FRAME *frame );
void print_source_line( PARSE* p );


void frame_init( FRAME* frame )
{
    frame->prev = 0;
    frame->prev_user = 0;
    lol_init(frame->args);
    frame->module = root_module();
    frame->rulename = "module scope";
    frame->procedure = 0;
}

void frame_free( FRAME* frame )
{
    lol_free( frame->args );
}

/*
 * compile_append() - append list results of two statements
 *
 *  parse->left more compile_append() by left-recursion
 *  parse->right    single rule
 */

LIST *
compile_append(
    PARSE   *parse,
    FRAME *frame )
{
    /* Append right to left. */

    return list_append( 
        parse_evaluate( parse->left, frame ),
        parse_evaluate( parse->right, frame ) );
}

/*
 * compile_eval() - evaluate if to determine which leg to compile
 *
 * Returns:
 *	list 	if expression true - compile 'then' clause
 *	L0	if expression false - compile 'else' clause
 */

static int
lcmp( LIST *t, LIST *s )
{
	int status = 0;

	while( !status && ( t || s ) )
	{
	    char *st = t ? t->string : "";
	    char *ss = s ? s->string : "";

	    status = strcmp( st, ss );

	    t = t ? list_next( t ) : t;
	    s = s ? list_next( s ) : s;
	}

	return status;
}

LIST *
compile_eval(
	PARSE	*parse,
	FRAME	*frame )
{
	LIST *ll, *lr, *s, *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;
}


/*
 * compile_foreach() - compile the "for x in y" statement
 *
 * Compile_foreach() resets the given variable name to each specified
 * value, executing the commands enclosed in braces for each iteration.
 *
 *  parse->string   index variable
 *  parse->left variable values
 *  parse->right    rule to compile
 */

LIST *
compile_foreach(
    PARSE   *parse,
    FRAME *frame )
{
    LIST    *nv = parse_evaluate( parse->left, frame );
    LIST    *l;
    SETTINGS *s = 0;
        
        if ( parse->num )
        {
            s = addsettings( s, 0, parse->string, L0 );
            pushsettings( s );
        }

    /* Call var_set to reset $(parse->string) for each val. */

    for( l = nv; l; l = list_next( l ) )
    {
        LIST *val = list_new( L0, copystr( l->string ) );

        var_set( parse->string, val, VAR_SET );

        list_free( parse_evaluate( parse->right, frame ) );
    }

        if ( parse->num )
        {
            popsettings( s );
            freesettings( s );
        }

    list_free( nv );

    return L0;
}

/*
 * compile_if() - compile 'if' rule
 *
 *  parse->left     condition tree
 *  parse->right        then tree
 *  parse->third        else tree
 */

LIST *
compile_if(
    PARSE   *p,
    FRAME *frame )
{
    LIST *l = parse_evaluate( p->left, frame );
    if( l )
    {
        list_free( l );
        return parse_evaluate( p->right, frame );
    }
    else
    {
        return parse_evaluate( p->third, frame );
    }
}

LIST *
compile_while(
    PARSE   *p,
    FRAME *frame )
{
    LIST *r = 0;
    LIST *l;
    while ( l = parse_evaluate( p->left, frame ) )
    {
        list_free( l );
        if( r ) list_free( r );
        r = parse_evaluate( p->right, frame );
    }
    return r;
}


/*
 * compile_include() - support for 'include' - call include() on file
 *
 *  parse->left list of files to include (can only do 1)
 */

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;
}

static LIST* evaluate_in_module ( char* module_name, PARSE * p, FRAME* frame)
{
    LIST* result;

    module_t* outer_module = frame->module;
    frame->module = module_name ? bindmodule( module_name ) : root_module();

    if ( outer_module != frame->module )
    {
        exit_module( outer_module );
        enter_module( frame->module );
    }
    
    result = parse_evaluate( p, frame );
    
    if ( outer_module != frame->module )
    {
        exit_module( frame->module );
        enter_module( outer_module );
        frame->module = outer_module;
    }

    return result;
}

LIST *
compile_module(
    PARSE   *p,
    FRAME *frame )
{
    /* Here we are entering a module declaration block. 
     */
    LIST* module_name = parse_evaluate( p->left, frame );
    LIST* result = evaluate_in_module( module_name ? module_name->string : 0, 
                                       p->right, frame );
    
    list_free( module_name );
    return result;
}

LIST *
compile_class( 
    PARSE *p, 
    FRAME *frame )
{
    /** Todo: check for empty class name.
        Check for class redeclaration. */

    char* class_module = 0;

    LIST* name = parse_evaluate( p->left->right, frame );
    LIST* bases = 0;

    if (p->left->left)
        bases = parse_evaluate( p->left->left->right, frame );

    class_module = make_class_module(name, bases, frame);    
    evaluate_in_module( class_module, p->right, frame );

    return L0;    
}


/*
 * compile_list() - expand and return a list 
 *
 *  parse->string - character string to expand
 */

LIST *
compile_list(
    PARSE   *parse,
    FRAME *frame )
{
    /* voodoo 1 means: s is a copyable string */
    char *s = parse->string;
    return var_expand( L0, s, s + strlen( s ), frame->args, 1 );
}

/*
 * compile_local() - declare (and set) local variables
 *
 *  parse->left list of variables
 *  parse->right    list of values
 *  parse->third    rules to execute
 */

LIST *
compile_local(
    PARSE   *parse,
    FRAME *frame )
{
    LIST *l;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -