1/*
2 * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
3 *
4 * This file is part of Jam - see jam.c for Copyright information.
5 */
6
7/*
8 * compile.c - compile parsed jam statements
9 *
10 * External routines:
11 *
12 *	compile_append() - append list results of two statements
13 *	compile_break() - compile 'break/continue/return' rule
14 *	compile_eval() - evaluate if to determine which leg to compile
15 *	compile_foreach() - compile the "for x in y" statement
16 *	compile_if() - compile 'if' rule
17 *	compile_include() - support for 'include' - call include() on file
18 *	compile_list() - expand and return a list
19 *	compile_local() - declare (and set) local variables
20 *	compile_null() - do nothing -- a stub for parsing
21 *	compile_on() - run rule under influence of on-target variables
22 *	compile_rule() - compile a single user defined rule
23 *	compile_rules() - compile a chain of rules
24 *	compile_set() - compile the "set variable" statement
25 *	compile_setcomp() - support for `rule` - save parse tree
26 *	compile_setexec() - support for `actions` - save execution string
27 *	compile_settings() - compile the "on =" (set variable on exec) statement
28 *	compile_switch() - compile 'switch' rule
29 *
30 * Internal routines:
31 *
32 *	debug_compile() - printf with indent to show rule expansion.
33 *	evaluate_rule() - execute a rule invocation
34 *
35 * 02/03/94 (seiwald) -	Changed trace output to read "setting" instead of
36 *			the awkward sounding "settings".
37 * 04/12/94 (seiwald) - Combined build_depends() with build_includes().
38 * 04/12/94 (seiwald) - actionlist() now just appends a single action.
39 * 04/13/94 (seiwald) - added shorthand L0 for null list pointer
40 * 05/13/94 (seiwald) - include files are now bound as targets, and thus
41 *			can make use of $(SEARCH)
42 * 06/01/94 (seiwald) - new 'actions existing' does existing sources
43 * 08/23/94 (seiwald) - Support for '+=' (append to variable)
44 * 12/20/94 (seiwald) - NOTIME renamed NOTFILE.
45 * 01/22/95 (seiwald) - Exit rule.
46 * 02/02/95 (seiwald) - Always rule; LEAVES rule.
47 * 02/14/95 (seiwald) - NoUpdate rule.
48 * 01/20/00 (seiwald) - Upgraded from K&R to ANSI C
49 * 09/07/00 (seiwald) - stop crashing when a rule redefines itself
50 * 09/11/00 (seiwald) - new evaluate_rule() for headers().
51 * 09/11/00 (seiwald) - rules now return values, accessed via [ rule arg ... ]
52 * 09/12/00 (seiwald) - don't complain about rules invoked without targets
53 * 01/13/01 (seiwald) - fix case where rule is defined within another
54 * 01/10/01 (seiwald) - built-ins split out to builtin.c.
55 * 01/11/01 (seiwald) - optimize compile_rules() for tail recursion
56 * 01/21/01 (seiwald) - replace evaluate_if() with compile_eval()
57 * 01/24/01 (seiwald) - 'while' statement
58 * 03/23/01 (seiwald) - "[ on target rule ]" support
59 * 02/28/02 (seiwald) - merge EXEC_xxx flags in with RULE_xxx
60 * 03/02/02 (seiwald) - rules can be invoked via variable names
61 * 03/12/02 (seiwald) - &&,&,||,|,in now short-circuit again
62 * 03/25/02 (seiwald) - if ( "" a b ) one again returns true
63 * 06/21/02 (seiwald) - support for named parameters
64 * 10/22/02 (seiwald) - list_new() now does its own newstr()/copystr()
65 * 10/22/02 (seiwald) - working return/break/continue statements
66 * 11/04/02 (seiwald) - const-ing for string literals
67 * 11/18/02 (seiwald) - remove bogus search() in 'on' statement.
68 * 12/17/02 (seiwald) - new copysettings() to protect target-specific vars
69 */
70
71# ifdef OPT_RULE_PROFILING_EXT
72# include <sys/time.h>
73# endif
74
75# include "jam.h"
76
77# include "lists.h"
78# include "parse.h"
79# include "compile.h"
80# include "variable.h"
81# include "expand.h"
82# include "rules.h"
83# include "newstr.h"
84# include "search.h"
85
86static const char *set_names[] = { "=", "+=", "?=" };
87static void debug_compile( int which, const char *s );
88int glob( const char *s, const char *c );
89
90
91
92/*
93 * compile_append() - append list results of two statements
94 *
95 *	parse->left	more compile_append() by left-recursion
96 *	parse->right	single rule
97 */
98
99LIST *
100compile_append(
101	PARSE	*parse,
102	LOL	*args,
103	int	*jmp )
104{
105	/* Append right to left. */
106
107	return list_append(
108		(*parse->left->func)( parse->left, args, jmp ),
109		(*parse->right->func)( parse->right, args, jmp ) );
110}
111
112/*
113 * compile_break() - compile 'break/continue/return' rule
114 *
115 *	parse->left	results
116 *	parse->num	JMP_BREAK/CONTINUE/RETURN
117 */
118
119LIST *
120compile_break(
121	PARSE	*parse,
122	LOL	*args,
123	int	*jmp )
124{
125	LIST *lv = (*parse->left->func)( parse->left, args, jmp );
126	*jmp = parse->num;
127	return lv;
128}
129
130/*
131 * compile_eval() - evaluate if to determine which leg to compile
132 *
133 * Returns:
134 *	list 	if expression true - compile 'then' clause
135 *	L0	if expression false - compile 'else' clause
136 */
137
138static int
139lcmp( LIST *t, LIST *s )
140{
141	int status = 0;
142
143	while( !status && ( t || s ) )
144	{
145	    const char *st = t ? t->string : "";
146	    const char *ss = s ? s->string : "";
147
148	    status = strcmp( st, ss );
149
150	    t = t ? list_next( t ) : t;
151	    s = s ? list_next( s ) : s;
152	}
153
154	return status;
155}
156
157LIST *
158compile_eval(
159	PARSE	*parse,
160	LOL	*args,
161	int	*jmp )
162{
163	LIST *ll, *lr, *s, *t;
164	int status = 0;
165
166	/* Short circuit lr eval for &&, ||, and 'in' */
167
168	ll = (*parse->left->func)( parse->left, args, jmp );
169	lr = 0;
170
171	switch( parse->num )
172	{
173	case EXPR_AND:
174	case EXPR_IN: 	if( ll ) goto eval; break;
175	case EXPR_OR: 	if( !ll ) goto eval; break;
176	default: eval: 	lr = (*parse->right->func)( parse->right, args, jmp );
177	}
178
179	/* Now eval */
180
181	switch( parse->num )
182	{
183	case EXPR_NOT:
184		if( !ll ) status = 1;
185		break;
186
187	case EXPR_AND:
188		if( ll && lr ) status = 1;
189		break;
190
191	case EXPR_OR:
192		if( ll || lr ) status = 1;
193		break;
194
195	case EXPR_IN:
196		/* "a in b": make sure each of */
197		/* ll is equal to something in lr. */
198
199		for( t = ll; t; t = list_next( t ) )
200		{
201		    for( s = lr; s; s = list_next( s ) )
202			if( !strcmp( t->string, s->string ) )
203			    break;
204		    if( !s ) break;
205		}
206
207		/* No more ll? Success */
208
209		if( !t ) status = 1;
210
211		break;
212
213	case EXPR_EXISTS:       if( lcmp( ll, L0 ) != 0 ) status = 1; break;
214	case EXPR_EQUALS:	if( lcmp( ll, lr ) == 0 ) status = 1; break;
215	case EXPR_NOTEQ:	if( lcmp( ll, lr ) != 0 ) status = 1; break;
216	case EXPR_LESS:		if( lcmp( ll, lr ) < 0  ) status = 1; break;
217	case EXPR_LESSEQ:	if( lcmp( ll, lr ) <= 0 ) status = 1; break;
218	case EXPR_MORE:		if( lcmp( ll, lr ) > 0  ) status = 1; break;
219	case EXPR_MOREEQ:	if( lcmp( ll, lr ) >= 0 ) status = 1; break;
220
221	}
222
223	if( DEBUG_IF )
224	{
225	    debug_compile( 0, "if" );
226	    list_print( ll );
227	    printf( "(%d) ", status );
228	    list_print( lr );
229	    printf( "\n" );
230	}
231
232	/* Find something to return. */
233	/* In odd circumstances (like "" = "") */
234	/* we'll have to return a new string. */
235
236	if( !status ) t = 0;
237	else if( ll ) t = ll, ll = 0;
238	else if( lr ) t = lr, lr = 0;
239	else t = list_new( L0, "1", 0 );
240
241	if( ll ) list_free( ll );
242	if( lr ) list_free( lr );
243	return t;
244}
245
246/*
247 * compile_foreach() - compile the "for x in y" statement
248 *
249 * Compile_foreach() resets the given variable name to each specified
250 * value, executing the commands enclosed in braces for each iteration.
251 *
252 *	parse->string	index variable
253 *	parse->left	variable values
254 *	parse->right	rule to compile
255 */
256
257LIST *
258compile_foreach(
259	PARSE	*p,
260	LOL	*args,
261	int	*jmp )
262{
263	LIST	*nv = (*p->left->func)( p->left, args, jmp );
264	LIST	*result = 0;
265	LIST	*l;
266
267	/* for each value for var */
268
269	for( l = nv; l && *jmp == JMP_NONE; l = list_next( l ) )
270	{
271	    /* Reset $(p->string) for each val. */
272
273	    var_set( p->string, list_new( L0, l->string, 1 ), VAR_SET );
274
275	    /* Keep only last result. */
276
277	    list_free( result );
278	    result = (*p->right->func)( p->right, args, jmp );
279
280	    /* continue loop? */
281
282	    if( *jmp == JMP_CONTINUE )
283		*jmp = JMP_NONE;
284	}
285
286	/* Here by break/continue? */
287
288	if( *jmp == JMP_BREAK || *jmp == JMP_CONTINUE )
289	    *jmp = JMP_NONE;
290
291	list_free( nv );
292
293	/* Returns result of last loop */
294
295	return result;
296}
297
298/*
299 * compile_if() - compile 'if' rule
300 *
301 *	parse->left		condition tree
302 *	parse->right		then tree
303 *	parse->third		else tree
304 */
305
306LIST *
307compile_if(
308	PARSE	*p,
309	LOL	*args,
310	int	*jmp )
311{
312	LIST *l = (*p->left->func)( p->left, args, jmp );
313
314	p = l ? p->right : p->third;
315
316	list_free( l );
317
318	return (*p->func)( p, args, jmp );
319}
320
321/*
322 * compile_include() - support for 'include' - call include() on file
323 *
324 * 	parse->left	list of files to include (can only do 1)
325 */
326
327LIST *
328compile_include(
329	PARSE	*parse,
330	LOL	*args,
331	int	*jmp )
332{
333	LIST	*nt = (*parse->left->func)( parse->left, args, jmp );
334
335	if( DEBUG_COMPILE )
336	{
337	    debug_compile( 0, "include" );
338	    list_print( nt );
339	    printf( "\n" );
340	}
341
342	if( nt )
343	{
344	    TARGET *t = bindtarget( nt->string );
345
346	    /* Bind the include file under the influence of */
347	    /* "on-target" variables.  Though they are targets, */
348	    /* include files are not built with make(). */
349	    /* Needn't copysettings(), as search sets no vars. */
350
351	    pushsettings( t->settings );
352	    t->boundname = search( t->name, &t->time );
353	    popsettings( t->settings );
354
355	    /* Don't parse missing file if NOCARE set */
356
357	    if( t->time || !( t->flags & T_FLAG_NOCARE ) )
358		parse_file( t->boundname );
359	}
360
361	list_free( nt );
362
363	return L0;
364}
365
366/*
367 * compile_list() - expand and return a list
368 *
369 * 	parse->string - character string to expand
370 */
371
372LIST *
373compile_list(
374	PARSE	*parse,
375	LOL	*args,
376	int	*jmp )
377{
378	/* voodoo 1 means: s is a copyable string */
379	const char *s = parse->string;
380	return var_expand( L0, s, s + strlen( s ), args, 1 );
381}
382
383/*
384 * compile_local() - declare (and set) local variables
385 *
386 *	parse->left	list of variables
387 *	parse->right	list of values
388 *	parse->third	rules to execute
389 */
390
391LIST *
392compile_local(
393	PARSE	*parse,
394	LOL	*args,
395	int	*jmp )
396{
397	LIST *l;
398	SETTINGS *s = 0;
399	LIST	*nt = (*parse->left->func)( parse->left, args, jmp );
400	LIST	*ns = (*parse->right->func)( parse->right, args, jmp );
401	LIST	*result;
402
403	if( DEBUG_COMPILE )
404	{
405	    debug_compile( 0, "local" );
406	    list_print( nt );
407	    printf( " = " );
408	    list_print( ns );
409	    printf( "\n" );
410	}
411
412	/* Initial value is ns */
413
414	for( l = nt; l; l = list_next( l ) )
415	    s = addsettings( s, 0, l->string, list_copy( (LIST*)0, ns ) );
416
417	list_free( ns );
418	list_free( nt );
419
420	/* Note that callees of the current context get this "local" */
421	/* variable, making it not so much local as layered. */
422
423	pushsettings( s );
424	result = (*parse->third->func)( parse->third, args, jmp );
425	popsettings( s );
426	freesettings( s );
427
428	return result;
429}
430
431/*
432 * compile_null() - do nothing -- a stub for parsing
433 */
434
435LIST *
436compile_null(
437	PARSE	*parse,
438	LOL	*args,
439	int	*jmp )
440{
441	return L0;
442}
443
444/*
445 * compile_on() - run rule under influence of on-target variables
446 *
447 * 	parse->left	target list; only first used
448 *	parse->right	rule to run
449 */
450
451LIST *
452compile_on(
453	PARSE	*parse,
454	LOL	*args,
455	int	*jmp )
456{
457	LIST	*nt = (*parse->left->func)( parse->left, args, jmp );
458	LIST	*result = 0;
459
460	if( DEBUG_COMPILE )
461	{
462	    debug_compile( 0, "on" );
463	    list_print( nt );
464	    printf( "\n" );
465	}
466
467	/*
468	 * Copy settings, so that 'on target var on target = val'
469	 * doesn't set var globally.
470	 */
471
472	if( nt )
473	{
474	    TARGET *t = bindtarget( nt->string );
475	    SETTINGS *s = copysettings( t->settings );
476
477	    pushsettings( s );
478	    result = (*parse->right->func)( parse->right, args, jmp );
479	    popsettings( s );
480	    freesettings( s );
481	}
482
483	list_free( nt );
484
485	return result;
486}
487
488/*
489 * compile_rule() - compile a single user defined rule
490 *
491 *	parse->left	list of rules to run
492 *	parse->right	parameters (list of lists) to rule, recursing left
493 *
494 * Wrapped around evaluate_rule() so that headers() can share it.
495 */
496
497LIST *
498compile_rule(
499	PARSE	*parse,
500	LOL	*args,
501	int	*jmp )
502{
503	LOL	nargs[1];
504	LIST	*result = 0;
505	LIST	*ll, *l;
506	PARSE	*p;
507
508	/* list of rules to run -- normally 1! */
509
510	ll = (*parse->left->func)( parse->left, args, jmp );
511
512	/* Build up the list of arg lists */
513
514	lol_init( nargs );
515
516	for( p = parse->right; p; p = p->left )
517	    lol_add( nargs, (*p->right->func)( p->right, args, jmp ) );
518
519	/* Run rules, appending results from each */
520
521	for( l = ll; l; l = list_next( l ) )
522	{
523	    int localJmp = JMP_NONE;
524	    result = evaluate_rule( l->string, nargs, result, &localJmp );
525	    if (localJmp == JMP_EOF)
526	    {
527			*jmp = JMP_EOF;
528			break;
529	    }
530	}
531
532	list_free( ll );
533	lol_free( nargs );
534
535	return result;
536}
537
538/*
539 * evaluate_rule() - execute a rule invocation
540 */
541
542LIST *
543evaluate_rule(
544	const char *rulename,
545	LOL	*args,
546	LIST	*result,
547	int	*jmp )
548{
549	RULE	*rule = bindrule( rulename );
550
551	if( DEBUG_COMPILE )
552	{
553	    debug_compile( 1, rulename );
554	    lol_print( args );
555	    printf( "\n" );
556	}
557
558	/* Check traditional targets $(<) and sources $(>) */
559
560	if( !rule->actions && !rule->procedure )
561	    printf( "warning: unknown rule %s\n", rule->name );
562
563	/* If this rule will be executed for updating the targets */
564	/* then construct the action for make(). */
565
566	if( rule->actions )
567	{
568	    TARGETS	*t;
569	    ACTION	*action;
570
571	    /* The action is associated with this instance of this rule */
572
573	    action = (ACTION *)malloc( sizeof( ACTION ) );
574	    memset( (char *)action, '\0', sizeof( *action ) );
575
576	    action->rule = rule;
577	    action->targets = targetlist( (TARGETS *)0, lol_get( args, 0 ) );
578	    action->sources = targetlist( (TARGETS *)0, lol_get( args, 1 ) );
579
580	    /* Make targets[1,N-1] depend on targets[0], to describe the */
581	    /* generated targets for the rule. Do it with includes, to */
582	    /* reflect non-build dependency. */
583
584	    if( action->targets )
585	    {
586	    	TARGET *t0 = action->targets->target;
587	    	for( t = action->targets->next; t; t = t->next )
588	    	{
589	    		TARGET *tn = t->target;
590	    		if( !tn->includes )
591	    		{
592	    			tn->includes = copytarget( tn );
593	    		}
594	    		tn = tn->includes;
595	    		tn->depends = targetentry( tn->depends, t0 );
596	    	}
597	    }
598
599	    /* Append this action to the actions of each target */
600
601	    for( t = action->targets; t; t = t->next )
602		t->target->actions = actionlist( t->target->actions, action );
603	}
604
605	/* Now recursively compile any parse tree associated with this rule */
606
607	if( rule->procedure )
608	{
609	    PARSE *parse = rule->procedure;
610	    SETTINGS *s = 0;
611	    LIST *l;
612	    int i;
613
614# ifdef OPT_RULE_PROFILING_EXT
615		struct timeval startTime, endTime;
616
617		if ( DEBUG_PROFILE_RULES )
618			gettimeofday(&startTime, 0);
619# endif
620
621	    /* build parameters as local vars */
622
623	    for( l = rule->params, i = 0; l; l = l->next, i++ )
624		s = addsettings( s, 0, l->string,
625		    list_copy( L0, lol_get( args, i ) ) );
626
627	    /* Run rule. */
628	    /* Bring in local params. */
629	    /* refer/free to ensure rule not freed during use. */
630
631	    parse_refer( parse );
632
633	    pushsettings( s );
634	    result = list_append( result, (*parse->func)( parse, args, jmp ) );
635	    popsettings( s );
636	    freesettings( s );
637
638	    parse_free( parse );
639
640# ifdef OPT_RULE_PROFILING_EXT
641		if ( DEBUG_PROFILE_RULES )
642		{
643			gettimeofday(&endTime, 0);
644
645			rule->invocations++;
646			rule->invocation_time
647				+= (endTime.tv_sec - startTime.tv_sec) * (int64_t)1000000
648					+ (endTime.tv_usec - startTime.tv_usec);
649		}
650# endif
651
652	}
653
654	if( DEBUG_COMPILE )
655	    debug_compile( -1, 0 );
656
657	return result;
658}
659
660/*
661 * compile_rules() - compile a chain of rules
662 *
663 *	parse->left	single rule
664 *	parse->right	more compile_rules() by right-recursion
665 */
666
667LIST *
668compile_rules(
669	PARSE	*parse,
670	LOL	*args,
671	int	*jmp )
672{
673	/* Ignore result from first statement; return the 2nd. */
674	/* Optimize recursion on the right by looping. */
675
676	LIST 	*result = 0;
677
678	while( *jmp == JMP_NONE && parse->func == compile_rules )
679	{
680	    list_free( result );
681	    result = (*parse->left->func)( parse->left, args, jmp );
682	    parse = parse->right;
683	}
684
685	if( *jmp == JMP_NONE )
686	{
687	    list_free( result );
688	    result = (*parse->func)( parse, args, jmp );
689	}
690
691	return result;
692}
693
694/*
695 * compile_set() - compile the "set variable" statement
696 *
697 *	parse->left	variable names
698 *	parse->right	variable values
699 *	parse->num	VAR_SET/APPEND/DEFAULT
700 */
701
702LIST *
703compile_set(
704	PARSE	*parse,
705	LOL	*args,
706	int	*jmp )
707{
708	LIST	*nt = (*parse->left->func)( parse->left, args, jmp );
709	LIST	*ns = (*parse->right->func)( parse->right, args, jmp );
710	LIST	*l;
711
712	if( DEBUG_COMPILE )
713	{
714	    debug_compile( 0, "set" );
715	    list_print( nt );
716	    printf( " %s ", set_names[ parse->num ] );
717	    list_print( ns );
718	    printf( "\n" );
719	}
720
721	/* Call var_set to set variable */
722	/* var_set keeps ns, so need to copy it */
723
724	for( l = nt; l; l = list_next( l ) )
725	    var_set( l->string, list_copy( L0, ns ), parse->num );
726
727	list_free( nt );
728
729	return ns;
730}
731
732/*
733 * compile_setcomp() - support for `rule` - save parse tree
734 *
735 *	parse->string	rule name
736 *	parse->left	list of argument names
737 *	parse->right	rules for rule
738 */
739
740LIST *
741compile_setcomp(
742	PARSE	*parse,
743	LOL	*args,
744	int	*jmp )
745{
746	RULE	*rule = bindrule( parse->string );
747	LIST	*params = 0;
748	PARSE	*p;
749
750	/* Build param list */
751
752	for( p = parse->left; p; p = p->left )
753	    params = list_new( params, p->string, 1 );
754
755	if( DEBUG_COMPILE )
756	{
757	    debug_compile( 0, "rule" );
758	    printf( "%s ", parse->string );
759	    list_print( params );
760	    printf( "\n" );
761	}
762
763	/* Free old one, if present */
764
765	if( rule->procedure )
766	    parse_free( rule->procedure );
767
768	if( rule->params )
769	    list_free( rule->params );
770
771	rule->procedure = parse->right;
772	rule->params = params;
773
774	/* we now own this parse tree */
775	/* don't let parse_free() release it */
776
777	parse_refer( parse->right );
778
779	return L0;
780}
781
782/*
783 * compile_setexec() - support for `actions` - save execution string
784 *
785 *	parse->string	rule name
786 *	parse->string1	OS command string
787 *	parse->num	flags
788 *	parse->left	`bind` variables
789 *
790 * Note that the parse flags (as defined in compile.h) are transfered
791 * directly to the rule flags (as defined in rules.h).
792 */
793
794LIST *
795compile_setexec(
796	PARSE	*parse,
797	LOL	*args,
798	int	*jmp )
799{
800	RULE	*rule = bindrule( parse->string );
801	LIST	*bindlist = (*parse->left->func)( parse->left, args, jmp );
802
803	/* Free old one, if present */
804
805	if( rule->actions )
806	{
807	    freestr( rule->actions );
808	    list_free( rule->bindlist );
809	}
810
811	rule->actions = copystr( parse->string1 );
812	rule->bindlist = bindlist;
813	rule->flags = parse->num;
814
815	return L0;
816}
817
818/*
819 * compile_settings() - compile the "on =" (set variable on exec) statement
820 *
821 *	parse->left	variable names
822 *	parse->right	target name
823 *	parse->third	variable value
824 *	parse->num	VAR_SET/APPEND/DEFAULT
825 */
826
827LIST *
828compile_settings(
829	PARSE	*parse,
830	LOL	*args,
831	int	*jmp )
832{
833	LIST	*nt = (*parse->left->func)( parse->left, args, jmp );
834	LIST	*ns = (*parse->third->func)( parse->third, args, jmp );
835	LIST	*targets = (*parse->right->func)( parse->right, args, jmp );
836	LIST	*ts;
837
838	if( DEBUG_COMPILE )
839	{
840	    debug_compile( 0, "set" );
841	    list_print( nt );
842	    printf( "on " );
843	    list_print( targets );
844	    printf( " %s ", set_names[ parse->num ] );
845	    list_print( ns );
846	    printf( "\n" );
847	}
848
849	/* Call addsettings to save variable setting */
850	/* addsettings keeps ns, so need to copy it */
851	/* Pass append flag to addsettings() */
852
853	for( ts = targets; ts; ts = list_next( ts ) )
854	{
855	    TARGET 	*t = bindtarget( ts->string );
856	    LIST	*l;
857
858	    for( l = nt; l; l = list_next( l ) )
859		t->settings = addsettings( t->settings, parse->num,
860				l->string, list_copy( (LIST*)0, ns ) );
861	}
862
863	list_free( nt );
864	list_free( targets );
865
866	return ns;
867}
868
869/*
870 * compile_switch() - compile 'switch' rule
871 *
872 *	parse->left	switch value (only 1st used)
873 *	parse->right	cases
874 *
875 *	cases->left	1st case
876 *	cases->right	next cases
877 *
878 *	case->string	argument to match
879 *	case->left	parse tree to execute
880 */
881
882LIST *
883compile_switch(
884	PARSE	*parse,
885	LOL	*args,
886	int	*jmp )
887{
888	LIST	*nt = (*parse->left->func)( parse->left, args, jmp );
889	LIST	*result = 0;
890
891	if( DEBUG_COMPILE )
892	{
893	    debug_compile( 0, "switch" );
894	    list_print( nt );
895	    printf( "\n" );
896	}
897
898	/* Step through cases */
899
900	for( parse = parse->right; parse; parse = parse->right )
901	{
902	    if( !glob( parse->left->string, nt ? nt->string : "" ) )
903	    {
904		/* Get & exec parse tree for this case */
905		parse = parse->left->left;
906		result = (*parse->func)( parse, args, jmp );
907		break;
908	    }
909	}
910
911	list_free( nt );
912
913	return result;
914}
915
916/*
917 * compile_while() - compile 'while' rule
918 *
919 *	parse->left		condition tree
920 *	parse->right		execution tree
921 */
922
923LIST *
924compile_while(
925	PARSE	*p,
926	LOL	*args,
927	int	*jmp )
928{
929	LIST *result = 0;
930	LIST *l;
931
932	/* Returns the value from the last execution of the block */
933
934	while( ( *jmp == JMP_NONE ) &&
935	       ( l = (*p->left->func)( p->left, args, jmp ) ) )
936	{
937	    /* Always toss while's expression */
938
939	    list_free( l );
940
941	    /* Keep only last result. */
942
943	    list_free( result );
944	    result = (*p->right->func)( p->right, args, jmp );
945
946	    /* continue loop? */
947
948	    if( *jmp == JMP_CONTINUE )
949		*jmp = JMP_NONE;
950	}
951
952	/* Here by break/continue? */
953
954	if( *jmp == JMP_BREAK || *jmp == JMP_CONTINUE )
955	    *jmp = JMP_NONE;
956
957	/* Returns result of last loop */
958
959	return result;
960}
961
962/*
963 * debug_compile() - printf with indent to show rule expansion.
964 */
965
966static void
967debug_compile( int which, const char *s )
968{
969	static int level = 0;
970	static char indent[36] = ">>>>|>>>>|>>>>|>>>>|>>>>|>>>>|>>>>|";
971	int i = ((1+level) * 2) % 35;
972
973	if( which >= 0 )
974	    printf( "%*.*s ", i, i, indent );
975
976	if( s )
977	    printf( "%s ", s );
978
979	level += which;
980}
981