2 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
3 * Released under the terms of the GNU GPL v2.0.
10 #define LKC_DIRECT_LINK
15 struct expr *expr_alloc_symbol(struct symbol *sym)
17 struct expr *e = malloc(sizeof(*e));
18 memset(e, 0, sizeof(*e));
24 struct expr *expr_alloc_one(enum expr_type type, struct expr *ce)
26 struct expr *e = malloc(sizeof(*e));
27 memset(e, 0, sizeof(*e));
33 struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2)
35 struct expr *e = malloc(sizeof(*e));
36 memset(e, 0, sizeof(*e));
43 struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2)
45 struct expr *e = malloc(sizeof(*e));
46 memset(e, 0, sizeof(*e));
53 struct expr *expr_alloc_and(struct expr *e1, struct expr *e2)
57 return e2 ? expr_alloc_two(E_AND, e1, e2) : e1;
60 struct expr *expr_alloc_or(struct expr *e1, struct expr *e2)
64 return e2 ? expr_alloc_two(E_OR, e1, e2) : e1;
67 struct expr *expr_copy(struct expr *org)
74 e = malloc(sizeof(*org));
75 memcpy(e, org, sizeof(*org));
81 e->left.expr = expr_copy(org->left.expr);
85 e->left.sym = org->left.sym;
86 e->right.sym = org->right.sym;
91 e->left.expr = expr_copy(org->left.expr);
92 e->right.expr = expr_copy(org->right.expr);
95 printf("can't copy type %d\n", e->type);
104 void expr_free(struct expr *e)
113 expr_free(e->left.expr);
120 expr_free(e->left.expr);
121 expr_free(e->right.expr);
124 printf("how to free type %d?\n", e->type);
130 static int trans_count;
135 static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct expr **ep2)
137 if (e1->type == type) {
138 __expr_eliminate_eq(type, &e1->left.expr, &e2);
139 __expr_eliminate_eq(type, &e1->right.expr, &e2);
142 if (e2->type == type) {
143 __expr_eliminate_eq(type, &e1, &e2->left.expr);
144 __expr_eliminate_eq(type, &e1, &e2->right.expr);
147 if (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
148 e1->left.sym == e2->left.sym && (e1->left.sym->flags & (SYMBOL_YES|SYMBOL_NO)))
150 if (!expr_eq(e1, e2))
153 expr_free(e1); expr_free(e2);
156 e1 = expr_alloc_symbol(&symbol_no);
157 e2 = expr_alloc_symbol(&symbol_no);
160 e1 = expr_alloc_symbol(&symbol_yes);
161 e2 = expr_alloc_symbol(&symbol_yes);
168 void expr_eliminate_eq(struct expr **ep1, struct expr **ep2)
175 __expr_eliminate_eq(e1->type, ep1, ep2);
179 if (e1->type != e2->type) switch (e2->type) {
182 __expr_eliminate_eq(e2->type, ep1, ep2);
186 e1 = expr_eliminate_yn(e1);
187 e2 = expr_eliminate_yn(e2);
193 int expr_eq(struct expr *e1, struct expr *e2)
197 if (e1->type != e2->type)
202 return e1->left.sym == e2->left.sym && e1->right.sym == e2->right.sym;
204 return e1->left.sym == e2->left.sym;
206 return expr_eq(e1->left.expr, e2->left.expr);
211 old_count = trans_count;
212 expr_eliminate_eq(&e1, &e2);
213 res = (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
214 e1->left.sym == e2->left.sym);
217 trans_count = old_count;
226 expr_fprint(e1, stdout);
228 expr_fprint(e2, stdout);
235 struct expr *expr_eliminate_yn(struct expr *e)
239 if (e) switch (e->type) {
241 e->left.expr = expr_eliminate_yn(e->left.expr);
242 e->right.expr = expr_eliminate_yn(e->right.expr);
243 if (e->left.expr->type == E_SYMBOL) {
244 if (e->left.expr->left.sym == &symbol_no) {
245 expr_free(e->left.expr);
246 expr_free(e->right.expr);
248 e->left.sym = &symbol_no;
249 e->right.expr = NULL;
251 } else if (e->left.expr->left.sym == &symbol_yes) {
254 *e = *(e->right.expr);
259 if (e->right.expr->type == E_SYMBOL) {
260 if (e->right.expr->left.sym == &symbol_no) {
261 expr_free(e->left.expr);
262 expr_free(e->right.expr);
264 e->left.sym = &symbol_no;
265 e->right.expr = NULL;
267 } else if (e->right.expr->left.sym == &symbol_yes) {
270 *e = *(e->left.expr);
277 e->left.expr = expr_eliminate_yn(e->left.expr);
278 e->right.expr = expr_eliminate_yn(e->right.expr);
279 if (e->left.expr->type == E_SYMBOL) {
280 if (e->left.expr->left.sym == &symbol_no) {
283 *e = *(e->right.expr);
286 } else if (e->left.expr->left.sym == &symbol_yes) {
287 expr_free(e->left.expr);
288 expr_free(e->right.expr);
290 e->left.sym = &symbol_yes;
291 e->right.expr = NULL;
295 if (e->right.expr->type == E_SYMBOL) {
296 if (e->right.expr->left.sym == &symbol_no) {
299 *e = *(e->left.expr);
302 } else if (e->right.expr->left.sym == &symbol_yes) {
303 expr_free(e->left.expr);
304 expr_free(e->right.expr);
306 e->left.sym = &symbol_yes;
307 e->right.expr = NULL;
321 struct expr *expr_trans_bool(struct expr *e)
329 e->left.expr = expr_trans_bool(e->left.expr);
330 e->right.expr = expr_trans_bool(e->right.expr);
334 if (e->left.sym->type == S_TRISTATE) {
335 if (e->right.sym == &symbol_no) {
350 struct expr *expr_join_or(struct expr *e1, struct expr *e2)
353 struct symbol *sym1, *sym2;
356 return expr_copy(e1);
357 if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT)
359 if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT)
361 if (e1->type == E_NOT) {
363 if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL)
365 sym1 = tmp->left.sym;
368 if (e2->type == E_NOT) {
369 if (e2->left.expr->type != E_SYMBOL)
371 sym2 = e2->left.expr->left.sym;
376 if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE)
378 if (sym1->type == S_TRISTATE) {
379 if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
380 ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
381 (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) {
382 // (a='y') || (a='m') -> (a!='n')
383 return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_no);
385 if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
386 ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) ||
387 (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) {
388 // (a='y') || (a='n') -> (a!='m')
389 return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_mod);
391 if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
392 ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
393 (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) {
394 // (a='m') || (a='n') -> (a!='y')
395 return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_yes);
398 if (sym1->type == S_BOOLEAN && sym1 == sym2) {
399 if ((e1->type == E_NOT && e1->left.expr->type == E_SYMBOL && e2->type == E_SYMBOL) ||
400 (e2->type == E_NOT && e2->left.expr->type == E_SYMBOL && e1->type == E_SYMBOL))
401 return expr_alloc_symbol(&symbol_yes);
405 printf("optimize (");
406 expr_fprint(e1, stdout);
408 expr_fprint(e2, stdout);
414 struct expr *expr_join_and(struct expr *e1, struct expr *e2)
417 struct symbol *sym1, *sym2;
420 return expr_copy(e1);
421 if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT)
423 if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT)
425 if (e1->type == E_NOT) {
427 if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL)
429 sym1 = tmp->left.sym;
432 if (e2->type == E_NOT) {
433 if (e2->left.expr->type != E_SYMBOL)
435 sym2 = e2->left.expr->left.sym;
440 if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE)
443 if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_yes) ||
444 (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_yes))
445 // (a) && (a='y') -> (a='y')
446 return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
448 if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_no) ||
449 (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_no))
450 // (a) && (a!='n') -> (a)
451 return expr_alloc_symbol(sym1);
453 if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_mod) ||
454 (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_mod))
455 // (a) && (a!='m') -> (a='y')
456 return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
458 if (sym1->type == S_TRISTATE) {
459 if (e1->type == E_EQUAL && e2->type == E_UNEQUAL) {
460 // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b'
461 sym2 = e1->right.sym;
462 if ((e2->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
463 return sym2 != e2->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
464 : expr_alloc_symbol(&symbol_no);
466 if (e1->type == E_UNEQUAL && e2->type == E_EQUAL) {
467 // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b'
468 sym2 = e2->right.sym;
469 if ((e1->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
470 return sym2 != e1->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
471 : expr_alloc_symbol(&symbol_no);
473 if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
474 ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) ||
475 (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes)))
476 // (a!='y') && (a!='n') -> (a='m')
477 return expr_alloc_comp(E_EQUAL, sym1, &symbol_mod);
479 if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
480 ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
481 (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes)))
482 // (a!='y') && (a!='m') -> (a='n')
483 return expr_alloc_comp(E_EQUAL, sym1, &symbol_no);
485 if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
486 ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
487 (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod)))
488 // (a!='m') && (a!='n') -> (a='m')
489 return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
491 if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_mod) ||
492 (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_mod) ||
493 (e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_yes) ||
494 (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_yes))
499 printf("optimize (");
500 expr_fprint(e1, stdout);
502 expr_fprint(e2, stdout);
508 static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2)
514 if (e1->type == type) {
515 expr_eliminate_dups1(type, &e1->left.expr, &e2);
516 expr_eliminate_dups1(type, &e1->right.expr, &e2);
519 if (e2->type == type) {
520 expr_eliminate_dups1(type, &e1, &e2->left.expr);
521 expr_eliminate_dups1(type, &e1, &e2->right.expr);
528 case E_OR: case E_AND:
529 expr_eliminate_dups1(e1->type, &e1, &e1);
536 tmp = expr_join_or(e1, e2);
538 expr_free(e1); expr_free(e2);
539 e1 = expr_alloc_symbol(&symbol_no);
545 tmp = expr_join_and(e1, e2);
547 expr_free(e1); expr_free(e2);
548 e1 = expr_alloc_symbol(&symbol_yes);
560 static void expr_eliminate_dups2(enum expr_type type, struct expr **ep1, struct expr **ep2)
564 struct expr *tmp, *tmp1, *tmp2;
566 if (e1->type == type) {
567 expr_eliminate_dups2(type, &e1->left.expr, &e2);
568 expr_eliminate_dups2(type, &e1->right.expr, &e2);
571 if (e2->type == type) {
572 expr_eliminate_dups2(type, &e1, &e2->left.expr);
573 expr_eliminate_dups2(type, &e1, &e2->right.expr);
580 expr_eliminate_dups2(e1->type, &e1, &e1);
581 // (FOO || BAR) && (!FOO && !BAR) -> n
582 tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1)));
583 tmp2 = expr_copy(e2);
584 tmp = expr_extract_eq_and(&tmp1, &tmp2);
585 if (expr_is_yes(tmp1)) {
587 e1 = expr_alloc_symbol(&symbol_no);
595 expr_eliminate_dups2(e1->type, &e1, &e1);
596 // (FOO && BAR) || (!FOO || !BAR) -> y
597 tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1)));
598 tmp2 = expr_copy(e2);
599 tmp = expr_extract_eq_or(&tmp1, &tmp2);
600 if (expr_is_no(tmp1)) {
602 e1 = expr_alloc_symbol(&symbol_yes);
616 struct expr *expr_eliminate_dups(struct expr *e)
622 oldcount = trans_count;
626 case E_OR: case E_AND:
627 expr_eliminate_dups1(e->type, &e, &e);
628 expr_eliminate_dups2(e->type, &e, &e);
634 e = expr_eliminate_yn(e);
636 trans_count = oldcount;
640 struct expr *expr_transform(struct expr *e)
653 e->left.expr = expr_transform(e->left.expr);
654 e->right.expr = expr_transform(e->right.expr);
659 if (e->left.sym->type != S_BOOLEAN)
661 if (e->right.sym == &symbol_no) {
663 e->left.expr = expr_alloc_symbol(e->left.sym);
667 if (e->right.sym == &symbol_mod) {
668 printf("boolean symbol %s tested for 'm'? test forced to 'n'\n", e->left.sym->name);
670 e->left.sym = &symbol_no;
674 if (e->right.sym == &symbol_yes) {
681 if (e->left.sym->type != S_BOOLEAN)
683 if (e->right.sym == &symbol_no) {
688 if (e->right.sym == &symbol_mod) {
689 printf("boolean symbol %s tested for 'm'? test forced to 'y'\n", e->left.sym->name);
691 e->left.sym = &symbol_yes;
695 if (e->right.sym == &symbol_yes) {
697 e->left.expr = expr_alloc_symbol(e->left.sym);
703 switch (e->left.expr->type) {
706 tmp = e->left.expr->left.expr;
710 e = expr_transform(e);
718 e->type = e->type == E_EQUAL ? E_UNEQUAL : E_EQUAL;
721 // !(a || b) -> !a && !b
724 e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
726 tmp->right.expr = NULL;
727 e = expr_transform(e);
730 // !(a && b) -> !a || !b
733 e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
735 tmp->right.expr = NULL;
736 e = expr_transform(e);
739 if (e->left.expr->left.sym == &symbol_yes) {
745 e->left.sym = &symbol_no;
748 if (e->left.expr->left.sym == &symbol_mod) {
754 e->left.sym = &symbol_mod;
757 if (e->left.expr->left.sym == &symbol_no) {
763 e->left.sym = &symbol_yes;
777 int expr_contains_symbol(struct expr *dep, struct symbol *sym)
785 return expr_contains_symbol(dep->left.expr, sym) ||
786 expr_contains_symbol(dep->right.expr, sym);
788 return dep->left.sym == sym;
791 return dep->left.sym == sym ||
792 dep->right.sym == sym;
794 return expr_contains_symbol(dep->left.expr, sym);
801 bool expr_depends_symbol(struct expr *dep, struct symbol *sym)
808 return expr_depends_symbol(dep->left.expr, sym) ||
809 expr_depends_symbol(dep->right.expr, sym);
811 return dep->left.sym == sym;
813 if (dep->left.sym == sym) {
814 if (dep->right.sym == &symbol_yes || dep->right.sym == &symbol_mod)
819 if (dep->left.sym == sym) {
820 if (dep->right.sym == &symbol_no)
830 struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2)
832 struct expr *tmp = NULL;
833 expr_extract_eq(E_AND, &tmp, ep1, ep2);
835 *ep1 = expr_eliminate_yn(*ep1);
836 *ep2 = expr_eliminate_yn(*ep2);
841 struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2)
843 struct expr *tmp = NULL;
844 expr_extract_eq(E_OR, &tmp, ep1, ep2);
846 *ep1 = expr_eliminate_yn(*ep1);
847 *ep2 = expr_eliminate_yn(*ep2);
852 void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2)
856 if (e1->type == type) {
857 expr_extract_eq(type, ep, &e1->left.expr, &e2);
858 expr_extract_eq(type, ep, &e1->right.expr, &e2);
861 if (e2->type == type) {
862 expr_extract_eq(type, ep, ep1, &e2->left.expr);
863 expr_extract_eq(type, ep, ep1, &e2->right.expr);
866 if (expr_eq(e1, e2)) {
867 *ep = *ep ? expr_alloc_two(type, *ep, e1) : e1;
870 e1 = expr_alloc_symbol(&symbol_yes);
871 e2 = expr_alloc_symbol(&symbol_yes);
872 } else if (type == E_OR) {
873 e1 = expr_alloc_symbol(&symbol_no);
874 e2 = expr_alloc_symbol(&symbol_no);
881 struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym)
883 struct expr *e1, *e2;
886 e = expr_alloc_symbol(sym);
887 if (type == E_UNEQUAL)
888 e = expr_alloc_one(E_NOT, e);
893 e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym);
894 e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym);
895 if (sym == &symbol_yes)
896 e = expr_alloc_two(E_AND, e1, e2);
897 if (sym == &symbol_no)
898 e = expr_alloc_two(E_OR, e1, e2);
899 if (type == E_UNEQUAL)
900 e = expr_alloc_one(E_NOT, e);
903 e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym);
904 e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym);
905 if (sym == &symbol_yes)
906 e = expr_alloc_two(E_OR, e1, e2);
907 if (sym == &symbol_no)
908 e = expr_alloc_two(E_AND, e1, e2);
909 if (type == E_UNEQUAL)
910 e = expr_alloc_one(E_NOT, e);
913 return expr_trans_compare(e->left.expr, type == E_EQUAL ? E_UNEQUAL : E_EQUAL, sym);
916 if (type == E_EQUAL) {
917 if (sym == &symbol_yes)
919 if (sym == &symbol_mod)
920 return expr_alloc_symbol(&symbol_no);
921 if (sym == &symbol_no)
922 return expr_alloc_one(E_NOT, expr_copy(e));
924 if (sym == &symbol_yes)
925 return expr_alloc_one(E_NOT, expr_copy(e));
926 if (sym == &symbol_mod)
927 return expr_alloc_symbol(&symbol_yes);
928 if (sym == &symbol_no)
933 return expr_alloc_comp(type, e->left.sym, sym);
942 tristate expr_calc_value(struct expr *e)
945 const char *str1, *str2;
952 sym_calc_value(e->left.sym);
953 return e->left.sym->curr.tri;
955 val1 = expr_calc_value(e->left.expr);
956 val2 = expr_calc_value(e->right.expr);
957 return E_AND(val1, val2);
959 val1 = expr_calc_value(e->left.expr);
960 val2 = expr_calc_value(e->right.expr);
961 return E_OR(val1, val2);
963 val1 = expr_calc_value(e->left.expr);
966 sym_calc_value(e->left.sym);
967 sym_calc_value(e->right.sym);
968 str1 = sym_get_string_value(e->left.sym);
969 str2 = sym_get_string_value(e->right.sym);
970 return !strcmp(str1, str2) ? yes : no;
972 sym_calc_value(e->left.sym);
973 sym_calc_value(e->right.sym);
974 str1 = sym_get_string_value(e->left.sym);
975 str2 = sym_get_string_value(e->right.sym);
976 return !strcmp(str1, str2) ? no : yes;
978 printf("expr_calc_value: %d?\n", e->type);
983 int expr_compare_type(enum expr_type t1, enum expr_type t2)
1010 printf("[%dgt%d?]", t1, t2);
1015 void expr_print(struct expr *e, void (*fn)(void *, const char *), void *data, int prevtoken)
1022 if (expr_compare_type(prevtoken, e->type) > 0)
1026 if (e->left.sym->name)
1027 fn(data, e->left.sym->name);
1029 fn(data, "<choice>");
1033 expr_print(e->left.expr, fn, data, E_NOT);
1036 fn(data, e->left.sym->name);
1038 fn(data, e->right.sym->name);
1041 fn(data, e->left.sym->name);
1043 fn(data, e->right.sym->name);
1046 expr_print(e->left.expr, fn, data, E_OR);
1048 expr_print(e->right.expr, fn, data, E_OR);
1051 expr_print(e->left.expr, fn, data, E_AND);
1053 expr_print(e->right.expr, fn, data, E_AND);
1056 fn(data, e->right.sym->name);
1059 expr_print(e->left.expr, fn, data, E_CHOICE);
1064 fn(data, e->left.sym->name);
1066 fn(data, e->right.sym->name);
1072 sprintf(buf, "<unknown type %d>", e->type);
1077 if (expr_compare_type(prevtoken, e->type) > 0)
1081 static void expr_print_file_helper(void *data, const char *str)
1083 fwrite(str, strlen(str), 1, data);
1086 void expr_fprint(struct expr *e, FILE *out)
1088 expr_print(e, expr_print_file_helper, out, E_NONE);
1091 static void expr_print_gstr_helper(void *data, const char *str)
1093 str_append((struct gstr*)data, str);
1096 void expr_gstr_print(struct expr *e, struct gstr *gs)
1098 expr_print(e, expr_print_gstr_helper, gs, E_NONE);