1 %{
2
3 /*-
4 * Copyright (c) 1988, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * %sccs.include.redist.c%
8 */
9
10 #ifndef lint
11 static char sccsid[] = "@(#)mkmake.y 8.1 (Berkeley) 06/06/93";
12 #endif /* not lint */
13
14 typedef struct string {
15 int
16 hashval,
17 length;
18 char
19 *string;
20 struct string
21 *next;
22 } string_t;
23
24 /*
25 * The deal with these is that they exist on various lists.
26 *
27 * First off, they are on a temporary list during the time they
28 * are in the active focus of the parser.
29 *
30 * Secondly, they live on one of three queues:
31 * 1. Variables
32 * 2. Targets
33 * 3. Actions
34 * (and, we restrict any given one to live on one and only one such list)
35 *
36 * Also, they may live on the list of values for someone else's variable,
37 * or as someone's dependancy.
38 */
39
40 typedef struct same {
41 string_t
42 *string; /* My name */
43 struct same
44 *nexttoken, /* Next pointer */
45 *lasttoken, /* Back pointer */
46 *depend_list, /* If target, dependancies */
47 *action_list, /* If target, actions */
48 *value_list, /* If variable, value list */
49 *shell_item; /* If a shell variable, current value */
50 } same_t;
51
52 %}
53
54 %union {
55 string_t *string;
56 same_t *same;
57 int intval;
58 }
59
60 %start makefile
61 %token <string> TOKEN QUOTED_STRING
62 %token <intval> FOR IN DO DONE
63 %token <intval> MACRO_CHAR NL WHITE_SPACE
64 %token <intval> ':' '=' '$' '{' '}' ';' '-' '@' '(' ')' ' ' '\t'
65 %type <same> target target1 assignment assign1 actions action
66 %type <same> command_list list list_element
67 %type <same> for_statement maybe_at_minus tokens token
68 %type <same> maybe_white_space
69 %type <intval> white_space macro_char
70 %%
71
72 makefile : lines;
73
74 lines : line
75 | lines line
76 ;
77
78 line : NL
79 | assignment
80 | target_action
81 ;
82
83 assignment : assign1 tokens NL
84 {
85 assign($1, $2);
86 }
87 | assign1 NL
88 {
89 assign($1, same_copy(null));
90 }
91 ;
92
93 assign1: token maybe_white_space '=' maybe_white_space
94 ;
95
96 target_action: target actions
97 {
98 add_targets_actions($1, $2);
99 }
100 | target
101 {
102 add_targets_actions($1, 0);
103 }
104 ;
105
106 target : target1 tokens NL
107 {
108 $$ = add_depends($1, $2);
109 }
110 | target1 NL
111 {
112 $$ = add_depends($1, same_copy(null));
113 }
114 ;
115
116 target1: tokens maybe_white_space ':' maybe_white_space
117 {
118 $$ = ws_merge($1);
119 }
120 ;
121
122 actions: action
123 | actions action
124 {
125 $$ = same_cat(same_cat($1, same_copy(newline)), $2);
126 }
127 ;
128
129 action: white_space command_list NL
130 {
131 $$ = $2;
132 }
133 | white_space for_statement do command_list semi_colon done NL
134 {
135 $$ = do_command($2, $4);
136 }
137 ;
138
139 for_statement: maybe_at_minus FOR white_space token
140 in tokens semi_colon
141 {
142 $$ = for_statement($1, $4, ws_merge(expand_variables($6, 0)));
143 }
144 ;
145
146 in: white_space IN white_space
147 do: white_space DO white_space
148 ;
149
150 done: white_space DONE
151 ;
152
153 semi_colon: ';'
154 ;
155
156 command_list: list
157 | '(' list maybe_white_space ')'
158 {
159 $$ = same_cat($2, same_copy(cwd_line));
160 }
161 ;
162
163 list: token
164 | list list_element
165 {
166 $$ = same_cat($1, $2);
167 }
168 | list white_space list_element
169 {
170 $$ = same_cat($1, same_cat(same_copy(blank), $3));
171 }
172 ;
173
174 list_element: token
175 | semi_colon
176 {
177 $$ = same_copy(newline);
178 }
179 ;
180
181 maybe_at_minus: /* empty */
182 {
183 $$ = same_copy(null);
184 }
185 | '@'
186 {
187 char buffer[2];
188
189 buffer[0] = $1;
190 buffer[1] = 0;
191 $$ = same_item(string_lookup(buffer));
192 }
193 | '-'
194 {
195 char buffer[2];
196
197 buffer[0] = $1;
198 buffer[1] = 0;
199 $$ = same_item(string_lookup(buffer));
200 }
201 ;
202
203 tokens : token
204 | tokens maybe_white_space token
205 {
206 $$ = same_cat($1, same_cat($2, $3));
207 }
208 ;
209
210 token: TOKEN
211 {
212 $$ = same_item($1);
213 }
214 | QUOTED_STRING
215 {
216 $$ = same_item($1);
217 }
218 | '$' macro_char
219 {
220 char buffer[3];
221
222 buffer[0] = '$';
223 buffer[1] = $2;
224 buffer[2] = 0;
225
226 $$ = same_item(string_lookup(buffer));
227 }
228 | '$' '$' TOKEN
229 {
230 $$ = shell_variable(same_item($3));
231 }
232 | MACRO_CHAR
233 {
234 $$ = same_char($1);
235 }
236 | '$' '{' TOKEN '}'
237 {
238 $$ = variable(same_item($3));
239 }
240 | '$' '(' TOKEN ')'
241 {
242 $$ = variable(same_item($3));
243 }
244 | '$' TOKEN
245 {
246 $$ = variable(same_item($2));
247 }
248 | '-'
249 {
250 $$ = same_char('-');
251 }
252 | '@'
253 {
254 $$ = same_char('@');
255 }
256 ;
257
258 macro_char: MACRO_CHAR
259 | '@'
260 ;
261
262 maybe_white_space:
263 {
264 $$ = same_copy(null);
265 }
266 | white_space
267 {
268 $$ = same_char($1);
269 }
270 ;
271
272 white_space : WHITE_SPACE
273 | white_space WHITE_SPACE
274 ;
275 %%
276 #include <stdio.h>
277 #include <ctype.h>
278
279 static int last_char, last_saved = 0;
280 static int column = 0, lineno = 1;
281
282
283 static string_t
284 *strings = 0;
285
286 static same_t
287 *shell_variables = 0,
288 *shell_special = 0,
289 *variables = 0,
290 *targets = 0,
291 *actions = 0;
292
293 static same_t
294 *null,
295 *blank,
296 *cwd_line,
297 *newline;
298
299 extern char *malloc();
300
301 static unsigned int
302 clock = -1;
303
304 struct {
305 same_t *first;
306 int next;
307 } visit_stack[20]; /* 20 maximum */
308
309 #define visit(what,via) \
310 (visit_stack[++clock].next = 0, visit_stack[clock].first = via = what)
311 #define visited(via) (visitcheck(via) || ((via) == 0) \
312 || (visit_stack[clock].next && (via == visit_stack[clock].first)))
313 #define visit_next(via) (visit_stack[clock].next = 1, (via) = (via)->nexttoken)
314 #define visit_end() (clock--)
315
yyerror(s)316 yyerror(s)
317 char *s;
318 {
319 fprintf(stderr, "line %d, character %d: %s\n", lineno, column, s);
320 do_dump();
321 }
322
323 int
visitcheck(same)324 visitcheck(same)
325 same_t *same;
326 {
327 if (same->string == 0) {
328 yyerror("BUG - freed 'same' in use...");
329 exit(1);
330 }
331 return 0;
332 }
333
334 int
string_hashof(string,length)335 string_hashof(string, length)
336 char *string;
337 int length;
338 {
339 register int i = 0;
340
341 while (length--) {
342 i = (i<<3) + *string ^ ((i>>28)&0x7);
343 }
344 return i;
345 }
346
347 int
string_same(s1,s2)348 string_same(s1, s2)
349 string_t
350 *s1, *s2;
351 {
352 if ((s1->hashval == s2->hashval) && (s1->length == s2->length)
353 && (memcmp(s1->string, s2->string, s1->length) == 0)) {
354 return 1;
355 } else {
356 return 0;
357 }
358 }
359
360 string_t *
string_lookup(string)361 string_lookup(string)
362 char *string;
363 {
364 string_t ours;
365 string_t *ptr;
366
367 ours.length = strlen(string);
368 ours.hashval = string_hashof(string, ours.length);
369 ours.string = string;
370
371 for (ptr = strings; ptr; ptr = ptr->next) {
372 if (string_same(&ours, ptr)) {
373 return ptr;
374 }
375 }
376 if ((ptr = (string_t *)malloc(sizeof *ptr)) == 0) {
377 fprintf(stderr, "No space to add string *%s*!\n", string);
378 exit(1);
379 }
380 ptr->hashval = ours.hashval;
381 ptr->length = ours.length;
382 if ((ptr->string = malloc(ours.length+1)) == 0) {
383 fprintf(stderr, "No space to add literal *%s*!\n", string);
384 exit(1);
385 }
386 memcpy(ptr->string, string, ours.length+1);
387 ptr->next = strings;
388 strings = ptr;
389 return ptr;
390 }
391
392 #define same_singleton(s) ((s)->nexttoken == (s))
393
394 same_t *
same_search(list,token)395 same_search(list, token)
396 same_t
397 *list,
398 *token;
399 {
400 same_t *ptr;
401
402 ptr = list;
403 for (visit(list, ptr); !visited(ptr); visit_next(ptr)) {
404 string_t *string;
405
406 string = ptr->string;
407 if (string_same(string, token->string)) {
408 visit_end();
409 return ptr;
410 }
411 }
412 visit_end();
413 return 0;
414 }
415
416 same_t *
same_cat(list,tokens)417 same_cat(list, tokens)
418 same_t
419 *list,
420 *tokens;
421 {
422 same_t *last;
423
424 if (tokens == 0) {
425 return list;
426 }
427 if (list) {
428 last = tokens->lasttoken;
429 tokens->lasttoken = list->lasttoken;
430 list->lasttoken = last;
431 tokens->lasttoken->nexttoken = tokens;
432 last->nexttoken = list;
433 return list;
434 } else {
435 return tokens;
436 }
437 }
438
439 same_t *
same_item(string)440 same_item(string)
441 string_t *string;
442 {
443 same_t *ptr;
444
445 if ((ptr = (same_t *)malloc(sizeof *ptr)) == 0) {
446 fprintf(stderr, "No more space for tokens!\n");
447 exit(1);
448 }
449 memset((char *)ptr, 0, sizeof *ptr);
450 ptr->nexttoken = ptr->lasttoken = ptr;
451 ptr->string = string;
452 return ptr;
453 }
454
455 same_t *
same_copy(same)456 same_copy(same)
457 same_t *same;
458 {
459 same_t *head, *copy;
460
461 head = 0;
462 for (visit(same, copy); !visited(copy); visit_next(copy)) {
463 same_t *ptr;
464
465 ptr = same_item(copy->string);
466 head = same_cat(head, ptr);
467 }
468 visit_end();
469 return head;
470 }
471
472
473 same_t *
same_merge(t1,t2)474 same_merge(t1, t2)
475 same_t
476 *t1,
477 *t2;
478 {
479 if (same_singleton(t1) && same_singleton(t2)) {
480 int length = strlen(t1->string->string)+strlen(t2->string->string);
481 char *buffer = malloc(length+1);
482 same_t *value;
483
484 if (buffer == 0) {
485 yyerror("No space to merge strings in same_merge!");
486 exit(1);
487 }
488 strcpy(buffer, t1->string->string);
489 strcat(buffer, t2->string->string);
490 value = same_item(string_lookup(buffer));
491 free(buffer);
492 return value;
493 } else {
494 yyerror("Internal error - same_merge with non-singletons");
495 exit(1);
496 }
497 }
498
499
500 void
same_free(list)501 same_free(list)
502 same_t *list;
503 {
504 same_t *token, *ptr;
505
506 if (list == 0) {
507 return;
508 }
509
510 token = list;
511 do {
512 ptr = token->nexttoken;
513 token->string = 0;
514 (void) free((char *)token);
515 token = ptr;
516 } while (token != list);
517 }
518
519 same_t *
same_unlink(token)520 same_unlink(token)
521 same_t
522 *token;
523 {
524 same_t *tmp;
525
526 if (token == 0) {
527 return 0;
528 }
529 if ((tmp = token->nexttoken) == token) {
530 tmp = 0;
531 }
532 token->lasttoken->nexttoken = token->nexttoken;
533 token->nexttoken->lasttoken = token->lasttoken;
534 token->nexttoken = token->lasttoken = token;
535 return tmp;
536 }
537
538 void
same_replace(old,new)539 same_replace(old, new)
540 same_t
541 *old,
542 *new;
543 {
544 new->lasttoken->nexttoken = old->nexttoken;
545 old->nexttoken->lasttoken = new->lasttoken;
546 new->lasttoken = old->lasttoken;
547 /* rather than
548 * old->lasttoken->nexttoken = new
549 * we update in place (for the case where there isn't anything else)
550 */
551 *old = *new;
552 }
553
554
555 same_t *
same_char(ch)556 same_char(ch)
557 char ch;
558 {
559 char buffer[2];
560
561 buffer[0] = ch;
562 buffer[1] = 0;
563
564 return same_item(string_lookup(buffer));
565 }
566
567
568 void
add_target(target,actions)569 add_target(target, actions)
570 same_t
571 *target,
572 *actions;
573 {
574 same_t *ptr;
575
576 if ((ptr = same_search(targets, target)) == 0) {
577 targets = same_cat(targets, target);
578 ptr = target;
579 } else {
580 ptr->depend_list = same_cat(ptr->depend_list, target->depend_list);
581 }
582 if (actions) {
583 if (ptr->action_list) {
584 same_free(ptr->action_list);
585 }
586 ptr->action_list = same_copy(actions);
587 }
588 }
589
590
591 same_t *
add_targets_actions(target,actions)592 add_targets_actions(target, actions)
593 same_t
594 *target,
595 *actions;
596 {
597 same_t *ptr;
598
599 if (target == 0) {
600 return 0;
601 }
602 do {
603 ptr = same_unlink(target);
604 add_target(target, actions);
605 target = ptr;
606 } while (target);
607
608 same_free(actions);
609 return 0;
610 }
611
612 same_t *
add_depends(target,depends)613 add_depends(target, depends)
614 same_t
615 *target,
616 *depends;
617 {
618 same_t *original = target;
619
620 depends = same_cat(depends, same_copy(blank)); /* Separator */
621
622 for (visit(original, target); !visited(target); visit_next(target)) {
623 target->depend_list = same_cat(target->depend_list, same_copy(depends));
624 }
625 visit_end();
626 same_free(depends);
627
628 return original;
629 }
630
631
632 /*
633 * We know that variable is a singleton
634 */
635
636 void
assign(variable,value)637 assign(variable, value)
638 same_t
639 *variable,
640 *value;
641 {
642 same_t *ptr;
643
644 if ((ptr = same_search(variables, variable)) != 0) {
645 same_free(ptr->value_list);
646 variables = same_unlink(ptr);
647 same_free(ptr);
648 }
649 variable->value_list = value;
650 variables = same_cat(variables, variable);
651 }
652
653 same_t *
value_of(variable)654 value_of(variable)
655 same_t *variable;
656 {
657 same_t *ptr = same_search(variables, variable);
658
659 if (ptr == 0) {
660 return same_copy(null);
661 } else {
662 return same_copy(ptr->value_list);
663 }
664 }
665
666
667 same_t *
expand_variables(token,free)668 expand_variables(token, free)
669 same_t *token;
670 int free;
671 {
672 same_t *head = 0;
673
674 if (!free) {
675 token = same_copy(token); /* Get our private copy */
676 }
677
678 while (token) {
679 char *string = token->string->string;
680 same_t *tmp = same_unlink(token);
681
682 if ((string[0] == '$') && (string[1] == '{')) { /* Expand time */
683 int len = strlen(string);
684
685 string[len-1] = 0;
686 head = same_cat(head, expand_variables(
687 value_of(same_item(string_lookup(string+2))), 1));
688 string[len-1] = '}';
689 } else {
690 head = same_cat(head, token);
691 }
692 token = tmp;
693 }
694 return head;
695 }
696
697
698 same_t *
ws_merge(list)699 ws_merge(list)
700 same_t *list;
701 {
702 same_t *newlist = 0, *item;
703 int what = 0;
704
705 while (list) {
706 switch (what) {
707 case 0:
708 if (isspace(list->string->string[0])) {
709 ;
710 } else {
711 item = same_item(list->string);
712 what = 1;
713 }
714 break;
715 case 1:
716 if (isspace(list->string->string[0])) {
717 newlist = same_cat(newlist, item);
718 item = 0;
719 what = 0;
720 } else {
721 item = same_merge(item, same_item(list->string));
722 what = 1;
723 }
724 break;
725 }
726 list = same_unlink(list);
727 }
728 return same_cat(newlist, item);
729 }
730
731
732 same_t *
variable(var_name)733 variable(var_name)
734 same_t *var_name;
735 {
736 int length = strlen(var_name->string->string);
737 same_t *resolved;
738 char *newname;
739
740 if ((newname = malloc(length+1+3)) == 0) {
741 fprintf("Out of space for a variable name.\n");
742 exit(1);
743 }
744 newname[0] = '$';
745 newname[1] = '{';
746 strcpy(newname+2, var_name->string->string);
747 strcat(newname, "}");
748 resolved = same_item(string_lookup(newname));
749 free(newname);
750
751 return resolved;
752 }
753
754
755 same_t *
shell_variable(var_name)756 shell_variable(var_name)
757 same_t *var_name;
758 {
759 int length = strlen(var_name->string->string);
760 same_t *resolved;
761 char *newname;
762
763 if ((newname = malloc(length+1+2)) == 0) {
764 fprintf("Out of space for a variable name.\n");
765 exit(1);
766 }
767 newname[0] = '$';
768 newname[1] = '$';
769 strcpy(newname+2, var_name->string->string);
770 resolved = same_item(string_lookup(newname));
771 free(newname);
772
773 return resolved;
774 }
775
776 same_t *
for_statement(special,variable,list)777 for_statement(special, variable, list)
778 same_t
779 *special,
780 *variable,
781 *list;
782 {
783 variable->shell_item = special;
784 variable->value_list = list;
785 return variable;
786 }
787
788 same_t *
do_command(forlist,commands)789 do_command(forlist, commands)
790 same_t
791 *forlist,
792 *commands;
793 {
794 same_t
795 *special,
796 *command_list = 0,
797 *new_commands,
798 *tmp,
799 *shell_item,
800 *value_list = forlist->value_list;
801 char
802 *tmpstr,
803 *variable_name = forlist->string->string;
804
805 special = forlist->shell_item;
806 if (same_unlink(forlist->shell_item) != 0) {
807 yyerror("Unexpected second item in special part of do_command");
808 exit(1);
809 }
810
811 while ((shell_item = value_list) != 0) {
812 value_list = same_unlink(shell_item);
813 /* Visit each item in commands. For each shell variable which
814 * matches ours, replace it with ours.
815 */
816 new_commands = same_copy(commands);
817 for (visit(new_commands, tmp); !visited(tmp); visit_next(tmp)) {
818 tmpstr = tmp->string->string;
819 if ((tmpstr[0] == '$') && (tmpstr[1] == '$')) {
820 if (strcmp(tmpstr+2, variable_name) == 0) {
821 same_replace(tmp, same_copy(shell_item));
822 }
823 }
824 }
825 visit_end();
826 command_list = same_cat(command_list, new_commands);
827 }
828 return same_cat(command_list, same_copy(newline));
829 }
830
831
832 int
Getchar()833 Getchar()
834 {
835 if (last_saved) {
836 last_saved = 0;
837 return last_char;
838 } else {
839 int c;
840 c = getchar();
841 switch (c) {
842 case '\n':
843 lineno++;
844 column = 0;
845 break;
846 default:
847 column++;
848 }
849 return c;
850 }
851 }
852
853
854 int
token_type(string)855 token_type(string)
856 char *string;
857 {
858 switch (string[0]) {
859 case 'f':
860 if (strcmp(string, "for") == 0) {
861 return FOR;
862 }
863 break;
864 case 'd':
865 if (string[1] == 'o') {
866 if (strcmp(string, "do") == 0) {
867 return DO;
868 } else if (strcmp(string, "done") == 0) {
869 return DONE;
870 }
871 }
872 break;
873 case 'i':
874 if (strcmp(string, "in") == 0) {
875 return IN;
876 }
877 break;
878 default:
879 break;
880 }
881 return TOKEN;
882 }
883
884
yylex()885 yylex()
886 {
887 #define ret_token(c) if (bufptr != buffer) { \
888 save(c); \
889 *bufptr = 0; \
890 bufptr = buffer; \
891 yylval.string = string_lookup(buffer); \
892 return token_type(buffer); \
893 }
894 #define save(c) { last_char = c; last_saved = 1; }
895 #if defined(YYDEBUG)
896 #define Return(c) if (yydebug) { \
897 printf("[%d]", c); \
898 fflush(stdout); \
899 } \
900 yyval.intval = c; \
901 return c;
902 #else /* defined(YYDEBUG) */
903 #define Return(y,c) { yylval.intval = c; return y; }
904 #endif /* defined(YYDEBUG) */
905
906
907 static char buffer[500], *bufptr = buffer;
908 static int eof_found = 0;
909 int c;
910
911 if (eof_found != 0) {
912 eof_found++;
913 if (eof_found > 2) {
914 fprintf(stderr, "End of file ignored.\n");
915 exit(1);
916 }
917 Return(EOF,0);
918 }
919 while ((c = Getchar()) != EOF) {
920 switch (c) {
921 case '#':
922 ret_token(c);
923 while (((c = Getchar()) != EOF) && (c != '\n')) {
924 ;
925 }
926 save(c);
927 break;
928 case '<':
929 case '?':
930 ret_token(c);
931 Return(MACRO_CHAR, c);
932 case '\t':
933 case ' ':
934 ret_token(c);
935 Return(WHITE_SPACE, c);
936 case '-':
937 case '@':
938 case ':':
939 case ';':
940 case '=':
941 case '$':
942 case '{':
943 case '}':
944 case '(':
945 case ')':
946 ret_token(c);
947 Return(c,c);
948 case '\'':
949 case '"':
950 if (bufptr != buffer) {
951 if (bufptr[-1] == '\\') {
952 bufptr[-1] = c;
953 }
954 break;
955 } else {
956 int newc;
957
958 ret_token(c);
959 *bufptr++ = c;
960 while (((newc = Getchar()) != EOF) && (newc != c)) {
961 *bufptr++ = newc;
962 }
963 *bufptr++ = c;
964 *bufptr = 0;
965 bufptr = buffer;
966 yylval.string = string_lookup(buffer);
967 return QUOTED_STRING;
968 }
969 case '\n':
970 if (bufptr != buffer) {
971 if (bufptr[-1] == '\\') {
972 bufptr--;
973 if ((c = Getchar()) != '\t') {
974 yyerror("continuation line doesn't begin with a tab");
975 save(c);
976 }
977 ret_token(c);
978 Return(WHITE_SPACE, c);
979 }
980 }
981 ret_token(c);
982 Return(NL, 0);
983 default:
984 *bufptr++ = c;
985 break;
986 }
987 }
988
989 eof_found = 1;
990
991 ret_token(' ');
992 Return(EOF, 0);
993 }
994
main()995 main()
996 {
997 #define YYDEBUG
998 extern int yydebug;
999
1000 null = same_item(string_lookup(""));
1001 newline = same_item(string_lookup("\n"));
1002 blank = same_item(string_lookup(" "));
1003 cwd_line = same_cat(same_copy(newline),
1004 same_cat(same_item(string_lookup("cd ${CWD}")),
1005 same_copy(newline)));
1006
1007 yyparse();
1008
1009 do_dump();
1010
1011 return 0;
1012 }
1013
1014 #if defined(YYDEBUG)
dump_same(same)1015 dump_same(same)
1016 same_t *same;
1017 {
1018 same_t *same2;
1019
1020 for (visit(same, same2); !visited(same2); visit_next(same2)) {
1021 printf(same2->string->string);
1022 }
1023 visit_end();
1024 }
1025 #endif /* YYDEBUG */
1026
do_dump()1027 do_dump()
1028 {
1029 string_t *string;
1030 same_t *same, *same2;
1031
1032 if (yydebug > 1) {
1033 printf("strings...\n");
1034 for (string = strings; string; string = string->next) {
1035 printf("\t%s\n", string->string);
1036 }
1037 }
1038
1039 printf("# variables...\n");
1040 for (visit(variables, same); !visited(same); visit_next(same)) {
1041 printf("%s =\t", same->string->string);
1042 for (visit(same->value_list, same2); !visited(same2);
1043 visit_next(same2)) {
1044 printf(same2->string->string);
1045 }
1046 visit_end();
1047 printf("\n");
1048 }
1049 visit_end();
1050
1051 printf("\n\n#targets...\n");
1052 for (visit(targets, same); !visited(same); visit_next(same)) {
1053 printf("\n%s:\t", same->string->string);
1054 for (visit(same->depend_list, same2); !visited(same2);
1055 visit_next(same2)) {
1056 printf(same2->string->string);
1057 }
1058 visit_end();
1059 printf("\n\t");
1060 for (visit(same->action_list, same2); !visited(same2);
1061 visit_next(same2)) {
1062 printf(same2->string->string);
1063 if (same2->string->string[0] == '\n') {
1064 printf("\t");
1065 }
1066 }
1067 visit_end();
1068 printf("\n");
1069 }
1070 visit_end();
1071 }
1072