aboutsummaryrefslogtreecommitdiff
path: root/tccgen.c
diff options
context:
space:
mode:
authorMatthias Gatto <uso.cosmo.ray@gmail.com>2016-12-09 11:42:41 +0100
committerMatthias Gatto <uso.cosmo.ray@gmail.com>2017-07-05 10:57:50 +0200
commit157bad52cdb052015f64a29e47099b2470f67c3e (patch)
tree0f63feb00ba8a13813180cbef159edf3b026cef4 /tccgen.c
parent9ed8b54f6cd2ebf1d5dc678ab2296e92ad85cd3e (diff)
downloadtinycc-157bad52cdb052015f64a29e47099b2470f67c3e.tar.gz
tinycc-157bad52cdb052015f64a29e47099b2470f67c3e.tar.bz2
add C11's _Generic
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.
Diffstat (limited to 'tccgen.c')
-rw-r--r--tccgen.c71
1 files changed, 71 insertions, 0 deletions
diff --git a/tccgen.c b/tccgen.c
index 304225e..af8d2a7 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -92,6 +92,7 @@ ST_FUNC void vpush(CType *type);
ST_FUNC int gvtst(int inv, int t);
ST_FUNC int is_btype_size(int bt);
static void gen_inline_functions(TCCState *s);
+static void skip_or_save_block(TokenString **str);
ST_INLN int is_float(int t)
{
@@ -4689,6 +4690,76 @@ ST_FUNC void unary(void)
next();
break;
+ case TOK_GENERIC:
+ {
+ CType controlling_type;
+ int has_default = 0;
+ int has_match = 0;
+ CType cur_type;
+ AttributeDef ad_tmp;
+ int learn = 0;
+ TokenString *str = NULL;
+ ParseState saved_parse_state;
+
+ next();
+ skip('(');
+ expr_type(&controlling_type, 1);
+ if (controlling_type.t & VT_ARRAY)
+ controlling_type.t = VT_PTR;
+ controlling_type.t &= ~VT_CONSTANT;
+ for (;;) {
+ learn = 0;
+ skip(',');
+ if (tok == TOK_DEFAULT) {
+ if (has_default)
+ tcc_error("too many 'default'");
+ if (!has_match) {
+ has_default = 1;
+ learn = 1;
+ }
+ next();
+ } else {
+ int itmp;
+
+ parse_btype(&cur_type, &ad_tmp);
+ type_decl(&cur_type, &ad_tmp, &itmp, TYPE_ABSTRACT);
+ if (compare_types(&controlling_type, &cur_type, 0)) {
+ if (has_match) {
+ tcc_error("type march twice");
+ }
+ if (has_default)
+ tok_str_free(str);
+ has_match = 1;
+ learn = 1;
+ }
+ }
+ skip(':');
+ if (learn) {
+ skip_or_save_block(&str);
+ } else {
+ skip_or_save_block(NULL);
+ }
+ if (tok == ',')
+ continue;
+ else if (tok == ')')
+ break;
+ }
+ if (!has_match && !has_default) {
+ char buf[256];
+
+ type_to_str(buf, 256, &controlling_type, NULL);
+ tcc_error("_Generic sellector of type '%s' is not compatible with any assosiation",
+ buf);
+ }
+ skip(')');
+ save_parse_state(&saved_parse_state);
+ begin_macro(str, 1);
+ next();
+ expr_eq();
+ end_macro();
+ restore_parse_state(&saved_parse_state);
+ break;
+ }
// special qnan , snan and infinity values
case TOK___NAN__:
vpush64(VT_DOUBLE, 0x7ff8000000000000ULL);