📄 compile.c
字号:
/* * 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 <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 );struct frame *frame_before_python_call;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 intlcmp( 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, VAR_SET, 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 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -