fixed pkg-config rule
[k8jam.git] / src / compile.c
blob109068cdc5c57eaeac96405239ce3dcd3febcb74
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"
79 #include "matchglob.h"
82 static const char *set_names[] = { "=", "+=", "-=", "?=" };
83 static void debug_compile (int which, const char *s);
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)
102 * compile_break() - compile 'break/continue/return' rule
104 * parse->left results
105 * parse->num JMP_BREAK/CONTINUE/RETURN
107 LIST *compile_break (PARSE *parse, LOL *args, int *jmp) {
108 LIST *lv = (*parse->left->func)(parse->left, args, jmp);
109 *jmp = parse->num;
110 return lv;
115 * compile_eval() - evaluate if to determine which leg to compile
117 * Returns:
118 * list if expression true - compile 'then' clause
119 * L0 if expression false - compile 'else' clause
121 static JAMFA_PURE int lcmp (LIST *t, LIST *s) {
122 int status = 0;
124 while (!status && (t || s)) {
125 const char *st = t?t->string:"";
126 const char *ss = s?s->string:"";
128 status = strcmp(st, ss);
129 t = t?list_next(t):t;
130 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;
143 switch (parse->num) {
144 case EXPR_AND:
145 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: lr = (*parse->right->func)(parse->right, args, jmp);
153 break;
155 /* now eval */
156 switch (parse->num) {
157 case EXPR_NOT:
158 if (!ll) status = 1;
159 break;
160 case EXPR_AND:
161 if (ll && lr) status = 1;
162 break;
163 case EXPR_OR:
164 if (ll || lr) status = 1;
165 break;
166 case EXPR_IN:
167 /* "a in b": make sure each of ll is equal to something in lr */
168 for (t = ll; t; t = list_next(t)) {
169 for (s = lr; s; s = list_next(s)) if (strcmp(t->string, s->string) == 0) break;
170 if (!s) break;
172 /* No more ll? success */
173 if (!t) status = 1;
174 break;
175 case EXPR_EXISTS:
176 if (lcmp(ll, L0) != 0) status = 1;
177 break;
178 case EXPR_EQUALS:
179 if (lcmp(ll, lr) == 0) status = 1;
180 break;
181 case EXPR_NOTEQ:
182 if (lcmp(ll, lr) != 0) status = 1;
183 break;
184 case EXPR_LESS:
185 if (lcmp(ll, lr) < 0) status = 1;
186 break;
187 case EXPR_LESSEQ:
188 if (lcmp(ll, lr) <= 0) status = 1;
189 break;
190 case EXPR_MORE:
191 if (lcmp(ll, lr) > 0) status = 1;
192 break;
193 case EXPR_MOREEQ:
194 if (lcmp(ll, lr) >= 0) status = 1;
195 break;
197 if (DEBUG_IF) {
198 debug_compile(0, "if");
199 list_print(ll);
200 printf("(%d) ", status);
201 list_print(lr);
202 printf("\n");
204 /* find something to return */
205 /* in odd circumstances (like "" = "") we'll have to return a new string */
206 if (!status) t = 0;
207 else if (ll) t = ll, ll = 0;
208 else if (lr) t = lr, lr = 0;
209 else t = list_new(L0, "1", 0);
210 if (ll) list_free(ll);
211 if (lr) list_free(lr);
212 return t;
217 * compile_foreach() - compile the "for x in y" statement
219 * Compile_foreach() resets the given variable name to each specified
220 * value, executing the commands enclosed in braces for each iteration.
222 * parse->string index variable
223 * parse->left variable values
224 * parse->right rule to compile
226 LIST *compile_foreach (PARSE *p, LOL *args, int *jmp) {
227 LIST *nv = (*p->left->func)(p->left, args, jmp);
228 LIST *result = 0;
229 LIST *l;
231 /* for each value for var */
232 for (l = nv; l && *jmp == JMP_NONE; l = list_next(l)) {
233 /* reset $(p->string) for each val */
234 var_set(p->string, list_new(L0, l->string, 1), VAR_SET);
235 /* keep only last result */
236 list_free(result);
237 result = (*p->right->func)(p->right, args, jmp);
238 /* continue loop? */
239 if (*jmp == JMP_CONTINUE) *jmp = JMP_NONE;
241 /* here by break/continue? */
242 if (*jmp == JMP_BREAK || *jmp == JMP_CONTINUE) *jmp = JMP_NONE;
243 list_free(nv);
244 /* returns result of last loop */
245 return result;
250 * compile_if() - compile 'if' rule
252 * parse->left condition tree
253 * parse->right then tree
254 * parse->third else tree
256 LIST *compile_if (PARSE *p, LOL *args, int *jmp) {
257 LIST *l = (*p->left->func)(p->left, args, jmp);
259 p = l?p->right:p->third;
260 list_free(l);
261 return (*p->func)(p, args, jmp);
266 * compile_include() - support for 'include' - call include() on file
268 * parse->left list of files to include (can only do 1)
270 static LIST *compile_include_internal (PARSE *parse, LOL *args, int *jmp, int assoft) {
271 LIST *nt = (*parse->left->func)(parse->left, args, jmp);
273 if (DEBUG_COMPILE) {
274 debug_compile(0, (assoft?"softinclude":"include"));
275 list_print(nt);
276 printf("\n");
278 if (nt) {
279 TARGET *t = bindtarget(nt->string);
280 /* bind the include file under the influence of "on-target" variables */
281 /* though they are targets, include files are not built with make() */
282 /* needn't copysettings(), as search sets no vars */
283 pushsettings(t->settings);
284 t->boundname = search(t->name, &t->time);
285 popsettings(t->settings);
286 /* don't parse missing file if NOCARE set */
287 if (t->time || !(t->flags & T_FLAG_NOCARE)) {
288 int doit = 1;
289 FILE *fl = fopen(t->boundname, "r");
291 if (fl == NULL) {
292 if (assoft) {
293 doit = 0;
294 } else {
295 printf("Failed to include file '%s'\n", t->boundname);
296 exit(EXITBAD);
298 } else {
299 fclose(fl);
301 if (doit) parse_file(t->boundname);
304 list_free(nt);
305 return L0;
310 * compile_include() - support for 'include' - call include() on file
312 * parse->left list of files to include (can only do 1)
314 LIST *compile_include (PARSE *parse, LOL *args, int *jmp) {
315 return compile_include_internal(parse, args, jmp, 0);
320 * compile_softinclude() - support for 'softinclude' - call include() on file if file exists
322 * parse->left list of files to include (can only do 1)
324 LIST *compile_softinclude (PARSE *parse, LOL *args, int *jmp) {
325 return compile_include_internal(parse, args, jmp, 1);
330 * compile_list() - expand and return a list
332 * parse->string - character string to expand
334 LIST *compile_list (PARSE *parse, LOL *args, int *jmp) {
335 /* voodoo 1 means: s is a copyable string */
336 const char *s = parse->string;
337 return var_expand(L0, s, s+strlen(s), args, 1);
342 * compile_local() - declare (and set) local variables
344 * parse->left list of variables
345 * parse->right list of values
346 * parse->third rules to execute
348 LIST *compile_local (PARSE *parse, LOL *args, int *jmp) {
349 LIST *l;
350 SETTINGS *s = 0;
351 LIST *nt = (*parse->left->func)(parse->left, args, jmp);
352 LIST *ns = (*parse->right->func)(parse->right, args, jmp);
353 LIST *result;
355 if (DEBUG_COMPILE) {
356 debug_compile(0, "local");
357 list_print(nt);
358 printf(" = ");
359 list_print(ns);
360 printf("\n");
362 /* initial value is ns */
363 for (l = nt; l; l = list_next(l)) s = addsettings(s, 0, l->string, list_copy((LIST *)0, ns));
364 list_free(ns);
365 list_free(nt);
366 /* note that callees of the current context get this "local" */
367 /* variable, making it not so much local as layered */
368 pushsettings(s);
369 result = (*parse->third->func)(parse->third, args, jmp);
370 popsettings(s);
371 freesettings(s);
372 return result;
377 * compile_null() - do nothing -- a stub for parsing
379 LIST *compile_null (PARSE *parse, LOL *args, int *jmp) {
380 return L0;
385 * compile_on() - run rule under influence of on-target variables
387 * parse->left target list; only first used
388 * parse->right rule to run
390 LIST *compile_on (PARSE *parse, LOL *args, int *jmp) {
391 LIST *nt = (*parse->left->func)(parse->left, args, jmp);
392 LIST *result = 0;
394 if (DEBUG_COMPILE) {
395 debug_compile(0, "on");
396 list_print(nt);
397 printf("\n");
399 /* copy settings, so that 'on target var on target = val' doesn't set var globally */
400 if (nt) {
401 TARGET *t = bindtarget(nt->string);
402 SETTINGS *s = copysettings(t->settings);
404 pushsettings(s);
405 result = (*parse->right->func)(parse->right, args, jmp);
406 popsettings(s);
407 freesettings(s);
409 list_free(nt);
410 return result;
415 * compile_rule() - compile a single user defined rule
417 * parse->left list of rules to run
418 * parse->right parameters (list of lists) to rule, recursing left
420 * Wrapped around evaluate_rule() so that headers() can share it.
422 LIST *compile_rule (PARSE *parse, LOL *args, int *jmp) {
423 LOL nargs[1];
424 LIST *result = 0;
425 LIST *ll, *l;
426 PARSE *p;
428 /* list of rules to run -- normally 1! */
429 ll = (*parse->left->func)(parse->left, args, jmp);
430 /* build up the list of arg lists */
431 lol_init(nargs);
432 for (p = parse->right; p; p = p->left) lol_add(nargs, (*p->right->func)(p->right, args, jmp));
433 /* run rules, appending results from each */
434 for (l = ll; l; l = list_next(l)) result = evaluate_rule(l->string, nargs, result);
435 list_free(ll);
436 lol_free(nargs);
437 return result;
442 * evaluate_rule() - execute a rule invocation
444 LIST *evaluate_rule (const char *rulename, LOL *args, LIST *result) {
445 //#ifdef OPT_EXPAND_RULE_NAMES_EXT
446 RULE *rule;
447 char *expanded, *c;
448 tKString buf;
450 kStringNew(&buf);
451 if (var_string(rulename, &buf, args, ' ') < 0) {
452 kStringFree(&buf);
453 printf("Failed to expand rule %s -- expansion too long\n", rulename);
454 exit(EXITBAD);
456 expanded = kStringCStr(&buf);
457 while (expanded[0] == ' ') ++expanded;
458 while ((c = strrchr(expanded, ' '))) *c = '\0';
459 if (DEBUG_COMPILE) {
460 debug_compile(1, rulename);
461 if (strcmp(rulename, expanded)) printf("-> %s ", expanded);
462 lol_print(args);
463 printf("\n");
465 rule = bindrule(expanded);
466 kStringFree(&buf);
467 //#else
469 RULE *rule = bindrule(rulename);
471 if (DEBUG_COMPILE) {
472 debug_compile(1, rulename);
473 lol_print(args);
474 printf("\n");
477 //#endif
478 /* check traditional targets $(<) and sources $(>) */
479 if (!rule->actions && !rule->procedure) printf("warning: unknown rule %s\n", rule->name);
480 /* if this rule will be executed for updating the targets then construct the action for make() */
481 if (rule->actions) {
482 TARGETS *t;
483 ACTION *action;
485 /* the action is associated with this instance of this rule */
486 action = (ACTION *)malloc(sizeof(ACTION));
487 memset((char *)action, '\0', sizeof(*action));
488 action->rule = rule;
489 action->targets = targetlist((TARGETS *)0, lol_get(args, 0));
490 action->sources = targetlist((TARGETS *)0, lol_get(args, 1));
491 /* append this action to the actions of each target */
492 for (t = action->targets; t; t = t->next) t->target->actions = actionlist(t->target->actions, action);
494 /* now recursively compile any parse tree associated with this rule */
495 if (rule->procedure) {
496 PARSE *parse = rule->procedure;
497 SETTINGS *s = 0;
498 int jmp = JMP_NONE;
499 LIST *l;
500 int i;
502 /* build parameters as local vars */
503 for (l = rule->params, i = 0; l; l = l->next, i++) s = addsettings(s, 0, l->string, list_copy(L0, lol_get(args, i)));
504 /* run rule */
505 /* bring in local params */
506 /* refer/free to ensure rule not freed during use */
507 parse_refer(parse);
508 pushsettings(s);
509 result = list_append(result, (*parse->func)(parse, args, &jmp));
510 popsettings(s);
511 freesettings(s);
512 parse_free(parse);
514 if (DEBUG_COMPILE) debug_compile(-1, 0);
515 //#ifdef OPT_EXPAND_RULE_NAMES_EXT
516 kStringFree(&buf);
517 //#endif
518 return result;
523 * compile_rules() - compile a chain of rules
525 * parse->left single rule
526 * parse->right more compile_rules() by right-recursion
528 LIST *compile_rules (PARSE *parse, LOL *args, int *jmp) {
529 /* ignore result from first statement; return the 2nd */
530 /* optimize recursion on the right by looping */
531 LIST *result = 0;
533 while (*jmp == JMP_NONE && parse->func == compile_rules) {
534 list_free(result);
535 result = (*parse->left->func)(parse->left, args, jmp);
536 parse = parse->right;
538 if (*jmp == JMP_NONE) {
539 list_free(result);
540 result = (*parse->func)(parse, args, jmp);
542 return result;
547 * compile_set() - compile the "set variable" statement
549 * parse->left variable names
550 * parse->right variable values
551 * parse->num VAR_SET/APPEND/DEFAULT
553 LIST *compile_set (PARSE *parse, LOL *args, int *jmp) {
554 LIST *nt = (*parse->left->func)(parse->left, args, jmp);
555 LIST *ns = (*parse->right->func)(parse->right, args, jmp);
556 LIST *l;
558 if (DEBUG_COMPILE) {
559 debug_compile(0, "set");
560 list_print(nt);
561 printf(" %s ", set_names[parse->num]);
562 list_print(ns);
563 printf("\n");
565 /* call var_set to set variable */
566 /* var_set keeps ns, so need to copy it */
567 for (l = nt; l; l = list_next(l)) var_set(l->string, list_copy(L0, ns), parse->num);
568 list_free(nt);
569 return ns;
574 * compile_setcomp() - support for `rule` - save parse tree
576 * parse->string rule name
577 * parse->left list of argument names
578 * parse->right rules for rule
580 LIST *compile_setcomp (PARSE *parse, LOL *args, int *jmp) {
581 RULE *rule = bindrule(parse->string);
582 LIST *params = 0;
583 PARSE *p;
585 /* build param list */
586 for (p = parse->left; p; p = p->left) params = list_new(params, p->string, 1);
587 if (DEBUG_COMPILE) {
588 debug_compile(0, "rule");
589 printf("%s ", parse->string);
590 list_print(params);
591 printf("\n");
593 /* free old one, if present */
594 if (rule->procedure) parse_free(rule->procedure);
595 if (rule->params) list_free(rule->params);
596 rule->procedure = parse->right;
597 rule->params = params;
598 /* we now own this parse tree */
599 /* don't let parse_free() release it */
600 parse_refer(parse->right);
601 return L0;
606 * compile_setexec() - support for `actions` - save execution string
608 * parse->string rule name
609 * parse->string1 OS command string
610 * parse->num flags
611 * parse->left `bind` variables
613 * Note that the parse flags (as defined in compile.h) are transfered
614 * directly to the rule flags (as defined in rules.h).
616 LIST *compile_setexec (PARSE *parse, LOL *args, int *jmp) {
617 RULE *rule = bindrule(parse->string);
618 LIST *bindlist = (*parse->left->func)(parse->left, args, jmp);
620 /* free old one, if present */
621 if (rule->actions) {
622 freestr(rule->actions);
623 list_free(rule->bindlist);
625 rule->actions = copystr(parse->string1);
626 rule->bindlist = bindlist;
627 rule->flags = parse->num;
628 return L0;
633 * compile_settings() - compile the "on =" (set variable on exec) statement
635 * parse->left variable names
636 * parse->right target name
637 * parse->third variable value
638 * parse->num VAR_SET/APPEND/DEFAULT
640 LIST *compile_settings (PARSE *parse, LOL *args, int *jmp) {
641 LIST *nt = (*parse->left->func)(parse->left, args, jmp);
642 LIST *ns = (*parse->third->func)(parse->third, args, jmp);
643 LIST *targets = (*parse->right->func)(parse->right, args, jmp);
644 LIST *ts;
646 if (DEBUG_COMPILE) {
647 debug_compile(0, "set");
648 list_print(nt);
649 printf("on ");
650 list_print(targets);
651 printf(" %s ", set_names[parse->num]);
652 list_print(ns);
653 printf("\n");
655 /* call addsettings to save variable setting addsettings keeps ns, so need to copy it */
656 /* pass append flag to addsettings() */
657 for (ts = targets; ts; ts = list_next(ts)) {
658 TARGET *t = bindtarget(ts->string);
659 LIST *l;
661 for (l = nt; l; l = list_next(l)) {
662 t->settings = addsettings(t->settings, parse->num, l->string, list_copy((LIST *)0, ns));
665 list_free(nt);
666 list_free(targets);
667 return ns;
672 * compile_switch() - compile 'switch' rule
674 * parse->left switch value (only 1st used)
675 * parse->right cases
677 * cases->left 1st case
678 * cases->right next cases
680 * case->string argument to match
681 * case->left parse tree to execute
683 LIST *compile_switch (PARSE *parse, LOL *args, int *jmp) {
684 LIST *nt = (*parse->left->func)(parse->left, args, jmp);
685 LIST *result = 0;
687 if (DEBUG_COMPILE) {
688 debug_compile(0, "switch");
689 list_print(nt);
690 printf("\n");
692 /* step through cases */
693 for (parse = parse->right; parse; parse = parse->right) {
694 if (!matchglob(parse->left->string, nt?nt->string:"")) {
695 /* get and exec parse tree for this case */
696 parse = parse->left->left;
697 result = (*parse->func)(parse, args, jmp);
698 break;
701 list_free(nt);
702 return result;
707 * compile_while() - compile 'while' rule
709 * parse->left condition tree
710 * parse->right execution tree
712 LIST *compile_while (PARSE *p, LOL *args, int *jmp) {
713 LIST *result = 0;
714 LIST *l;
716 /* returns the value from the last execution of the block */
717 while ((*jmp == JMP_NONE ) && (l = (*p->left->func)(p->left, args, jmp))) {
718 /* always toss while's expression */
719 list_free(l);
720 /* keep only last result */
721 list_free(result);
722 result = (*p->right->func)(p->right, args, jmp);
723 /* continue loop? */
724 if (*jmp == JMP_CONTINUE) *jmp = JMP_NONE;
726 /* here by break/continue? */
727 if (*jmp == JMP_BREAK || *jmp == JMP_CONTINUE) *jmp = JMP_NONE;
728 /* returns result of last loop */
729 return result;
734 * debug_compile() - printf with indent to show rule expansion.
736 static void debug_compile (int which, const char *s) {
737 static int level = 0;
738 static const char indent[36] = ">>>>|>>>>|>>>>|>>>>|>>>>|>>>>|>>>>|";
739 int i = ((1+level)*2)%35;
741 if (which >= 0) printf("%*.*s ", i, i, indent);
742 if (s) printf("%s ", s);
743 level += which;