Simple implementation, I'm not even sure to respect C standart here, but it should work with most use case. This add an case in unary(), and generate TokString depending of _Generic controlling exression, use begin_macro to "push" the generated TokString, then call unary() again before exiting the switch so the just add token are reevaluate again.
Unified · Split
| @@ -92,6 +92,7 @@ ST_FUNC void vpush(CType *type); · 91 unmodified lines | ||
| 92 | 92 | ST_FUNC int gvtst(int inv, int t); |
| 93 | 93 | ST_FUNC int is_btype_size(int bt); |
| 94 | 94 | static void gen_inline_functions(TCCState *s); |
| 95 | +static void skip_or_save_block(TokenString **str); | |
| 95 | 96 | |
| 96 | 97 | ST_INLN int is_float(int t) |
| 97 | 98 | { |
| @@ -4689,6 +4690,76 @@ ST_FUNC void unary(void) · 4591 unmodified lines | ||
| 4689 | 4690 | next(); |
| 4690 | 4691 | break; |
| 4691 | 4692 | |
| 4693 | + case TOK_GENERIC: | |
| 4694 | + { | |
| 4695 | + CType controlling_type; | |
| 4696 | + int has_default = 0; | |
| 4697 | + int has_match = 0; | |
| 4698 | + CType cur_type; | |
| 4699 | + AttributeDef ad_tmp; | |
| 4700 | + int learn = 0; | |
| 4701 | + TokenString *str = NULL; | |
| 4702 | + ParseState saved_parse_state; | |
| 4703 | + | |
| 4704 | + next(); | |
| 4705 | + skip('('); | |
| 4706 | + expr_type(&controlling_type, 1); | |
| 4707 | + if (controlling_type.t & VT_ARRAY) | |
| 4708 | + controlling_type.t = VT_PTR; | |
| 4709 | + controlling_type.t &= ~VT_CONSTANT; | |
| 4710 | + for (;;) { | |
| 4711 | + learn = 0; | |
| 4712 | + skip(','); | |
| 4713 | + if (tok == TOK_DEFAULT) { | |
| 4714 | + if (has_default) | |
| 4715 | + tcc_error("too many 'default'"); | |
| 4716 | + if (!has_match) { | |
| 4717 | + has_default = 1; | |
| 4718 | + learn = 1; | |
| 4719 | + } | |
| 4720 | + next(); | |
| 4721 | + } else { | |
| 4722 | + int itmp; | |
| 4723 | + | |
| 4724 | + parse_btype(&cur_type, &ad_tmp); | |
| 4725 | + type_decl(&cur_type, &ad_tmp, &itmp, TYPE_ABSTRACT); | |
| 4726 | + if (compare_types(&controlling_type, &cur_type, 0)) { | |
| 4727 | + if (has_match) { | |
| 4728 | + tcc_error("type march twice"); | |
| 4729 | + } | |
| 4730 | + if (has_default) | |
| 4731 | + tok_str_free(str); | |
| 4732 | + has_match = 1; | |
| 4733 | + learn = 1; | |
| 4734 | + } | |
| 4735 | + } | |
| 4736 | + skip(':'); | |
| 4737 | + if (learn) { | |
| 4738 | + skip_or_save_block(&str); | |
| 4739 | + } else { | |
| 4740 | + skip_or_save_block(NULL); | |
| 4741 | + } | |
| 4742 | + if (tok == ',') | |
| 4743 | + continue; | |
| 4744 | + else if (tok == ')') | |
| 4745 | + break; | |
| 4746 | + } | |
| 4747 | + if (!has_match && !has_default) { | |
| 4748 | + char buf[256]; | |
| 4749 | + | |
| 4750 | + type_to_str(buf, 256, &controlling_type, NULL); | |
| 4751 | + tcc_error("_Generic sellector of type '%s' is not compatible with any assosiation", | |
| 4752 | + buf); | |
| 4753 | + } | |
| 4754 | + skip(')'); | |
| 4755 | + save_parse_state(&saved_parse_state); | |
| 4756 | + begin_macro(str, 1); | |
| 4757 | + next(); | |
| 4758 | + expr_eq(); | |
| 4759 | + end_macro(); | |
| 4760 | + restore_parse_state(&saved_parse_state); | |
| 4761 | + break; | |
| 4762 | + } | |
| 4692 | 4763 | // special qnan , snan and infinity values |
| 4693 | 4764 | case TOK___NAN__: |
| 4694 | 4765 | vpush64(VT_DOUBLE, 0x7ff8000000000000ULL); |
| @@ -36,7 +36,9 @@ · 35 unmodified lines | ||
| 36 | 36 | DEF(TOK_RESTRICT2, "__restrict") |
| 37 | 37 | DEF(TOK_RESTRICT3, "__restrict__") |
| 38 | 38 | DEF(TOK_EXTENSION, "__extension__") /* gcc keyword */ |
| 39 | − | |
| 39 | + | |
| 40 | + DEF(TOK_GENERIC, "_Generic") | |
| 41 | + | |
| 40 | 42 | DEF(TOK_FLOAT, "float") |
| 41 | 43 | DEF(TOK_DOUBLE, "double") |
| 42 | 44 | DEF(TOK_BOOL, "_Bool") |