fixed bug in debug dump for assign
[k8jam.git] / src / compile.c
blobd376cbb5e30be8acabfebbb31e3b908aa89b7f11
1 /*
2 * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
4 * This file is part of Jam - see jam.c for Copyright information.
5 */
6 /*
7 * compile.c - compile parsed jam statements
9 * External routines:
11 * compile_append() - append list results of two statements
12 * compile_break() - compile 'break/continue/return' rule
13 * compile_eval() - evaluate if to determine which leg to compile
14 * compile_foreach() - compile the "for x in y" statement
15 * compile_if() - compile 'if' rule
16 * compile_include() - support for 'include' - call include() on file
17 * compile_list() - expand and return a list
18 * compile_local() - declare (and set) local variables
19 * compile_null() - do nothing -- a stub for parsing
20 * compile_on() - run rule under influence of on-target variables
21 * compile_rule() - compile a single user defined rule
22 * compile_rules() - compile a chain of rules
23 * compile_set() - compile the "set variable" statement
24 * compile_setcomp() - support for `rule` - save parse tree
25 * compile_setexec() - support for `actions` - save execution string
26 * compile_settings() - compile the "on =" (set variable on exec) statement
27 * compile_switch() - compile 'switch' rule
29 * Internal routines:
31 * debug_compile() - printf with indent to show rule expansion.
32 * evaluate_rule() - execute a rule invocation
34 * 02/03/94 (seiwald) - Changed trace output to read "setting" instead of
35 * the awkward sounding "settings".
36 * 04/12/94 (seiwald) - Combined build_depends() with build_includes().
37 * 04/12/94 (seiwald) - actionlist() now just appends a single action.
38 * 04/13/94 (seiwald) - added shorthand L0 for null list pointer
39 * 05/13/94 (seiwald) - include files are now bound as targets, and thus
40 * can make use of $(SEARCH)
41 * 06/01/94 (seiwald) - new 'actions existing' does existing sources
42 * 08/23/94 (seiwald) - Support for '+=' (append to variable)
43 * 12/20/94 (seiwald) - NOTIME renamed NOTFILE.
44 * 01/22/95 (seiwald) - Exit rule.
45 * 02/02/95 (seiwald) - Always rule; LEAVES rule.
46 * 02/14/95 (seiwald) - NoUpdate rule.
47 * 01/20/00 (seiwald) - Upgraded from K&R to ANSI C
48 * 09/07/00 (seiwald) - stop crashing when a rule redefines itself
49 * 09/11/00 (seiwald) - new evaluate_rule() for headers().
50 * 09/11/00 (seiwald) - rules now return values, accessed via [ rule arg ... ]
51 * 09/12/00 (seiwald) - don't complain about rules invoked without targets
52 * 01/13/01 (seiwald) - fix case where rule is defined within another
53 * 01/10/01 (seiwald) - built-ins split out to builtin.c.
54 * 01/11/01 (seiwald) - optimize compile_rules() for tail recursion
55 * 01/21/01 (seiwald) - replace evaluate_if() with compile_eval()
56 * 01/24/01 (seiwald) - 'while' statement
57 * 03/23/01 (seiwald) - "[ on target rule ]" support
58 * 02/28/02 (seiwald) - merge EXEC_xxx flags in with RULE_xxx
59 * 03/02/02 (seiwald) - rules can be invoked via variable names
60 * 03/12/02 (seiwald) - &&,&,||,|,in now short-circuit again
61 * 03/25/02 (seiwald) - if ( "" a b ) one again returns true
62 * 06/21/02 (seiwald) - support for named parameters
63 * 10/22/02 (seiwald) - list_new() now does its own newstr()/copystr()
64 * 10/22/02 (seiwald) - working return/break/continue statements
65 * 11/04/02 (seiwald) - const-ing for string literals
66 * 11/18/02 (seiwald) - remove bogus search() in 'on' statement.
67 * 12/17/02 (seiwald) - new copysettings() to protect target-specific vars
69 #include "jam.h"
71 #include "lists.h"
72 #include "parse.h"
73 #include "compile.h"
74 #include "variable.h"
75 #include "expand.h"
76 #include "rules.h"
77 #include "newstr.h"
78 #include "search.h"
81 static const char *set_names[] = { "=", "+=", "-=", "?=" };
82 static void debug_compile (int which, const char *s);
83 int glob (const char *s, const char *c);
87 * compile_append() - append list results of two statements
89 * parse->left more compile_append() by left-recursion
90 * parse->right single rule
92 LIST *compile_append (PARSE *parse, LOL *args, int *jmp) {
93 /* Append right to left. */
94 return list_append(
95 (*parse->left->func)(parse->left, args, jmp),
96 (*parse->right->func)(parse->right, args, jmp));
101 * compile_break() - compile 'break/continue/return' rule
103 * parse->left results
104 * parse->num JMP_BREAK/CONTINUE/RETURN
106 LIST *compile_break (PARSE *parse, LOL *args, int *jmp) {
107 LIST *lv = (*parse->left->func)(parse->left, args, jmp);
108 *jmp = parse->num;
109 return lv;
114 * compile_eval() - evaluate if to determine which leg to compile
116 * Returns:
117 * list if expression true - compile 'then' clause
118 * L0 if expression false - compile 'else' clause
120 static int lcmp (LIST *t, LIST *s) {
121 int status = 0;
123 while (!status && (t || s)) {
124 const char *st = t?t->string:"";
125 const char *ss = s?s->string:"";
127 status = strcmp(st, ss);
128 t = t?list_next(t):t;
129 s = s?list_next(s):s;
132 return status;
136 LIST *compile_eval (PARSE *parse, LOL *args, int *jmp) {
137 LIST *ll, *lr, *s, *t;
138 int status = 0;
140 /* Short circuit lr eval for &&, ||, and 'in' */
141 ll = (*parse->left->func)(parse->left, args, jmp);
142 lr = 0;
144 switch (parse->num) {
145 case EXPR_AND: case EXPR_IN:
146 if (ll) goto eval;
147 break;
148 case EXPR_OR:
149 if (!ll) goto eval;
150 break;
151 default:
152 eval:
153 lr = (*parse->right->func)(parse->right, args, jmp);
156 /* Now eval */
157 switch ( parse->num) {
158 case EXPR_NOT:
159 if (!ll) status = 1;
160 break;
161 case EXPR_AND:
162 if (ll && lr) status = 1;
163 break;
164 case EXPR_OR:
165 if (ll || lr) status = 1;
166 break;
167 case EXPR_IN:
168 /* "a in b": make sure each of */
169 /* ll is equal to something in lr. */
170 for (t = ll; t; t = list_next(t)) {
171 for (s = lr; s; s = list_next(s)) if (!strcmp(t->string, s->string)) break;
172 if (!s) break;
174 /* No more ll? Success */
175 if (!t) status = 1;
176 break;
177 case EXPR_EXISTS:
178 if (lcmp(ll, L0) != 0) status = 1;
179 break;
180 case EXPR_EQUALS:
181 if (lcmp(ll, lr) == 0) status = 1;
182 break;
183 case EXPR_NOTEQ:
184 if (lcmp(ll, lr) != 0) status = 1;
185 break;
186 case EXPR_LESS:
187 if (lcmp(ll, lr) < 0) status = 1;
188 break;
189 case EXPR_LESSEQ:
190 if (lcmp(ll, lr) <= 0) status = 1;
191 break;
192 case EXPR_MORE:
193 if (lcmp(ll, lr) > 0) status = 1;
194 break;
195 case EXPR_MOREEQ:
196 if (lcmp(ll, lr) >= 0) status = 1;
197 break;
200 if (DEBUG_IF) {
201 debug_compile(0, "if");
202 list_print(ll);
203 printf("(%d) ", status);
204 list_print(lr);
205 printf("\n");
208 /* Find something to return. */
209 /* In odd circumstances (like "" = "") */
210 /* we'll have to return a new string. */
211 if (!status) t = 0;
212 else if (ll) t = ll, ll = 0;
213 else if (lr) t = lr, lr = 0;
214 else t = list_new(L0, "1", 0);
216 if (ll) list_free(ll);
217 if (lr) list_free(lr);
219 return t;
224 * compile_foreach() - compile the "for x in y" statement
226 * Compile_foreach() resets the given variable name to each specified
227 * value, executing the commands enclosed in braces for each iteration.
229 * parse->string index variable
230 * parse->left variable values
231 * parse->right rule to compile
233 LIST *compile_foreach (PARSE *p, LOL *args, int *jmp) {
234 LIST *nv = (*p->left->func)(p->left, args, jmp);
235 LIST *result = 0;
236 LIST *l;
238 /* for each value for var */
239 for (l = nv; l && *jmp == JMP_NONE; l = list_next(l)) {
240 /* Reset $(p->string) for each val. */
241 var_set(p->string, list_new(L0, l->string, 1), VAR_SET);
242 /* Keep only last result. */
243 list_free(result);
244 result = (*p->right->func)(p->right, args, jmp);
245 /* continue loop? */
246 if (*jmp == JMP_CONTINUE) *jmp = JMP_NONE;
248 /* Here by break/continue? */
249 if (*jmp == JMP_BREAK || *jmp == JMP_CONTINUE) *jmp = JMP_NONE;
250 list_free(nv);
251 /* Returns result of last loop */
252 return result;
257 * compile_if() - compile 'if' rule
259 * parse->left condition tree
260 * parse->right then tree
261 * parse->third else tree
263 LIST *compile_if (PARSE *p, LOL *args, int *jmp) {
264 LIST *l = (*p->left->func)(p->left, args, jmp);
265 p = l?p->right:p->third;
266 list_free(l);
267 return (*p->func)(p, args, jmp);
272 * compile_include() - support for 'include' - call include() on file
274 * parse->left list of files to include (can only do 1)
276 LIST *compile_include (PARSE *parse, LOL *args, int *jmp) {
277 LIST *nt = (*parse->left->func)(parse->left, args, jmp);
278 if (DEBUG_COMPILE) {
279 debug_compile(0, "include");
280 list_print(nt);
281 printf("\n");
283 if (nt) {
284 TARGET *t = bindtarget(nt->string);
285 /* Bind the include file under the influence of */
286 /* "on-target" variables. Though they are targets, */
287 /* include files are not built with make(). */
288 /* Needn't copysettings(), as search sets no vars. */
289 pushsettings(t->settings);
290 t->boundname = search(t->name, &t->time);
291 popsettings(t->settings);
292 /* Don't parse missing file if NOCARE set */
293 if (t->time || !(t->flags & T_FLAG_NOCARE)) parse_file(t->boundname);
295 list_free(nt);
296 return L0;
301 * compile_list() - expand and return a list
303 * parse->string - character string to expand
305 LIST *compile_list (PARSE *parse, LOL *args, int *jmp) {
306 /* voodoo 1 means: s is a copyable string */
307 const char *s = parse->string;
308 return var_expand(L0, s, s+strlen(s), args, 1);
313 * compile_local() - declare (and set) local variables
315 * parse->left list of variables
316 * parse->right list of values
317 * parse->third rules to execute
319 LIST *compile_local (PARSE *parse, LOL *args, int *jmp) {
320 LIST *l;
321 SETTINGS *s = 0;
322 LIST *nt = (*parse->left->func)(parse->left, args, jmp);
323 LIST *ns = (*parse->right->func)(parse->right, args, jmp);
324 LIST *result;
326 if (DEBUG_COMPILE) {
327 debug_compile(0, "local");
328 list_print(nt);
329 printf(" = ");
330 list_print(ns);
331 printf("\n");
334 /* Initial value is ns */
335 for (l = nt; l; l = list_next(l)) s = addsettings(s, 0, l->string, list_copy((LIST *)0, ns));
336 list_free(ns);
337 list_free(nt);
338 /* Note that callees of the current context get this "local" */
339 /* variable, making it not so much local as layered. */
340 pushsettings(s);
341 result = (*parse->third->func)(parse->third, args, jmp);
342 popsettings(s);
343 freesettings(s);
345 return result;
350 * compile_null() - do nothing -- a stub for parsing
352 LIST *compile_null (PARSE *parse, LOL *args, int *jmp) {
353 return L0;
358 * compile_on() - run rule under influence of on-target variables
360 * parse->left target list; only first used
361 * parse->right rule to run
363 LIST *compile_on (PARSE *parse, LOL *args, int *jmp) {
364 LIST *nt = (*parse->left->func)(parse->left, args, jmp);
365 LIST *result = 0;
367 if (DEBUG_COMPILE) {
368 debug_compile(0, "on");
369 list_print(nt);
370 printf("\n");
374 * Copy settings, so that 'on target var on target = val'
375 * doesn't set var globally.
377 if (nt) {
378 TARGET *t = bindtarget(nt->string);
379 SETTINGS *s = copysettings(t->settings);
381 pushsettings(s);
382 result = (*parse->right->func)(parse->right, args, jmp);
383 popsettings(s);
384 freesettings(s);
386 list_free(nt);
388 return result;
393 * compile_rule() - compile a single user defined rule
395 * parse->left list of rules to run
396 * parse->right parameters (list of lists) to rule, recursing left
398 * Wrapped around evaluate_rule() so that headers() can share it.
400 LIST *compile_rule (PARSE *parse, LOL *args, int *jmp) {
401 LOL nargs[1];
402 LIST *result = 0;
403 LIST *ll, *l;
404 PARSE *p;
406 /* list of rules to run -- normally 1! */
407 ll = (*parse->left->func)(parse->left, args, jmp);
408 /* Build up the list of arg lists */
409 lol_init(nargs);
410 for (p = parse->right; p; p = p->left) lol_add(nargs, (*p->right->func)(p->right, args, jmp));
411 /* Run rules, appending results from each */
412 for (l = ll; l; l = list_next(l)) result = evaluate_rule(l->string, nargs, result);
413 list_free(ll);
414 lol_free(nargs);
416 return result;
421 * evaluate_rule() - execute a rule invocation
423 LIST *evaluate_rule (const char *rulename, LOL *args, LIST *result) {
424 RULE *rule = bindrule(rulename);
426 if (DEBUG_COMPILE) {
427 debug_compile(1, rulename);
428 lol_print(args);
429 printf("\n");
432 /* Check traditional targets $(<) and sources $(>) */
433 if (!rule->actions && !rule->procedure) printf("warning: unknown rule %s\n", rule->name);
434 /* If this rule will be executed for updating the targets */
435 /* then construct the action for make(). */
436 if (rule->actions) {
437 TARGETS *t;
438 ACTION *action;
440 /* The action is associated with this instance of this rule */
441 action = (ACTION *)malloc(sizeof(ACTION));
442 memset((char *)action, '\0', sizeof(*action));
443 action->rule = rule;
444 action->targets = targetlist((TARGETS *)0, lol_get(args, 0));
445 action->sources = targetlist((TARGETS *)0, lol_get(args, 1));
447 /* Append this action to the actions of each target */
448 for (t = action->targets; t; t = t->next) t->target->actions = actionlist(t->target->actions, action);
450 /* Now recursively compile any parse tree associated with this rule */
451 if (rule->procedure) {
452 PARSE *parse = rule->procedure;
453 SETTINGS *s = 0;
454 int jmp = JMP_NONE;
455 LIST *l;
456 int i;
458 /* build parameters as local vars */
459 for (l = rule->params, i = 0; l; l = l->next, i++) s = addsettings(s, 0, l->string, list_copy(L0, lol_get(args, i)));
460 /* Run rule. */
461 /* Bring in local params. */
462 /* refer/free to ensure rule not freed during use. */
463 parse_refer(parse);
464 pushsettings(s);
465 result = list_append(result, (*parse->func)(parse, args, &jmp));
466 popsettings(s);
467 freesettings(s);
468 parse_free(parse);
471 if (DEBUG_COMPILE) debug_compile(-1, 0);
473 return result;
478 * compile_rules() - compile a chain of rules
480 * parse->left single rule
481 * parse->right more compile_rules() by right-recursion
483 LIST *compile_rules (PARSE *parse, LOL *args, int *jmp) {
484 /* Ignore result from first statement; return the 2nd. */
485 /* Optimize recursion on the right by looping. */
486 LIST *result = 0;
488 while (*jmp == JMP_NONE && parse->func == compile_rules) {
489 list_free(result);
490 result = (*parse->left->func)(parse->left, args, jmp);
491 parse = parse->right;
493 if (*jmp == JMP_NONE) {
494 list_free(result);
495 result = (*parse->func)(parse, args, jmp);
498 return result;
503 * compile_set() - compile the "set variable" statement
505 * parse->left variable names
506 * parse->right variable values
507 * parse->num VAR_SET/APPEND/DEFAULT
509 LIST *compile_set (PARSE *parse, LOL *args, int *jmp) {
510 LIST *nt = (*parse->left->func)(parse->left, args, jmp);
511 LIST *ns = (*parse->right->func)(parse->right, args, jmp);
512 LIST *l;
514 if (DEBUG_COMPILE) {
515 debug_compile(0, "set");
516 list_print(nt);
517 printf(" %s ", set_names[parse->num]);
518 list_print(ns);
519 printf("\n");
521 /* call var_set to set variable */
522 /* var_set keeps ns, so need to copy it */
523 for (l = nt; l; l = list_next(l)) var_set(l->string, list_copy(L0, ns), parse->num);
524 list_free(nt);
525 return ns;
530 * compile_setcomp() - support for `rule` - save parse tree
532 * parse->string rule name
533 * parse->left list of argument names
534 * parse->right rules for rule
536 LIST *compile_setcomp (PARSE *parse, LOL *args, int *jmp) {
537 RULE *rule = bindrule(parse->string);
538 LIST *params = 0;
539 PARSE *p;
541 /* Build param list */
542 for (p = parse->left; p; p = p->left) params = list_new(params, p->string, 1);
544 if (DEBUG_COMPILE) {
545 debug_compile(0, "rule");
546 printf("%s ", parse->string);
547 list_print(params);
548 printf("\n");
551 /* Free old one, if present */
552 if (rule->procedure) parse_free(rule->procedure);
553 if (rule->params) list_free(rule->params);
555 rule->procedure = parse->right;
556 rule->params = params;
558 /* we now own this parse tree */
559 /* don't let parse_free() release it */
560 parse_refer(parse->right);
562 return L0;
567 * compile_setexec() - support for `actions` - save execution string
569 * parse->string rule name
570 * parse->string1 OS command string
571 * parse->num flags
572 * parse->left `bind` variables
574 * Note that the parse flags (as defined in compile.h) are transfered
575 * directly to the rule flags (as defined in rules.h).
577 LIST *compile_setexec (PARSE *parse, LOL *args, int *jmp) {
578 RULE *rule = bindrule(parse->string);
579 LIST *bindlist = (*parse->left->func)(parse->left, args, jmp);
581 /* Free old one, if present */
582 if (rule->actions) {
583 freestr(rule->actions);
584 list_free(rule->bindlist);
587 rule->actions = copystr(parse->string1);
588 rule->bindlist = bindlist;
589 rule->flags = parse->num;
591 return L0;
596 * compile_settings() - compile the "on =" (set variable on exec) statement
598 * parse->left variable names
599 * parse->right target name
600 * parse->third variable value
601 * parse->num VAR_SET/APPEND/DEFAULT
603 LIST *compile_settings (PARSE *parse, LOL *args, int *jmp) {
604 LIST *nt = (*parse->left->func)(parse->left, args, jmp);
605 LIST *ns = (*parse->third->func)(parse->third, args, jmp);
606 LIST *targets = (*parse->right->func)(parse->right, args, jmp);
607 LIST *ts;
609 if (DEBUG_COMPILE) {
610 debug_compile(0, "set");
611 list_print(nt);
612 printf("on ");
613 list_print(targets);
614 printf(" %s ", set_names[parse->num]);
615 list_print(ns);
616 printf("\n");
619 /* Call addsettings to save variable setting */
620 /* addsettings keeps ns, so need to copy it */
621 /* Pass append flag to addsettings() */
622 for (ts = targets; ts; ts = list_next(ts)) {
623 TARGET *t = bindtarget(ts->string);
624 LIST *l;
626 for (l = nt; l; l = list_next(l))
627 t->settings = addsettings(t->settings, parse->num, l->string, list_copy((LIST *)0, ns));
630 list_free(nt);
631 list_free(targets);
633 return ns;
638 * compile_switch() - compile 'switch' rule
640 * parse->left switch value (only 1st used)
641 * parse->right cases
643 * cases->left 1st case
644 * cases->right next cases
646 * case->string argument to match
647 * case->left parse tree to execute
649 LIST *compile_switch (PARSE *parse, LOL *args, int *jmp) {
650 LIST *nt = (*parse->left->func)(parse->left, args, jmp);
651 LIST *result = 0;
653 if (DEBUG_COMPILE) {
654 debug_compile(0, "switch");
655 list_print(nt);
656 printf("\n");
658 /* Step through cases */
659 for (parse = parse->right; parse; parse = parse->right) {
660 if (!glob( parse->left->string, nt?nt->string:"")) {
661 /* Get & exec parse tree for this case */
662 parse = parse->left->left;
663 result = (*parse->func)(parse, args, jmp);
664 break;
667 list_free(nt);
669 return result;
674 * compile_while() - compile 'while' rule
676 * parse->left condition tree
677 * parse->right execution tree
679 LIST *compile_while (PARSE *p, LOL *args, int *jmp) {
680 LIST *result = 0;
681 LIST *l;
683 /* Returns the value from the last execution of the block */
684 while ((*jmp == JMP_NONE ) && (l = (*p->left->func)(p->left, args, jmp))) {
685 /* Always toss while's expression */
686 list_free(l);
687 /* Keep only last result. */
688 list_free(result);
689 result = (*p->right->func)(p->right, args, jmp);
690 /* continue loop? */
691 if (*jmp == JMP_CONTINUE) *jmp = JMP_NONE;
693 /* Here by break/continue? */
694 if (*jmp == JMP_BREAK || *jmp == JMP_CONTINUE) *jmp = JMP_NONE;
695 /* Returns result of last loop */
697 return result;
702 * debug_compile() - printf with indent to show rule expansion.
705 static void debug_compile (int which, const char *s) {
706 static int level = 0;
707 static char indent[36] = ">>>>|>>>>|>>>>|>>>>|>>>>|>>>>|>>>>|";
708 int i = ((1+level)*2)%35;
710 if (which >= 0) printf("%*.*s ", i, i, indent);
711 if (s) printf("%s ", s);
712 level += which;