Mercurial > ~dholland > hg > tradcpp > index.cgi
comparison macro.c @ 19:f9792a9ec704
macro expansion.
author | David A. Holland |
---|---|
date | Mon, 20 Dec 2010 03:55:19 -0500 |
parents | c08a947d8f30 |
children | e3fab8f1b52c |
comparison
equal
deleted
inserted
replaced
18:c08a947d8f30 | 19:f9792a9ec704 |
---|---|
3 | 3 |
4 #include "array.h" | 4 #include "array.h" |
5 #include "mode.h" | 5 #include "mode.h" |
6 #include "place.h" | 6 #include "place.h" |
7 #include "macro.h" | 7 #include "macro.h" |
8 #include "output.h" | |
9 | |
10 struct expansionitem { | |
11 bool isstring; | |
12 union { | |
13 char *string; | |
14 unsigned param; | |
15 }; | |
16 }; | |
17 DECLARRAY(expansionitem); | |
18 DEFARRAY(expansionitem, ); | |
8 | 19 |
9 struct macro { | 20 struct macro { |
10 struct place defplace; | 21 struct place defplace; |
11 struct place expansionplace; | 22 struct place expansionplace; |
12 unsigned hash; | 23 unsigned hash; |
13 char *name; | 24 char *name; |
14 bool hasparams; | 25 bool hasparams; |
15 struct stringarray params; | 26 struct stringarray params; |
16 char *expansion; | 27 struct expansionitemarray expansion; |
28 bool inuse; | |
17 }; | 29 }; |
18 DECLARRAY(macro); | 30 DECLARRAY(macro); |
19 DEFARRAY(macro, ); | 31 DEFARRAY(macro, ); |
20 DECLARRAY(macroarray); | 32 DECLARRAY(macroarray); |
21 DEFARRAY(macroarray, ); | 33 DEFARRAY(macroarray, ); |
26 | 38 |
27 //////////////////////////////////////////////////////////// | 39 //////////////////////////////////////////////////////////// |
28 // macro structure ops | 40 // macro structure ops |
29 | 41 |
30 static | 42 static |
43 struct expansionitem * | |
44 expansionitem_create_string(const char *string) | |
45 { | |
46 struct expansionitem *ei; | |
47 | |
48 ei = domalloc(sizeof(*ei)); | |
49 ei->isstring = true; | |
50 ei->string = dostrdup(string); | |
51 return ei; | |
52 } | |
53 | |
54 static | |
55 struct expansionitem * | |
56 expansionitem_create_stringlen(const char *string, size_t len) | |
57 { | |
58 struct expansionitem *ei; | |
59 | |
60 ei = domalloc(sizeof(*ei)); | |
61 ei->isstring = true; | |
62 ei->string = dostrndup(string, len); | |
63 return ei; | |
64 } | |
65 | |
66 static | |
67 struct expansionitem * | |
68 expansionitem_create_param(unsigned param) | |
69 { | |
70 struct expansionitem *ei; | |
71 | |
72 ei = domalloc(sizeof(*ei)); | |
73 ei->isstring = false; | |
74 ei->param = param; | |
75 return ei; | |
76 } | |
77 | |
78 static | |
79 void | |
80 expansionitem_destroy(struct expansionitem *ei) | |
81 { | |
82 if (ei->isstring) { | |
83 free(ei->string); | |
84 } | |
85 free(ei); | |
86 } | |
87 | |
88 static | |
89 bool | |
90 expansionitem_eq(const struct expansionitem *ei1, | |
91 const struct expansionitem *ei2) | |
92 { | |
93 if (ei1->isstring != ei2->isstring) { | |
94 return false; | |
95 } | |
96 if (ei1->isstring) { | |
97 if (strcmp(ei1->string, ei2->string) != 0) { | |
98 return false; | |
99 } | |
100 } else { | |
101 if (ei1->param != ei2->param) { | |
102 return false; | |
103 } | |
104 } | |
105 return true; | |
106 } | |
107 | |
108 static | |
31 struct macro * | 109 struct macro * |
32 macro_create(struct place *p1, const char *name, unsigned hash, | 110 macro_create(struct place *p1, const char *name, unsigned hash, |
33 struct place *p2, const char *expansion) | 111 struct place *p2) |
34 { | 112 { |
35 struct macro *m; | 113 struct macro *m; |
36 | 114 |
37 m = domalloc(sizeof(*m)); | 115 m = domalloc(sizeof(*m)); |
38 m->defplace = *p1; | 116 m->defplace = *p1; |
39 m->expansionplace = *p2; | 117 m->expansionplace = *p2; |
40 m->hash = hash; | 118 m->hash = hash; |
41 m->name = dostrdup(name); | 119 m->name = dostrdup(name); |
42 m->hasparams = false; | 120 m->hasparams = false; |
43 stringarray_init(&m->params); | 121 stringarray_init(&m->params); |
44 m->expansion = dostrdup(expansion); | 122 expansionitemarray_init(&m->expansion); |
123 m->inuse = false; | |
45 return m; | 124 return m; |
46 } | 125 } |
47 | 126 |
127 DESTROYALL_ARRAY(expansionitem, ); | |
128 | |
48 static | 129 static |
49 void | 130 void |
50 macro_destroy(struct macro *m) | 131 macro_destroy(struct macro *m) |
51 { | 132 { |
133 expansionitemarray_destroyall(&m->expansion); | |
134 expansionitemarray_cleanup(&m->expansion); | |
52 free(m->name); | 135 free(m->name); |
53 free(m->expansion); | |
54 free(m); | 136 free(m); |
55 } | 137 } |
56 | 138 |
57 static | 139 static |
58 bool | 140 bool |
59 macro_eq(const struct macro *m1, const struct macro *m2) | 141 macro_eq(const struct macro *m1, const struct macro *m2) |
60 { | 142 { |
61 unsigned num1, num2, i; | 143 unsigned num1, num2, i; |
144 struct expansionitem *ei1, *ei2; | |
62 const char *p1, *p2; | 145 const char *p1, *p2; |
63 | 146 |
64 if (strcmp(m1->name, m2->name) != 0) { | 147 if (strcmp(m1->name, m2->name) != 0) { |
65 return false; | 148 return false; |
66 } | 149 } |
67 | 150 |
68 if (m1->hasparams != m2->hasparams) { | 151 if (m1->hasparams != m2->hasparams) { |
69 return false; | 152 return false; |
70 } | 153 } |
71 | 154 |
72 if (strcmp(m1->expansion, m2->expansion) != 0) { | 155 num1 = expansionitemarray_num(&m1->expansion); |
156 num2 = expansionitemarray_num(&m2->expansion); | |
157 if (num1 != num2) { | |
73 return false; | 158 return false; |
159 } | |
160 | |
161 for (i=0; i<num1; i++) { | |
162 ei1 = expansionitemarray_get(&m1->expansion, i); | |
163 ei2 = expansionitemarray_get(&m2->expansion, i); | |
164 if (!expansionitem_eq(ei1, ei2)) { | |
165 return false; | |
166 } | |
74 } | 167 } |
75 | 168 |
76 num1 = stringarray_num(&m1->params); | 169 num1 = stringarray_num(&m1->params); |
77 num2 = stringarray_num(&m2->params); | 170 num2 = stringarray_num(&m2->params); |
78 if (num1 != num2) { | 171 if (num1 != num2) { |
97 * that showed up in Dr. Dobbs in, according to my notes, May 1992. The | 190 * that showed up in Dr. Dobbs in, according to my notes, May 1992. The |
98 * implementation is new. | 191 * implementation is new. |
99 */ | 192 */ |
100 static | 193 static |
101 unsigned | 194 unsigned |
102 hashfunc(const char *s) | 195 hashfunc(const char *s, size_t len) |
103 { | 196 { |
104 uint16_t x1, x2, a; | 197 uint16_t x1, x2, a; |
105 size_t i, len; | 198 size_t i; |
106 | |
107 len = strlen(s); | |
108 | 199 |
109 x1 = (uint16_t) (len >> 16); | 200 x1 = (uint16_t) (len >> 16); |
110 x2 = (uint16_t) (len); | 201 x2 = (uint16_t) (len); |
111 if (x1==0) { | 202 if (x1==0) { |
112 x1++; | 203 x1++; |
173 macroarrayarray_cleanup(¯os); | 264 macroarrayarray_cleanup(¯os); |
174 } | 265 } |
175 | 266 |
176 static | 267 static |
177 struct macro * | 268 struct macro * |
178 macrotable_find(const char *name, bool remove) | 269 macrotable_findlen(const char *name, size_t len, bool remove) |
179 { | 270 { |
180 unsigned hash; | 271 unsigned hash; |
181 struct macroarray *bucket; | 272 struct macroarray *bucket; |
182 struct macro *m, *m2; | 273 struct macro *m, *m2; |
183 unsigned i, num; | 274 unsigned i, num; |
184 | 275 size_t mlen; |
185 hash = hashfunc(name); | 276 |
277 hash = hashfunc(name, len); | |
186 bucket = macroarrayarray_get(¯os, hash & hashmask); | 278 bucket = macroarrayarray_get(¯os, hash & hashmask); |
187 if (bucket == NULL) { | 279 if (bucket == NULL) { |
188 return NULL; | 280 return NULL; |
189 } | 281 } |
190 num = macroarray_num(bucket); | 282 num = macroarray_num(bucket); |
191 for (i=0; i<num; i++) { | 283 for (i=0; i<num; i++) { |
192 m = macroarray_get(bucket, i); | 284 m = macroarray_get(bucket, i); |
193 if (hash != m->hash) { | 285 if (hash != m->hash) { |
194 continue; | 286 continue; |
195 } | 287 } |
196 if (!strcmp(name, m->name)) { | 288 mlen = strlen(m->name); |
289 if (len == mlen && !memcmp(name, m->name, len)) { | |
197 if (remove) { | 290 if (remove) { |
198 if (i < num-1) { | 291 if (i < num-1) { |
199 m2 = macroarray_get(bucket, num-1); | 292 m2 = macroarray_get(bucket, num-1); |
200 macroarray_set(bucket, i, m2); | 293 macroarray_set(bucket, i, m2); |
201 } | 294 } |
204 } | 297 } |
205 return m; | 298 return m; |
206 } | 299 } |
207 } | 300 } |
208 return NULL; | 301 return NULL; |
302 } | |
303 | |
304 static | |
305 struct macro * | |
306 macrotable_find(const char *name, bool remove) | |
307 { | |
308 return macrotable_findlen(name, strlen(name), remove); | |
209 } | 309 } |
210 | 310 |
211 static | 311 static |
212 void | 312 void |
213 macrotable_rehash(void) | 313 macrotable_rehash(void) |
262 numbuckets = macroarrayarray_num(¯os); | 362 numbuckets = macroarrayarray_num(¯os); |
263 if (total_macros > 0 && total_macros / numbuckets > 9) { | 363 if (total_macros > 0 && total_macros / numbuckets > 9) { |
264 macrotable_rehash(); | 364 macrotable_rehash(); |
265 } | 365 } |
266 | 366 |
267 hash = hashfunc(m->name); | 367 hash = hashfunc(m->name, strlen(m->name)); |
268 bucket = macroarrayarray_get(¯os, hash & hashmask); | 368 bucket = macroarrayarray_get(¯os, hash & hashmask); |
269 if (bucket == NULL) { | 369 if (bucket == NULL) { |
270 bucket = macroarray_create(); | 370 bucket = macroarray_create(); |
271 macroarrayarray_set(¯os, hash & hashmask, bucket); | 371 macroarrayarray_set(¯os, hash & hashmask, bucket); |
272 } | 372 } |
278 // external macro definition interface | 378 // external macro definition interface |
279 | 379 |
280 static | 380 static |
281 struct macro * | 381 struct macro * |
282 macro_define_common_start(struct place *p1, const char *macro, | 382 macro_define_common_start(struct place *p1, const char *macro, |
283 struct place *p2, const char *expansion) | 383 struct place *p2) |
284 { | 384 { |
285 struct macro *m; | 385 struct macro *m; |
386 unsigned hash; | |
286 | 387 |
287 if (!is_identifier(macro)) { | 388 if (!is_identifier(macro)) { |
288 complain(p1, "Invalid macro name %s", macro); | 389 complain(p1, "Invalid macro name %s", macro); |
289 complain_fail(); | 390 complain_fail(); |
290 } | 391 } |
291 | 392 |
292 m = macro_create(p1, macro, hashfunc(macro), p2, expansion); | 393 hash = hashfunc(macro, strlen(macro)); |
394 m = macro_create(p1, macro, hash, p2); | |
293 return m; | 395 return m; |
294 } | 396 } |
295 | 397 |
296 static | 398 static |
297 void | 399 void |
353 params = s; | 455 params = s; |
354 p->column += len; | 456 p->column += len; |
355 } | 457 } |
356 } | 458 } |
357 | 459 |
460 static | |
461 bool | |
462 isparam(struct macro *m, const char *name, size_t len, unsigned *num_ret) | |
463 { | |
464 unsigned num, i; | |
465 const char *param; | |
466 | |
467 num = stringarray_num(&m->params); | |
468 for (i=0; i<num; i++) { | |
469 param = stringarray_get(&m->params, i); | |
470 if (strlen(param) == len && !strcmp(name, param)) { | |
471 *num_ret = i; | |
472 return true; | |
473 } | |
474 } | |
475 return false; | |
476 } | |
477 | |
478 static | |
479 void | |
480 macro_parse_expansion(struct macro *m, const char *buf) | |
481 { | |
482 size_t blockstart, wordstart, pos; | |
483 struct expansionitem *ei; | |
484 unsigned param; | |
485 | |
486 pos = blockstart = 0; | |
487 while (buf[pos] != '\0') { | |
488 pos += strspn(buf+pos, ws); | |
489 if (strchr(alnum, buf[pos])) { | |
490 wordstart = pos; | |
491 pos += strspn(buf+pos, alnum); | |
492 if (isparam(m, buf+wordstart, pos-wordstart, ¶m)) { | |
493 if (pos > blockstart) { | |
494 ei = expansionitem_create_stringlen( | |
495 buf + blockstart, | |
496 blockstart - pos); | |
497 expansionitemarray_add(&m->expansion, | |
498 ei, NULL); | |
499 } | |
500 ei = expansionitem_create_param(param); | |
501 expansionitemarray_add(&m->expansion, ei,NULL); | |
502 blockstart = pos; | |
503 continue; | |
504 } | |
505 continue; | |
506 } | |
507 pos++; | |
508 } | |
509 if (pos > blockstart) { | |
510 ei = expansionitem_create_stringlen(buf + blockstart, | |
511 blockstart - pos); | |
512 expansionitemarray_add(&m->expansion, ei, NULL); | |
513 } | |
514 } | |
515 | |
358 void | 516 void |
359 macro_define_plain(struct place *p1, const char *macro, | 517 macro_define_plain(struct place *p1, const char *macro, |
360 struct place *p2, const char *expansion) | 518 struct place *p2, const char *expansion) |
361 { | 519 { |
362 struct macro *m; | 520 struct macro *m; |
363 | 521 struct expansionitem *ei; |
364 m = macro_define_common_start(p1, macro, p2, expansion); | 522 |
523 m = macro_define_common_start(p1, macro, p2); | |
524 ei = expansionitem_create_string(expansion); | |
525 expansionitemarray_add(&m->expansion, ei, NULL); | |
365 macro_define_common_end(m); | 526 macro_define_common_end(m); |
366 } | 527 } |
367 | 528 |
368 void | 529 void |
369 macro_define_params(struct place *p1, const char *macro, | 530 macro_define_params(struct place *p1, const char *macro, |
370 struct place *p2, const char *params, | 531 struct place *p2, const char *params, |
371 struct place *p3, const char *expansion) | 532 struct place *p3, const char *expansion) |
372 { | 533 { |
373 struct macro *m; | 534 struct macro *m; |
374 | 535 |
375 m = macro_define_common_start(p1, macro, p3, expansion); | 536 m = macro_define_common_start(p1, macro, p3); |
376 macro_parse_parameters(m, p2, params); | 537 macro_parse_parameters(m, p2, params); |
538 macro_parse_expansion(m, expansion); | |
377 macro_define_common_end(m); | 539 macro_define_common_end(m); |
378 } | 540 } |
379 | 541 |
380 void | 542 void |
381 macro_undef(const char *macro) | 543 macro_undef(const char *macro) |
398 } | 560 } |
399 | 561 |
400 //////////////////////////////////////////////////////////// | 562 //////////////////////////////////////////////////////////// |
401 // macro expansion | 563 // macro expansion |
402 | 564 |
403 char *macroexpand(struct place *, char *buf, size_t len, bool honordefined); | 565 struct expstate { |
404 | 566 bool honordefined; |
405 void macro_sendline(struct place *, char *buf, size_t len); | 567 enum { ES_NORMAL, ES_WANTLPAREN, ES_NOARG, ES_HAVEARG } state; |
406 void macro_sendeof(struct place *); | 568 struct macro *curmacro; |
569 struct stringarray args; | |
570 unsigned argparens; | |
571 | |
572 bool tobuf; | |
573 char *buf; | |
574 size_t bufpos, bufmax; | |
575 }; | |
576 | |
577 static struct expstate mainstate; | |
578 | |
579 static void doexpand(struct expstate *es, struct place *p, | |
580 char *buf, size_t len); | |
581 | |
582 static | |
583 void | |
584 expstate_init(struct expstate *es, bool tobuf, bool honordefined) | |
585 { | |
586 es->honordefined = honordefined; | |
587 es->state = ES_NORMAL; | |
588 es->curmacro = NULL; | |
589 stringarray_init(&es->args); | |
590 es->argparens = 0; | |
591 es->tobuf = tobuf; | |
592 es->buf = NULL; | |
593 es->bufpos = 0; | |
594 es->bufmax = 0; | |
595 } | |
596 | |
597 static | |
598 void | |
599 expstate_cleanup(struct expstate *es) | |
600 { | |
601 assert(es->state == ES_NORMAL); | |
602 stringarray_cleanup(&es->args); | |
603 if (es->buf) { | |
604 free(es->buf); | |
605 } | |
606 } | |
607 | |
608 static | |
609 void | |
610 expstate_destroyargs(struct expstate *es) | |
611 { | |
612 unsigned i, num; | |
613 | |
614 num = stringarray_num(&es->args); | |
615 for (i=0; i<num; i++) { | |
616 free(stringarray_get(&es->args, i)); | |
617 } | |
618 stringarray_setsize(&es->args, 0); | |
619 } | |
620 | |
621 static | |
622 void | |
623 expand_send(struct expstate *es, const char *buf, size_t len) | |
624 { | |
625 if (es->tobuf) { | |
626 if (es->bufpos + len > es->bufmax) { | |
627 if (es->bufmax == 0) { | |
628 es->bufmax = 64; | |
629 } | |
630 while (es->bufpos + len > es->bufmax) { | |
631 es->bufmax *= 2; | |
632 } | |
633 es->buf = dorealloc(es->buf, es->bufmax); | |
634 } | |
635 memcpy(es->buf + es->bufpos, buf, len); | |
636 es->bufpos += len; | |
637 } else { | |
638 output(buf, len); | |
639 } | |
640 } | |
641 | |
642 static | |
643 void | |
644 expand_send_eof(struct expstate *es) | |
645 { | |
646 if (es->tobuf) { | |
647 expand_send(es, "", 1); | |
648 es->bufpos--; | |
649 } else { | |
650 output_eof(); | |
651 } | |
652 } | |
653 | |
654 static | |
655 void | |
656 expand_newarg(struct expstate *es, char *buf, size_t len) | |
657 { | |
658 char *text; | |
659 | |
660 text = dostrndup(buf, len); | |
661 stringarray_add(&es->args, text, NULL); | |
662 } | |
663 | |
664 static | |
665 void | |
666 expand_appendarg(struct expstate *es, char *buf, size_t len) | |
667 { | |
668 unsigned num; | |
669 char *text; | |
670 size_t oldlen; | |
671 | |
672 num = stringarray_num(&es->args); | |
673 assert(num > 0); | |
674 | |
675 text = stringarray_get(&es->args, num - 1); | |
676 oldlen = strlen(text); | |
677 text = dorealloc(text, oldlen + len + 1); | |
678 memcpy(text + oldlen, buf, len); | |
679 text[oldlen+len] = '\0'; | |
680 stringarray_set(&es->args, num - 1, text); | |
681 } | |
682 | |
683 static | |
684 char * | |
685 expand_substitute(struct expstate *es) | |
686 { | |
687 struct expansionitem *ei; | |
688 unsigned i, num; | |
689 size_t len; | |
690 char *arg; | |
691 char *ret; | |
692 | |
693 len = 0; | |
694 num = expansionitemarray_num(&es->curmacro->expansion); | |
695 for (i=0; i<num; i++) { | |
696 ei = expansionitemarray_get(&es->curmacro->expansion, i); | |
697 if (ei->isstring) { | |
698 len += strlen(ei->string); | |
699 } else { | |
700 arg = stringarray_get(&es->args, ei->param); | |
701 len += strlen(arg); | |
702 } | |
703 } | |
704 | |
705 ret = domalloc(len+1); | |
706 *ret = '\0'; | |
707 for (i=0; i<num; i++) { | |
708 ei = expansionitemarray_get(&es->curmacro->expansion, i); | |
709 if (ei->isstring) { | |
710 strcat(ret, ei->string); | |
711 } else { | |
712 arg = stringarray_get(&es->args, ei->param); | |
713 strcat(ret, arg); | |
714 } | |
715 } | |
716 | |
717 return ret; | |
718 } | |
719 | |
720 static | |
721 void | |
722 expand_domacro(struct expstate *es, struct place *p) | |
723 { | |
724 struct macro *m; | |
725 char *newbuf, *newbuf2; | |
726 | |
727 if (es->curmacro == NULL) { | |
728 /* defined() */ | |
729 if (stringarray_num(&es->args) != 1) { | |
730 complain(p, "Too many arguments for defined()"); | |
731 complain_fail(); | |
732 expand_send(es, "0", 1); | |
733 return; | |
734 } | |
735 m = macrotable_find(stringarray_get(&es->args, 0), false); | |
736 expand_send(es, (m != NULL) ? "1" : "0", 1); | |
737 return; | |
738 } | |
739 | |
740 assert(es->curmacro->inuse == false); | |
741 es->curmacro->inuse = true; | |
742 | |
743 newbuf = expand_substitute(es); | |
744 newbuf2 = macroexpand(p, newbuf, strlen(newbuf), false); | |
745 free(newbuf); | |
746 doexpand(es, p, newbuf2, strlen(newbuf2)); | |
747 free(newbuf2); | |
748 | |
749 es->curmacro->inuse = false; | |
750 } | |
751 | |
752 static | |
753 void | |
754 expand_got_ws(struct expstate *es, struct place *p, char *buf, size_t len) | |
755 { | |
756 switch (es->state) { | |
757 case ES_NORMAL: | |
758 expand_send(es, buf, len); | |
759 break; | |
760 break; | |
761 case ES_WANTLPAREN: | |
762 break; | |
763 case ES_NOARG: | |
764 break; | |
765 case ES_HAVEARG: | |
766 expand_appendarg(es, buf, len); | |
767 break; | |
768 } | |
769 } | |
770 | |
771 static | |
772 void | |
773 expand_got_word(struct expstate *es, struct place *p, char *buf, size_t len) | |
774 { | |
775 struct macro *m; | |
776 struct expansionitem *ei; | |
777 char *newbuf; | |
778 | |
779 switch (es->state) { | |
780 case ES_NORMAL: | |
781 if (es->honordefined && | |
782 len == 7 && !memcmp(buf, "defined", 7)) { | |
783 es->curmacro = NULL; | |
784 es->state = ES_WANTLPAREN; | |
785 break; | |
786 } | |
787 m = macrotable_findlen(buf, len, false); | |
788 if (m == NULL) { | |
789 expand_send(es, buf, len); | |
790 } else if (!m->hasparams) { | |
791 m->inuse = true; | |
792 assert(expansionitemarray_num(&m->expansion) == 1); | |
793 ei = expansionitemarray_get(&m->expansion, 0); | |
794 assert(ei->isstring); | |
795 newbuf = macroexpand(p, ei->string, | |
796 strlen(ei->string), false); | |
797 doexpand(es, p, newbuf, strlen(newbuf)); | |
798 free(newbuf); | |
799 m->inuse = false; | |
800 } else { | |
801 es->curmacro = m; | |
802 es->state = ES_WANTLPAREN; | |
803 } | |
804 break; | |
805 case ES_WANTLPAREN: | |
806 if (es->curmacro != NULL) { | |
807 complain(p, "Expected arguments for macro %s", | |
808 es->curmacro->name); | |
809 complain_fail(); | |
810 } else { | |
811 /* "defined foo" means "defined(foo)" */ | |
812 expand_newarg(es, buf, len); | |
813 es->state = ES_NORMAL; | |
814 expand_domacro(es, p); | |
815 break; | |
816 } | |
817 break; | |
818 case ES_NOARG: | |
819 expand_newarg(es, buf, len); | |
820 es->state = ES_HAVEARG; | |
821 break; | |
822 case ES_HAVEARG: | |
823 expand_appendarg(es, buf, len); | |
824 break; | |
825 } | |
826 } | |
827 | |
828 static | |
829 void | |
830 expand_got_lparen(struct expstate *es, struct place *p, char *buf, size_t len) | |
831 { | |
832 switch (es->state) { | |
833 case ES_NORMAL: | |
834 expand_send(es, buf, len); | |
835 break; | |
836 case ES_WANTLPAREN: | |
837 es->state = ES_NOARG; | |
838 break; | |
839 case ES_NOARG: | |
840 expand_newarg(es, buf, len); | |
841 es->state = ES_HAVEARG; | |
842 es->argparens++; | |
843 break; | |
844 case ES_HAVEARG: | |
845 expand_appendarg(es, buf, len); | |
846 es->argparens++; | |
847 break; | |
848 } | |
849 } | |
850 | |
851 static | |
852 void | |
853 expand_got_rparen(struct expstate *es, struct place *p, char *buf, size_t len) | |
854 { | |
855 switch (es->state) { | |
856 case ES_NORMAL: | |
857 expand_send(es, buf, len); | |
858 break; | |
859 case ES_WANTLPAREN: | |
860 if (es->curmacro) { | |
861 complain(p, "Expected arguments for macro %s", | |
862 es->curmacro->name); | |
863 } else { | |
864 complain(p, "Expected arguments for defined()"); | |
865 } | |
866 complain_fail(); | |
867 break; | |
868 case ES_NOARG: | |
869 assert(es->argparens == 0); | |
870 es->state = ES_NORMAL; | |
871 expand_domacro(es, p); | |
872 break; | |
873 case ES_HAVEARG: | |
874 if (es->argparens > 0) { | |
875 es->argparens--; | |
876 expand_appendarg(es, buf, len); | |
877 } else { | |
878 es->state = ES_NORMAL; | |
879 expand_domacro(es, p); | |
880 } | |
881 break; | |
882 } | |
883 } | |
884 | |
885 static | |
886 void | |
887 expand_got_comma(struct expstate *es, struct place *p, char *buf, size_t len) | |
888 { | |
889 switch (es->state) { | |
890 case ES_NORMAL: | |
891 expand_send(es, buf, len); | |
892 break; | |
893 case ES_WANTLPAREN: | |
894 if (es->curmacro) { | |
895 complain(p, "Expected arguments for macro %s", | |
896 es->curmacro->name); | |
897 } else { | |
898 complain(p, "Expected arguments for defined()"); | |
899 } | |
900 complain_fail(); | |
901 break; | |
902 case ES_NOARG: | |
903 assert(es->argparens == 0); | |
904 expand_newarg(es, buf, 0); | |
905 break; | |
906 case ES_HAVEARG: | |
907 if (es->argparens > 0) { | |
908 expand_appendarg(es, buf, len); | |
909 } else { | |
910 es->state = ES_NOARG; | |
911 } | |
912 break; | |
913 } | |
914 } | |
915 | |
916 static | |
917 void | |
918 expand_got_other(struct expstate *es, struct place *p, char *buf, size_t len) | |
919 { | |
920 switch (es->state) { | |
921 case ES_NORMAL: | |
922 expand_send(es, buf, len); | |
923 break; | |
924 case ES_WANTLPAREN: | |
925 if (es->curmacro) { | |
926 complain(p, "Expected arguments for macro %s", | |
927 es->curmacro->name); | |
928 } else { | |
929 complain(p, "Expected arguments for defined()"); | |
930 } | |
931 complain_fail(); | |
932 break; | |
933 case ES_NOARG: | |
934 expand_newarg(es, buf, len); | |
935 es->state = ES_HAVEARG; | |
936 break; | |
937 case ES_HAVEARG: | |
938 expand_appendarg(es, buf, len); | |
939 break; | |
940 } | |
941 } | |
942 | |
943 static | |
944 void | |
945 expand_got_eof(struct expstate *es, struct place *p) | |
946 { | |
947 switch (es->state) { | |
948 case ES_NORMAL: | |
949 expand_send_eof(es); | |
950 break; | |
951 case ES_WANTLPAREN: | |
952 if (es->curmacro) { | |
953 complain(p, "Expected arguments for macro %s", | |
954 es->curmacro->name); | |
955 } else { | |
956 complain(p, "Expected arguments for defined()"); | |
957 } | |
958 complain_fail(); | |
959 break; | |
960 case ES_NOARG: | |
961 case ES_HAVEARG: | |
962 if (es->curmacro) { | |
963 complain(p, "Unclosed argument list for macro %s", | |
964 es->curmacro->name); | |
965 } else { | |
966 complain(p, "Unclosed argument list for defined()"); | |
967 } | |
968 complain_fail(); | |
969 expstate_destroyargs(es); | |
970 break; | |
971 } | |
972 es->state = ES_NORMAL; | |
973 es->curmacro = NULL; | |
974 es->argparens = 0; | |
975 } | |
976 | |
977 static | |
978 void | |
979 doexpand(struct expstate *es, struct place *p, char *buf, size_t len) | |
980 { | |
981 size_t x; | |
982 | |
983 while (len > 0) { | |
984 x = strspn(buf, ws); | |
985 if (x > 0) { | |
986 expand_got_ws(es, p, buf, x); | |
987 buf += x; | |
988 len -= x; | |
989 } | |
990 | |
991 x = strspn(buf, alnum); | |
992 if (x > 0) { | |
993 expand_got_word(es, p, buf, x); | |
994 buf += x; | |
995 len -= x; | |
996 continue; | |
997 } | |
998 | |
999 if (buf[0] == '(') { | |
1000 expand_got_lparen(es, p, buf, 1); | |
1001 buf++; | |
1002 len--; | |
1003 continue; | |
1004 } | |
1005 | |
1006 if (buf[0] == ')') { | |
1007 expand_got_rparen(es, p, buf, 1); | |
1008 buf++; | |
1009 len--; | |
1010 continue; | |
1011 } | |
1012 | |
1013 if (buf[0] == ',') { | |
1014 expand_got_comma(es, p, buf, 1); | |
1015 buf++; | |
1016 len--; | |
1017 continue; | |
1018 } | |
1019 | |
1020 expand_got_other(es, p, buf, 1); | |
1021 buf++; | |
1022 len--; | |
1023 } | |
1024 } | |
1025 | |
1026 char * | |
1027 macroexpand(struct place *p, char *buf, size_t len, bool honordefined) | |
1028 { | |
1029 struct expstate es; | |
1030 char *ret; | |
1031 | |
1032 expstate_init(&es, true, honordefined); | |
1033 doexpand(&es, p, buf, len); | |
1034 expand_got_eof(&es, p); | |
1035 ret = es.buf; | |
1036 es.buf = NULL; | |
1037 expstate_cleanup(&es); | |
1038 | |
1039 return ret; | |
1040 } | |
1041 | |
1042 void | |
1043 macro_sendline(struct place *p, char *buf, size_t len) | |
1044 { | |
1045 doexpand(&mainstate, p, buf, len); | |
1046 } | |
1047 | |
1048 void | |
1049 macro_sendeof(struct place *p) | |
1050 { | |
1051 expand_got_eof(&mainstate, p); | |
1052 } | |
407 | 1053 |
408 //////////////////////////////////////////////////////////// | 1054 //////////////////////////////////////////////////////////// |
409 // module initialization | 1055 // module initialization |
410 | 1056 |
411 void | 1057 void |
412 macros_init(void) | 1058 macros_init(void) |
413 { | 1059 { |
414 macrotable_init(); | 1060 macrotable_init(); |
1061 expstate_init(&mainstate, false, false); | |
415 } | 1062 } |
416 | 1063 |
417 void | 1064 void |
418 macros_cleanup(void) | 1065 macros_cleanup(void) |
419 { | 1066 { |
1067 expstate_cleanup(&mainstate); | |
420 macrotable_cleanup(); | 1068 macrotable_cleanup(); |
421 } | 1069 } |