Commit | Line | Data |
---|---|---|
aebba157 GM |
1 | %{ |
2 | typedef struct string { | |
3 | int | |
4 | hashval, | |
5 | length; | |
6 | char | |
7 | *string; | |
8 | struct string | |
9 | *next; | |
10 | } string_t; | |
11 | ||
9b9748d9 GM |
12 | /* |
13 | * The deal with these is that they exist on various lists. | |
14 | * | |
15 | * First off, they are on a temporary list during the time they | |
16 | * are in the active focus of the parser. | |
17 | * | |
18 | * Secondly, they live on one of three queues: | |
19 | * 1. Variables | |
20 | * 2. Targets | |
21 | * 3. Actions | |
22 | * (and, we restrict any given one to live on one and only one such list) | |
23 | * | |
24 | * Also, they may live on the list of values for someone else's variable, | |
25 | * or as someone's dependancy. | |
26 | */ | |
27 | ||
aebba157 | 28 | typedef struct same { |
aebba157 | 29 | string_t |
9b9748d9 GM |
30 | *string; /* My name */ |
31 | struct same | |
32 | *nexttoken, /* Next pointer */ | |
33 | *lasttoken, /* Back pointer */ | |
34 | *depend_list, /* If target, dependancies */ | |
35 | *action_list, /* If target, actions */ | |
36 | *value_list; /* If variable, value list */ | |
aebba157 GM |
37 | } same_t; |
38 | ||
aebba157 GM |
39 | %} |
40 | ||
41 | %union { | |
42 | string_t *string; | |
43 | same_t *same; | |
9b9748d9 | 44 | int intval; |
aebba157 GM |
45 | } |
46 | ||
9b9748d9 GM |
47 | %token <string> TOKEN QUOTED_STRING |
48 | %token <intval> MACRO_CHAR BREAK_CHAR WHITE_SPACE NL END_OF_FILE | |
49 | %token <intval> ':' '=' '$' '{' '}' | |
aebba157 | 50 | %type <same> target assignment actions action tokens token |
9b9748d9 | 51 | %type <intval> special_chars white_space macro_char |
aebba157 | 52 | %% |
9b9748d9 | 53 | |
aebba157 GM |
54 | makefile : lines END_OF_FILE; |
55 | ||
56 | lines : line | |
57 | | lines line | |
58 | ; | |
59 | ||
9b9748d9 GM |
60 | line : maybe_white_space NL |
61 | | assignment | |
62 | | target_action | |
aebba157 GM |
63 | ; |
64 | ||
9b9748d9 GM |
65 | assignment : |
66 | token maybe_white_space '=' maybe_white_space tokens maybe_white_space NL | |
aebba157 | 67 | { |
9b9748d9 GM |
68 | assign($1, $5); |
69 | } | |
70 | | token maybe_white_space '=' maybe_white_space NL | |
71 | { | |
0859be39 | 72 | assign($1, same_copy(null)); |
aebba157 GM |
73 | } |
74 | ; | |
75 | ||
9b9748d9 GM |
76 | target_action: target actions |
77 | { | |
78 | add_targets_actions($1, $2); | |
79 | } | |
80 | | target | |
aebba157 | 81 | { |
0859be39 | 82 | add_targets_actions($1, same_copy(null)); |
9b9748d9 GM |
83 | } |
84 | ; | |
85 | ||
86 | target : | |
87 | tokens maybe_white_space ':' maybe_white_space tokens maybe_white_space NL | |
88 | { | |
89 | $$ = add_depends($1, $5); | |
90 | } | |
91 | | tokens maybe_white_space ':' maybe_white_space NL | |
92 | { | |
0859be39 | 93 | $$ = add_depends($1, same_copy(null)); |
aebba157 GM |
94 | } |
95 | ; | |
96 | ||
97 | actions: action | |
98 | | actions action | |
99 | { | |
9b9748d9 | 100 | $$ = same_cat($1, $2); |
aebba157 GM |
101 | } |
102 | ; | |
103 | ||
9b9748d9 | 104 | action: white_space tokens NL |
aebba157 GM |
105 | { |
106 | $$ = $2; | |
107 | } | |
108 | ; | |
109 | ||
110 | tokens : token | |
111 | | tokens token | |
112 | { | |
9b9748d9 | 113 | $$ = same_cat($1, $2); |
aebba157 GM |
114 | } |
115 | ; | |
9b9748d9 | 116 | |
aebba157 GM |
117 | token: TOKEN |
118 | { | |
9b9748d9 GM |
119 | $$ = same_item($1); |
120 | } | |
121 | | QUOTED_STRING | |
122 | { | |
123 | $$ = same_item($1); | |
124 | } | |
125 | | '$' macro_char | |
126 | { | |
127 | char buffer[3]; | |
128 | ||
129 | buffer[0] = '$'; | |
130 | buffer[1] = $2; | |
131 | buffer[2] = 0; | |
132 | ||
133 | $$ = same_item(string_lookup(buffer)); | |
134 | } | |
135 | | special_chars | |
136 | { | |
137 | char buffer[2]; | |
138 | ||
139 | buffer[0] = $1; | |
140 | buffer[1] = 0; | |
141 | ||
142 | $$ = same_item(string_lookup(buffer)); | |
143 | } | |
144 | | '$' '{' token '}' | |
145 | { | |
146 | $$ = same_copy(value_of($3)); | |
aebba157 GM |
147 | } |
148 | ; | |
9b9748d9 GM |
149 | |
150 | macro_char: MACRO_CHAR | |
151 | | '$' | |
152 | ; | |
153 | ||
154 | special_chars : BREAK_CHAR | |
155 | | MACRO_CHAR | |
156 | | white_space | |
157 | ; | |
158 | ||
159 | maybe_white_space: | |
160 | | white_space; | |
161 | ||
162 | white_space : WHITE_SPACE | |
163 | | white_space WHITE_SPACE | |
164 | ; | |
165 | ||
aebba157 GM |
166 | %% |
167 | #include <stdio.h> | |
168 | ||
169 | static int last_char, last_saved = 0; | |
170 | static int column = 0, lineno = 1; | |
171 | ||
172 | ||
9b9748d9 GM |
173 | static string_t |
174 | *strings = 0; | |
175 | static same_t | |
1d1968a6 GM |
176 | *variables = 0, |
177 | *targets = 0, | |
178 | *actions = 0; | |
9b9748d9 | 179 | |
aebba157 | 180 | static same_t |
0859be39 GM |
181 | *null, |
182 | *blank, | |
183 | *newline; | |
aebba157 GM |
184 | |
185 | extern char *malloc(); | |
186 | ||
0859be39 GM |
187 | static unsigned int |
188 | clock = -1; | |
189 | ||
190 | struct { | |
191 | same_t *first; | |
192 | int next; | |
193 | } visit_stack[20]; /* 20 maximum */ | |
194 | ||
195 | #define visit(what,via) \ | |
196 | (visit_stack[++clock].next = 0, visit_stack[clock].first = via = what) | |
1d1968a6 GM |
197 | #define visited(via) (((via) == 0) \ |
198 | || (visit_stack[clock].next && (via == visit_stack[clock].first))) | |
0859be39 GM |
199 | #define visit_next(via) (visit_stack[clock].next = 1, (via) = (via)->nexttoken) |
200 | #define visit_end() (clock--) | |
201 | ||
9b9748d9 GM |
202 | yyerror(s) |
203 | char *s; | |
aebba157 | 204 | { |
9b9748d9 GM |
205 | fprintf(stderr, "line %d, character %d: %s\n", lineno, column, s); |
206 | do_dump(); | |
207 | } | |
aebba157 | 208 | |
9b9748d9 GM |
209 | int |
210 | string_hashof(string, length) | |
211 | char *string; | |
212 | int length; | |
213 | { | |
214 | register int i = 0; | |
215 | ||
216 | while (length--) { | |
217 | i = (i<<3) + *string ^ ((i>>28)&0x7); | |
218 | } | |
219 | return i; | |
aebba157 GM |
220 | } |
221 | ||
9b9748d9 GM |
222 | int |
223 | string_same(s1, s2) | |
224 | string_t | |
225 | *s1, *s2; | |
aebba157 | 226 | { |
9b9748d9 GM |
227 | if ((s1->hashval == s2->hashval) && (s1->length == s2->length) |
228 | && (memcmp(s1->string, s2->string, s1->length) == 0)) { | |
229 | return 1; | |
230 | } else { | |
231 | return 0; | |
232 | } | |
aebba157 GM |
233 | } |
234 | ||
9b9748d9 GM |
235 | string_t * |
236 | string_lookup(string) | |
237 | char *string; | |
aebba157 | 238 | { |
9b9748d9 GM |
239 | string_t ours; |
240 | string_t *ptr; | |
241 | ||
242 | ours.length = strlen(string); | |
243 | ours.hashval = string_hashof(string, ours.length); | |
244 | ours.string = string; | |
245 | ||
246 | for (ptr = strings; ptr; ptr = ptr->next) { | |
247 | if (string_same(&ours, ptr)) { | |
248 | return ptr; | |
249 | } | |
250 | } | |
251 | if ((ptr = (string_t *)malloc(sizeof *ptr)) == 0) { | |
252 | fprintf(stderr, "No space to add string *%s*!\n", string); | |
253 | exit(1); | |
254 | } | |
255 | ptr->hashval = ours.hashval; | |
256 | ptr->length = ours.length; | |
257 | if ((ptr->string = malloc(ours.length+1)) == 0) { | |
258 | fprintf(stderr, "No space to add literal *%s*!\n", string); | |
259 | exit(1); | |
260 | } | |
261 | memcpy(ptr->string, string, ours.length+1); | |
262 | ptr->next = strings; | |
263 | strings = ptr; | |
264 | return ptr; | |
aebba157 GM |
265 | } |
266 | ||
267 | same_t * | |
9b9748d9 | 268 | same_search(list, token) |
aebba157 | 269 | same_t |
9b9748d9 GM |
270 | *list, |
271 | *token; | |
aebba157 | 272 | { |
9b9748d9 GM |
273 | same_t *ptr; |
274 | ||
0859be39 GM |
275 | ptr = list; |
276 | for (visit(list, ptr); !visited(ptr); visit_next(ptr)) { | |
9b9748d9 | 277 | string_t *string; |
aebba157 | 278 | |
9b9748d9 GM |
279 | string = ptr->string; |
280 | if (string_same(string, token->string)) { | |
0859be39 | 281 | visit_end(); |
9b9748d9 GM |
282 | return ptr; |
283 | } | |
284 | } | |
0859be39 | 285 | visit_end(); |
9b9748d9 GM |
286 | return 0; |
287 | } | |
aebba157 GM |
288 | |
289 | same_t * | |
9b9748d9 | 290 | same_cat(list, tokens) |
aebba157 | 291 | same_t |
9b9748d9 GM |
292 | *list, |
293 | *tokens; | |
aebba157 | 294 | { |
9b9748d9 | 295 | same_t *last; |
aebba157 | 296 | |
1d1968a6 GM |
297 | if (list) { |
298 | last = tokens->lasttoken; | |
299 | tokens->lasttoken = list->lasttoken; | |
300 | list->lasttoken = last; | |
301 | tokens->lasttoken->nexttoken = tokens; | |
302 | last->nexttoken = list; | |
303 | return list; | |
304 | } else { | |
305 | return tokens; | |
306 | } | |
aebba157 GM |
307 | } |
308 | ||
309 | same_t * | |
9b9748d9 | 310 | same_item(string) |
aebba157 GM |
311 | string_t *string; |
312 | { | |
313 | same_t *ptr; | |
314 | ||
315 | if ((ptr = (same_t *)malloc(sizeof *ptr)) == 0) { | |
316 | fprintf(stderr, "No more space for tokens!\n"); | |
317 | exit(1); | |
318 | } | |
9b9748d9 | 319 | memset((char *)ptr, 0, sizeof *ptr); |
0859be39 | 320 | ptr->nexttoken = ptr->lasttoken = ptr; |
aebba157 | 321 | ptr->string = string; |
aebba157 GM |
322 | return ptr; |
323 | } | |
324 | ||
9b9748d9 GM |
325 | same_t * |
326 | same_copy(same) | |
327 | same_t *same; | |
328 | { | |
0859be39 | 329 | same_t *head, *copy; |
9b9748d9 | 330 | |
1d1968a6 GM |
331 | head = 0; |
332 | for (visit(same, copy); !visited(copy); visit_next(copy)) { | |
9b9748d9 GM |
333 | same_t *ptr; |
334 | ||
0859be39 | 335 | ptr = same_item(copy->string); |
1d1968a6 | 336 | head = same_cat(head, ptr); |
9b9748d9 | 337 | } |
1d1968a6 | 338 | visit_end(); |
9b9748d9 GM |
339 | return head; |
340 | } | |
341 | ||
342 | void | |
0859be39 GM |
343 | same_free(list) |
344 | same_t *list; | |
9b9748d9 | 345 | { |
0859be39 | 346 | same_t *token, *ptr; |
9b9748d9 | 347 | |
0859be39 GM |
348 | token = list; |
349 | do { | |
9b9748d9 GM |
350 | ptr = token->nexttoken; |
351 | (void) free((char *)token); | |
352 | token = ptr; | |
0859be39 | 353 | } while (token != list); |
9b9748d9 GM |
354 | } |
355 | ||
356 | void | |
0859be39 | 357 | same_unlink(token) |
9b9748d9 | 358 | same_t |
0859be39 | 359 | *token; |
9b9748d9 | 360 | { |
1d1968a6 GM |
361 | if (token == 0) { |
362 | return; | |
363 | } | |
0859be39 GM |
364 | token->lasttoken->nexttoken = token->nexttoken; |
365 | token->nexttoken->lasttoken = token->lasttoken; | |
1d1968a6 | 366 | token->nexttoken = token->lasttoken = token; |
9b9748d9 GM |
367 | (void) free((char *) token); |
368 | } | |
369 | ||
370 | same_t * | |
371 | add_target(target) | |
372 | same_t | |
373 | *target; | |
374 | { | |
375 | same_t *ptr; | |
376 | ||
0859be39 | 377 | if ((ptr = same_search(targets, target)) == 0) { |
1d1968a6 GM |
378 | targets = same_cat(targets, target); |
379 | return target; | |
9b9748d9 | 380 | } else { |
1d1968a6 GM |
381 | ptr->action_list = same_cat(ptr->action_list, target->action_list); |
382 | ptr->depend_list = same_cat(ptr->depend_list, target->depend_list); | |
383 | return ptr; | |
9b9748d9 | 384 | } |
9b9748d9 GM |
385 | } |
386 | ||
387 | same_t * | |
388 | add_targets_actions(target, actions) | |
389 | same_t | |
390 | *target, | |
391 | *actions; | |
392 | { | |
1d1968a6 | 393 | same_t *ptr, *original = target; |
9b9748d9 | 394 | |
1d1968a6 GM |
395 | if (target == 0) { |
396 | return 0; | |
9b9748d9 | 397 | } |
1d1968a6 GM |
398 | do { |
399 | target->action_list = same_cat(target->action_list, | |
400 | same_copy(actions)); | |
401 | ptr = target->nexttoken; | |
402 | same_unlink(target); | |
403 | add_target(target); | |
404 | target = ptr; | |
405 | } while (target != original); | |
406 | ||
407 | same_free(actions); | |
9b9748d9 GM |
408 | return 0; |
409 | } | |
410 | ||
411 | same_t * | |
412 | add_depends(target, depends) | |
413 | same_t | |
414 | *target, | |
415 | *depends; | |
416 | { | |
417 | same_t *original = target; | |
418 | ||
1d1968a6 | 419 | depends = same_cat(depends, same_copy(blank)); /* Separator */ |
9b9748d9 | 420 | |
0859be39 | 421 | for (visit(original, target); !visited(target); visit_next(target)) { |
1d1968a6 | 422 | target->depend_list = same_cat(target->depend_list, same_copy(depends)); |
9b9748d9 | 423 | } |
0859be39 | 424 | visit_end(); |
1d1968a6 | 425 | same_free(depends); |
0859be39 | 426 | |
9b9748d9 GM |
427 | return original; |
428 | } | |
429 | ||
430 | ||
431 | /* | |
432 | * We know that variable is a singleton | |
433 | */ | |
434 | ||
435 | void | |
436 | assign(variable, value) | |
437 | same_t | |
438 | *variable, | |
439 | *value; | |
440 | { | |
441 | same_t *ptr; | |
442 | ||
0859be39 | 443 | if ((ptr = same_search(variables, variable)) != 0) { |
9b9748d9 | 444 | same_free(ptr->value_list); |
0859be39 | 445 | same_unlink(ptr); |
1d1968a6 | 446 | same_free(ptr); |
9b9748d9 GM |
447 | } |
448 | variable->value_list = value; | |
1d1968a6 | 449 | variables = same_cat(variables, variable); |
9b9748d9 GM |
450 | } |
451 | ||
452 | same_t * | |
453 | value_of(variable) | |
454 | same_t *variable; | |
455 | { | |
0859be39 | 456 | same_t *ptr = same_search(variables, variable); |
9b9748d9 GM |
457 | |
458 | if (ptr == 0) { | |
1d1968a6 | 459 | return same_copy(null); |
9b9748d9 | 460 | } else { |
1d1968a6 | 461 | return same_copy(ptr->value_list); |
9b9748d9 GM |
462 | } |
463 | } | |
464 | ||
465 | ||
aebba157 GM |
466 | int |
467 | Getchar() | |
468 | { | |
469 | if (last_saved) { | |
470 | last_saved = 0; | |
471 | return last_char; | |
472 | } else { | |
473 | int c; | |
474 | c = getchar(); | |
475 | switch (c) { | |
476 | case '\n': | |
477 | lineno++; | |
478 | column = 0; | |
479 | break; | |
480 | default: | |
481 | column++; | |
482 | } | |
483 | return c; | |
484 | } | |
485 | } | |
486 | ||
aebba157 GM |
487 | |
488 | yylex() | |
489 | { | |
490 | #define ret_token(c) if (bufptr != buffer) { \ | |
491 | save(c); \ | |
492 | *bufptr = 0; \ | |
493 | bufptr = buffer; \ | |
9b9748d9 | 494 | yylval.string = string_lookup(buffer); \ |
aebba157 GM |
495 | return TOKEN; \ |
496 | } | |
497 | #define save(c) { last_char = c; last_saved = 1; } | |
9b9748d9 | 498 | #if defined(YYDEBUG) |
aebba157 GM |
499 | #define Return(c) if (yydebug) { \ |
500 | printf("[%d]", c); \ | |
501 | fflush(stdout); \ | |
502 | } \ | |
9b9748d9 | 503 | yyval.intval = c; \ |
aebba157 | 504 | return c; |
9b9748d9 GM |
505 | #else /* defined(YYDEBUG) */ |
506 | #define Return(y,c) { yylval.intval = c; return y; } | |
507 | #endif /* defined(YYDEBUG) */ | |
aebba157 | 508 | |
9b9748d9 GM |
509 | |
510 | static char buffer[500], *bufptr = buffer; | |
aebba157 GM |
511 | static int eof_found = 0; |
512 | int c; | |
513 | ||
514 | if (eof_found != 0) { | |
515 | eof_found++; | |
516 | if (eof_found > 2) { | |
517 | fprintf(stderr, "End of file ignored.\n"); | |
518 | exit(1); | |
519 | } | |
9b9748d9 | 520 | Return(END_OF_FILE,0); |
aebba157 GM |
521 | } |
522 | while ((c = Getchar()) != EOF) { | |
523 | switch (c) { | |
524 | case '#': | |
525 | ret_token(c); | |
526 | while (((c = Getchar()) != EOF) && (c != '\n')) { | |
527 | ; | |
528 | } | |
529 | save(c); | |
530 | break; | |
9b9748d9 GM |
531 | case '@': |
532 | case '<': | |
533 | case '?': | |
534 | ret_token(c); | |
535 | Return(MACRO_CHAR, c); | |
536 | case '-': | |
537 | case '(': | |
538 | case ')': | |
539 | case ';': | |
540 | ret_token(c); | |
541 | Return(BREAK_CHAR, c); | |
aebba157 | 542 | case '\t': |
9b9748d9 | 543 | case ' ': |
aebba157 | 544 | ret_token(c); |
9b9748d9 | 545 | Return(WHITE_SPACE, c); |
aebba157 GM |
546 | case ':': |
547 | case '=': | |
9b9748d9 GM |
548 | case '$': |
549 | case '{': | |
550 | case '}': | |
aebba157 | 551 | ret_token(c); |
9b9748d9 GM |
552 | Return(c,c); |
553 | case '\'': | |
554 | case '"': | |
555 | { | |
556 | int newc; | |
557 | ||
558 | ret_token(c); | |
559 | *bufptr++ = c; | |
560 | while (((newc = Getchar()) != EOF) && (newc != c)) { | |
561 | *bufptr++ = newc; | |
562 | } | |
563 | *bufptr++ = c; | |
564 | *bufptr = 0; | |
565 | bufptr = buffer; | |
566 | yylval.string = string_lookup(buffer); | |
567 | return QUOTED_STRING; | |
568 | } | |
aebba157 GM |
569 | case '\n': |
570 | if (bufptr != buffer) { | |
571 | if (bufptr[-1] == '\\') { | |
572 | bufptr--; | |
9b9748d9 GM |
573 | if ((c = Getchar()) != '\t') { |
574 | yyerror("continuation line doesn't begin with a tab"); | |
575 | save(c); | |
576 | } | |
577 | ret_token(c); | |
578 | Return(WHITE_SPACE, c); | |
aebba157 GM |
579 | } |
580 | } | |
581 | ret_token(c); | |
9b9748d9 | 582 | Return(NL, 0); |
aebba157 GM |
583 | default: |
584 | *bufptr++ = c; | |
585 | break; | |
586 | } | |
587 | } | |
588 | ||
589 | eof_found = 1; | |
590 | ||
591 | ret_token(' '); | |
9b9748d9 GM |
592 | Return(END_OF_FILE, 0); |
593 | } | |
594 | ||
595 | main() | |
596 | { | |
597 | #define YYDEBUG | |
598 | extern int yydebug; | |
599 | ||
0859be39 GM |
600 | null = same_item(string_lookup("")); |
601 | newline = same_item(string_lookup("\n")); | |
602 | blank = same_item(string_lookup(" ")); | |
9b9748d9 | 603 | |
9b9748d9 GM |
604 | return yyparse(); |
605 | } | |
606 | ||
607 | #if defined(YYDEBUG) | |
608 | do_dump() | |
609 | { | |
610 | string_t *string; | |
611 | same_t *same, *same2; | |
612 | ||
613 | if (yydebug > 1) { | |
614 | printf("strings...\n"); | |
615 | for (string = strings; string; string = string->next) { | |
616 | printf("\t%s\n", string->string); | |
617 | } | |
618 | } | |
619 | ||
620 | printf("variables...\n"); | |
1d1968a6 | 621 | for (visit(variables, same); !visited(same); visit_next(same)) { |
9b9748d9 | 622 | printf("\t%s =\t", same->string->string); |
0859be39 GM |
623 | for (visit(same->value_list, same2); !visited(same2); |
624 | visit_next(same2)) { | |
9b9748d9 GM |
625 | printf(same2->string->string); |
626 | } | |
0859be39 | 627 | visit_end(); |
9b9748d9 GM |
628 | printf("\n"); |
629 | } | |
1d1968a6 | 630 | visit_end(); |
9b9748d9 GM |
631 | |
632 | printf("targets...\n"); | |
1d1968a6 | 633 | for (visit(targets, same); !visited(same); visit_next(same)) { |
9b9748d9 | 634 | printf("\t%s :\t", same->string->string); |
0859be39 GM |
635 | for (visit(same->depend_list, same2); !visited(same2); |
636 | visit_next(same2)) { | |
9b9748d9 GM |
637 | printf(same2->string->string); |
638 | } | |
0859be39 | 639 | visit_end(); |
1d1968a6 GM |
640 | printf("\n\t\t"); |
641 | for (visit(same->action_list, same2); !visited(same2); | |
642 | visit_next(same2)) { | |
643 | printf(same2->string->string); | |
644 | if (same2->string->string[0] == '\n') { | |
645 | printf("\t\t"); | |
9b9748d9 | 646 | } |
9b9748d9 | 647 | } |
1d1968a6 GM |
648 | visit_end(); |
649 | printf("\n"); | |
9b9748d9 | 650 | } |
1d1968a6 | 651 | visit_end(); |
aebba157 | 652 | } |
9b9748d9 | 653 | #endif /* YYDEBUG */ |