# include "jam.h"
# include "lists.h"
# include "parse.h"
# include "compile.h"
# include "variable.h"
# include "rules.h"
# include "newstr.h"
# include "make.h"
# include "search.h"
static void debug_compile();
static int evaluate_if();
static void builtin_depends();
static void builtin_echo();
static void builtin_exit();
static void builtin_flags();
int jam_glob();
# define P0 (PARSE *)0
# define C0 (char *)0
void
compile_builtins()
{
bindrule( "Always" )->procedure =
parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_TOUCHED );
bindrule( "ALWAYS" )->procedure =
parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_TOUCHED );
bindrule( "Depends" )->procedure =
parse_make( builtin_depends, P0, P0, C0, C0, L0, L0, T_DEPS_DEPENDS );
bindrule( "DEPENDS" )->procedure =
parse_make( builtin_depends, P0, P0, C0, C0, L0, L0, T_DEPS_DEPENDS );
bindrule( "Echo" )->procedure =
parse_make( builtin_echo, P0, P0, C0, C0, L0, L0, 0 );
bindrule( "ECHO" )->procedure =
parse_make( builtin_echo, P0, P0, C0, C0, L0, L0, 0 );
bindrule( "Exit" )->procedure =
parse_make( builtin_exit, P0, P0, C0, C0, L0, L0, 0 );
bindrule( "EXIT" )->procedure =
parse_make( builtin_exit, P0, P0, C0, C0, L0, L0, 0 );
bindrule( "Includes" )->procedure =
parse_make( builtin_depends, P0, P0, C0, C0, L0, L0, T_DEPS_INCLUDES );
bindrule( "INCLUDES" )->procedure =
parse_make( builtin_depends, P0, P0, C0, C0, L0, L0, T_DEPS_INCLUDES );
bindrule( "Leaves" )->procedure =
parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_LEAVES );
bindrule( "LEAVES" )->procedure =
parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_LEAVES );
bindrule( "NoCare" )->procedure =
parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_NOCARE );
bindrule( "NOCARE" )->procedure =
parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_NOCARE );
bindrule( "NOTIME" )->procedure =
parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_NOTFILE );
bindrule( "NotFile" )->procedure =
parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_NOTFILE );
bindrule( "NOTFILE" )->procedure =
parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_NOTFILE );
bindrule( "NoUpdate" )->procedure =
parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_NOUPDATE );
bindrule( "NOUPDATE" )->procedure =
parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_NOUPDATE );
bindrule( "Temporary" )->procedure =
parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_TEMP );
bindrule( "TEMPORARY" )->procedure =
parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_TEMP );
}
#ifdef APPLE_EXTENSIONS
void
compile_commitdeferred( parse, args )
PARSE *parse;
LOL *args;
{
if (DEBUG_COMPILE) {
printf("committing deferred assignments {\n");
}
var_commit_all_deferred_assignments();
if (DEBUG_COMPILE) {
printf("}\n");
}
}
#endif
void
compile_foreach( parse, args )
PARSE *parse;
LOL *args;
{
LIST *nv = var_list( parse->llist, args );
LIST *l;
for( l = nv; l; l = list_next( l ) )
{
LIST *val = list_new( L0, copystr( l->string ) );
var_set( parse->string, val, VAR_SET , 0 );
(*parse->left->func)( parse->left, args );
}
list_free( nv );
}
void
compile_if( parse, args )
PARSE *parse;
LOL *args;
{
if( evaluate_if( parse->left, args ) )
{
(*parse->right->left->func)( parse->right->left, args );
}
else
{
(*parse->right->right->func)( parse->right->right, args );
}
}
static int
evaluate_if( parse, args )
PARSE *parse;
LOL *args;
{
int status;
if( parse->num <= COND_OR )
{
switch( parse->num )
{
case COND_NOT:
status = !evaluate_if( parse->left, args );
break;
case COND_AND:
status = evaluate_if( parse->left, args ) &&
evaluate_if( parse->right, args );
break;
case COND_OR:
status = evaluate_if( parse->left, args ) ||
evaluate_if( parse->right, args );
break;
default:
status = 0;
}
}
else
{
LIST *nt, *ns;
nt = var_list( parse->llist, args );
ns = var_list( parse->rlist, args );
if( parse->num == COND_IN )
{
LIST *s, *t;
for( status = 1, t = nt; status && t; t = list_next( t ) )
{
int stat1;
for( stat1 = 0, s = ns; !stat1 && s; s = list_next( s ) )
stat1 = !strcmp( t->string, s->string );
status = stat1;
}
}
else
{
LIST *s = ns, *t = nt;
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;
}
}
switch( parse->num )
{
case COND_EXISTS: status = status > 0 ; break;
case COND_EQUALS: status = !status; break;
case COND_NOTEQ: status = status != 0; break;
case COND_LESS: status = status < 0; break;
case COND_LESSEQ: status = status <= 0; break;
case COND_MORE: status = status > 0; break;
case COND_MOREEQ: status = status >= 0; break;
case COND_IN: break;
}
if( DEBUG_IF )
{
debug_compile( 0, "if" );
list_print( nt );
printf( "(%d)", status );
list_print( ns );
printf( "\n" );
}
list_free( nt );
list_free( ns );
}
return status;
}
void
compile_include( parse, args )
PARSE *parse;
LOL *args;
{
LIST *nt = var_list( parse->llist, args );
if( DEBUG_COMPILE )
{
debug_compile( 0, "include" );
list_print( nt );
printf( "\n" );
}
if( nt )
{
TARGET *t = bindtarget( nt->string );
pushsettings( t->settings );
if (strcmp(t->name, "-") == 0)
{
t->boundname = "-";
t->flags |= T_FLAG_NOTFILE;
}
else
t->boundname = search( t->name, &t->time );
popsettings( t->settings );
parse_file( t->boundname );
}
list_free( nt );
}
void
compile_local( parse, args )
PARSE *parse;
LOL *args;
{
LIST *l;
SETTINGS *s = 0;
LIST *nt = var_list( parse->llist, args );
LIST *ns = var_list( parse->rlist, args );
if( DEBUG_COMPILE )
{
debug_compile( 0, "local" );
list_print( nt );
printf( " = " );
list_print( ns );
printf( "\n" );
}
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 );
pushsettings( s );
(*parse->left->func)( parse->left, args );
popsettings( s );
freesettings( s );
}
void
compile_null( parse, args )
PARSE *parse;
LOL *args;
{
}
void
compile_rule( parse, args )
PARSE *parse;
LOL *args;
{
RULE *rule = bindrule( parse->string );
LOL nargs[1];
PARSE *p;
lol_init( nargs );
for( p = parse->left; p; p = p->left )
lol_add( nargs, var_list( p->llist, args ) );
if( DEBUG_COMPILE )
{
debug_compile( 1, parse->string );
lol_print( nargs );
printf( "\n" );
}
if( !lol_get( nargs, 0 ) )
printf( "warning: no targets on rule %s %s\n",
rule->name, parse->llist ? parse->llist->string : "" );
if( !rule->actions && !rule->procedure )
printf( "warning: unknown rule %s\n", rule->name );
if( rule->actions )
{
TARGETS *t;
ACTION *action;
action = (ACTION *)malloc( sizeof( ACTION ) );
memset( (char *)action, '\0', sizeof( *action ) );
action->rule = rule;
action->targets = targetlist( (TARGETS *)0, lol_get( nargs, 0 ) );
action->sources = targetlist( (TARGETS *)0, lol_get( nargs, 1 ) );
for( t = action->targets; t; t = t->next )
t->target->actions = actionlist( t->target->actions, action );
}
if( rule->procedure )
(*rule->procedure->func)( rule->procedure, nargs );
lol_free( nargs );
if( DEBUG_COMPILE )
debug_compile( -1, 0 );
}
void
compile_vrule( parse, args )
PARSE *parse;
LOL *args;
{
LIST *nt = var_list( parse->llist, args );
LIST *l;
PARSE temp;
for( l = nt; l; l = list_next( l ) ) {
temp = *parse ;
temp.string = l->string ;
temp.llist = 0L;
compile_rule (&temp, args) ;
}
list_free( nt );
}
void
compile_rules( parse, args )
PARSE *parse;
LOL *args;
{
(*parse->left->func)( parse->left, args );
(*parse->right->func)( parse->right, args );
}
void
compile_set( parse, args )
PARSE *parse;
LOL *args;
{
LIST *nt = var_list( parse->llist, args );
LIST *ns = var_list( parse->rlist, args );
LIST *l;
int parsenum = parse->num;
int setflag;
int exportflag, deferflag;
char *trace;
exportflag = (parsenum & ASSIGN_EXPORT) ? 1 : 0;
deferflag = (parsenum & ASSIGN_DEFERRED) ? 1 : 0;
parsenum &= ~(ASSIGN_EXPORT | ASSIGN_DEFERRED);
switch( parsenum )
{
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, deferflag ? "set-deferred" : "set" );
list_print( nt );
printf( " %s ", trace );
list_print( deferflag ? parse->rlist : ns );
printf( "\n" );
}
for( l = nt; l; l = list_next( l ) )
{
if( deferflag )
var_set_deferred( l->string,
list_copy( (LIST*)0, parse->rlist ),
setflag, exportflag );
else
var_set( l->string,
list_next( l ) ? list_copy( (LIST*)0, ns ) : ns,
setflag, exportflag );
}
if( !nt )
list_free( ns );
list_free( nt );
}
void
compile_setcomp( parse, args )
PARSE *parse;
LOL *args;
{
RULE *rule = bindrule( parse->string );
if( rule->procedure )
parse_free( rule->procedure );
rule->procedure = parse->left;
parse->left = 0;
}
void
compile_setexec( parse, args )
PARSE *parse;
LOL *args;
{
RULE *rule = bindrule( parse->string );
if( rule->actions )
{
freestr( rule->actions );
list_free( rule->bindlist );
}
rule->actions = copystr( parse->string1 + (parse->string1[0] == '\n' ? 1 : 0) );
rule->bindlist = list_copy( L0, parse->llist );
rule->flags |= parse->num;
}
void
compile_settings( parse, args )
PARSE *parse;
LOL *args;
{
LIST *nt = var_list( parse->left->llist, args );
LIST *ns = var_list( parse->left->rlist, args );
LIST *targets, *ts;
int append = (parse->num & ~ASSIGN_EXPORT) == ASSIGN_APPEND;
targets = var_list( parse->llist, args );
if( DEBUG_COMPILE )
{
debug_compile( 0, "set" );
list_print( nt );
printf( "on " );
list_print( targets );
printf( " %s ", append ? "+=" : "=" );
list_print( ns );
printf( "\n" );
}
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( ns );
list_free( nt );
list_free( targets );
}
void
compile_switch( parse, args )
PARSE *parse;
LOL *args;
{
LIST *nt;
nt = var_list( parse->llist, args );
if( DEBUG_COMPILE )
{
debug_compile( 0, "switch" );
list_print( nt );
printf( "\n" );
}
for( parse = parse->left; parse; parse = parse->right )
{
if( !jam_glob( parse->left->string, nt ? nt->string : "" ) )
{
parse = parse->left->left;
(*parse->func)( parse, args );
break;
}
}
list_free( nt );
}
static void
builtin_depends( parse, args )
PARSE *parse;
LOL *args;
{
LIST *targets = lol_get( args, 0 );
LIST *sources = lol_get( args, 1 );
int which = parse->num;
LIST *l;
for( l = targets; l; l = list_next( l ) )
{
TARGET *t = bindtarget( l->string );
t->deps[ which ] = targetlist( t->deps[ which ], sources );
}
}
static void
builtin_echo( parse, args )
PARSE *parse;
LOL *args;
{
list_print( lol_get( args, 0 ) );
printf( "\n" );
}
static void
builtin_exit( parse, args )
PARSE *parse;
LOL *args;
{
list_print( lol_get( args, 0 ) );
printf( "\n" );
exit( EXITBAD );
}
static void
builtin_flags( parse, args )
PARSE *parse;
LOL *args;
{
LIST *l = lol_get( args, 0 );
for( ; l; l = list_next( l ) )
bindtarget( l->string )->flags |= parse->num;
}
static void
debug_compile( which, s )
int which;
char *s;
{
static int level = 0;
static char indent[36] = ">>>>|>>>>|>>>>|>>>>|>>>>|>>>>|>>>>|";
int i = ((1+level) * 2) % 35;
if( which >= 0 )
printf( "%*.*s ", i, i, indent );
if( s )
printf( "%s ", s );
level += which;
}