diff options
Diffstat (limited to 'wrapperhelper/src/parse.c')
| -rw-r--r-- | wrapperhelper/src/parse.c | 227 |
1 files changed, 182 insertions, 45 deletions
diff --git a/wrapperhelper/src/parse.c b/wrapperhelper/src/parse.c index 8b56cb15..b1f9ed90 100644 --- a/wrapperhelper/src/parse.c +++ b/wrapperhelper/src/parse.c @@ -398,6 +398,7 @@ static int is_type_spec_qual_kw(enum token_keyword_type_e kw) { (kw == KW_DOUBLE) || (kw == KW_ENUM) || (kw == KW_FLOAT) || + (kw == KW_FLOAT128) || (kw == KW_IMAGINARY) || (kw == KW_INT) || (kw == KW_INT128) || @@ -1064,7 +1065,7 @@ failed: if (e) expr_del(e); return NULL; } -static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constant_t *dest) { +static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constant_t *dest, int fatal) { // Evaluate the expression (we suppose it is constant) switch (e->typ) { case ETY_VAR: { @@ -1073,7 +1074,7 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan *dest = kh_val(const_map, it); return 1; } - printf("Error: failed to evaluate expression: expression is not constant (variable)\n"); + if (fatal) printf("Error: failed to evaluate expression: expression is not constant (variable)\n"); return 0; } case ETY_CONST: @@ -1083,18 +1084,18 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan // case ETY_GENERIC: case ETY_CALL: - printf("Error: failed to evaluate expression: expression is not constant (function call)\n"); + if (fatal) printf("Error: failed to evaluate expression: expression is not constant (function call)\n"); return 0; case ETY_ACCESS: case ETY_PTRACCESS: - printf("Error: failed to evaluate expression: expression is not constant (member access)\n"); + if (fatal) printf("Error: failed to evaluate expression: expression is not constant (member access)\n"); return 0; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wfloat-equal" case ETY_UNARY: - if (!eval_expression(e->val.unary.e, const_map, dest)) return 0; + if (!eval_expression(e->val.unary.e, const_map, dest, fatal)) return 0; switch (e->val.unary.typ) { case UOT_POSTINCR: @@ -1103,7 +1104,7 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan case UOT_PREDECR: case UOT_REF: case UOT_DEREF: - printf("Error: failed to evaluate expression: expression is not constant (assignment or memory accesses)\n"); + if (fatal) printf("Error: failed to evaluate expression: expression is not constant (assignment or memory accesses)\n"); return 0; case UOT_POS: return 1; // Nothing to do @@ -1123,7 +1124,7 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan case NCT_FLOAT: case NCT_DOUBLE: case NCT_LDOUBLE: - printf("Error: failed to evaluate expression: cannot bitwise-negate a floating point number\n"); + if (fatal) printf("Error: failed to evaluate expression: cannot bitwise-negate a floating point number\n"); return 0; case NCT_INT32: dest->val.i32 = ~dest->val.i32; return 1; case NCT_UINT32: dest->val.u32 = ~dest->val.u32; return 1; @@ -1147,8 +1148,8 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan case ETY_BINARY: { num_constant_t dest1, dest2; - if (!eval_expression(e->val.binary.e1, const_map, &dest1)) return 0; - if (!eval_expression(e->val.binary.e2, const_map, &dest2)) return 0; + if (!eval_expression(e->val.binary.e1, const_map, &dest1, fatal)) return 0; + if (!eval_expression(e->val.binary.e2, const_map, &dest2, fatal)) return 0; switch (e->val.binary.typ) { case BOT_ASSGN_EQ: @@ -1163,7 +1164,7 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan case BOT_ASSGN_AXOR: case BOT_ASSGN_AOR: case BOT_ARRAY: // Is this possible? - printf("Error: failed to evaluate expression: expression is not constant (assignments)\n"); + if (fatal) printf("Error: failed to evaluate expression: expression is not constant (assignments)\n"); return 0; #define DOIT(op) \ promote_csts(&dest1, &dest2); \ @@ -1183,7 +1184,7 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan case NCT_FLOAT: \ case NCT_DOUBLE: \ case NCT_LDOUBLE: \ - printf("Error: failed to evaluate expression: binary operation %u incompatible with floating point numbers\n", e->val.binary.typ); \ + if (fatal) printf("Error: failed to evaluate expression: binary operation %u incompatible with floating point numbers\n", e->val.binary.typ); \ return 0; \ case NCT_INT32: dest->val.i32 = dest1.val.i32 op dest2.val.i32; return 1; \ case NCT_UINT32: dest->val.u32 = dest1.val.u32 op dest2.val.u32; return 1; \ @@ -1230,9 +1231,9 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan case ETY_TERNARY: { num_constant_t dest1, dest2, dest3; - if (!eval_expression(e->val.ternary.e1, const_map, &dest1)) return 0; - if (!eval_expression(e->val.ternary.e2, const_map, &dest2)) return 0; - if (!eval_expression(e->val.ternary.e3, const_map, &dest3)) return 0; + if (!eval_expression(e->val.ternary.e1, const_map, &dest1, fatal)) return 0; + if (!eval_expression(e->val.ternary.e2, const_map, &dest2, fatal)) return 0; + if (!eval_expression(e->val.ternary.e3, const_map, &dest3, fatal)) return 0; switch (e->val.ternary.typ) { case TOT_COND: @@ -1254,7 +1255,7 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan // case ETY_INIT_LIST: case ETY_CAST: - if (!eval_expression(e->val.cast.e, const_map, dest)) return 0; + if (!eval_expression(e->val.cast.e, const_map, dest, fatal)) return 0; if (e->val.cast.typ->typ == TYPE_BUILTIN) { switch (e->val.cast.typ->val.builtin) { @@ -1340,13 +1341,16 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan case BTT_LONGDOUBLE: case BTT_CLONGDOUBLE: case BTT_ILONGDOUBLE: + case BTT_FLOAT128: + case BTT_CFLOAT128: + case BTT_IFLOAT128: case BTT_VA_LIST: default: - printf("Error: TODO: cast to builtin %s in constant expression\n", builtin2str[e->val.cast.typ->val.builtin]); + if (fatal) printf("Error: TODO: cast to builtin %s in constant expression\n", builtin2str[e->val.cast.typ->val.builtin]); return 0; } } else { - printf("Error: cast in constant expression\n"); + if (fatal) printf("Error: cast in constant expression\n"); return 0; } @@ -1382,7 +1386,7 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s goto failed; } num_constant_t eval; - if (!eval_expression(e, const_map, &eval)) { + if (!eval_expression(e, const_map, &eval, 1)) { expr_del(e); // Empty destructor goto failed; @@ -1567,6 +1571,8 @@ parse_cur_token_decl: *spec = SPEC_LONGCOMPLEX; } else if ((*spec == SPEC_BUILTIN) && (typ->val.builtin == BTT_FLOAT)) { typ->val.builtin = BTT_CFLOAT; + } else if ((*spec == SPEC_BUILTIN) && (typ->val.builtin == BTT_FLOAT128)) { + typ->val.builtin = BTT_CFLOAT128; } else if ((*spec == SPEC_BUILTIN) && (typ->val.builtin == BTT_DOUBLE)) { typ->val.builtin = BTT_CDOUBLE; } else if ((*spec == SPEC_BUILTIN) && (typ->val.builtin == BTT_LONGDOUBLE)) { @@ -1584,6 +1590,8 @@ parse_cur_token_decl: *spec = SPEC_LONGIMAGINARY; } else if ((*spec == SPEC_BUILTIN) && (typ->val.builtin == BTT_FLOAT)) { typ->val.builtin = BTT_IFLOAT; + } else if ((*spec == SPEC_BUILTIN) && (typ->val.builtin == BTT_FLOAT128)) { + typ->val.builtin = BTT_IFLOAT128; } else if ((*spec == SPEC_BUILTIN) && (typ->val.builtin == BTT_DOUBLE)) { typ->val.builtin = BTT_IDOUBLE; } else if ((*spec == SPEC_BUILTIN) && (typ->val.builtin == BTT_LONGDOUBLE)) { @@ -1643,6 +1651,25 @@ parse_cur_token_decl: } *tok = proc_next_token(prep); goto parse_cur_token_decl; + } else if ((tok->tokt == PTOK_KEYWORD) && (tok->tokv.kw == KW_FLOAT128)) { + if (*spec == SPEC_NONE) { + *spec = SPEC_BUILTIN; + typ->typ = TYPE_BUILTIN; + typ->val.builtin = BTT_FLOAT128; + } else if (*spec == SPEC_COMPLEX) { + *spec = SPEC_BUILTIN; + typ->typ = TYPE_BUILTIN; + typ->val.builtin = BTT_CFLOAT128; + } else if (*spec == SPEC_IMAGINARY) { + *spec = SPEC_BUILTIN; + typ->typ = TYPE_BUILTIN; + typ->val.builtin = BTT_IFLOAT128; + } else { + printf("Error: unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); + goto failed; + } + *tok = proc_next_token(prep); + goto parse_cur_token_decl; } else if ((tok->tokt == PTOK_KEYWORD) && (tok->tokv.kw == KW_CHAR)) { SPEC_SIGNED(CHAR, 0) } else if ((tok->tokt == PTOK_KEYWORD) && (tok->tokv.kw == KW_INT)) { @@ -2058,7 +2085,7 @@ parse_cur_token_decl: proc_token_del(tok); goto failed; } - if (!eval_expression(e, const_map, &cst)) { + if (!eval_expression(e, const_map, &cst, 1)) { expr_del(e); if (tag) string_del(tag); // Empty destructor @@ -2203,6 +2230,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d int has_list = 0, has_ident = 0; // TODO: allow_abstract and 'direct-abstract-declarator(opt) ( parameter-type-list(opt) )' + _Bool array_atomic = 0, array_const = 0, array_restrict = 0, array_static = 0, array_volatile = 0; string_t *cur_ident = NULL; type_t *typ = base_type; ++typ->nrefs; type_t *cur_bottom = NULL; @@ -2324,6 +2352,27 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d } if ((tok->tokt == PTOK_SYM) && (tok->tokv.sym == SYM_RPAREN)) { // Unnamed argument + if (typ2->typ == TYPE_ARRAY) { + // Need to convert type to a pointer + type_t *typ3 = type_new(); + if (!typ3) { + printf("Error: failed to allocate new type\n"); + type_del(typ2); + // Empty destructor + goto failed; + } + if (!type_copy_into(typ3, typ2)) { + printf("Error: failed to duplicate array type to temporary type\n"); + type_del(typ3); + type_del(typ2); + // Empty destructor + goto failed; + } + type_del(typ2); + typ3->typ = TYPE_PTR; + typ3->val.typ = typ3->val.array.typ; + typ2 = type_try_merge(typ3, PDECL_TYPE_SET); + } if (!vector_push(types, args, typ2)) { printf("Error: failed to add argument to argument vector\n"); vector_del(types, args); @@ -2452,23 +2501,76 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d } has_ident = 1; } + if (array_atomic || array_const || array_restrict || array_static || array_volatile) { + printf("Error: invalid array after array with type qualifier(s) and/or 'static'\n"); + // Empty destructor + goto failed; + } // Empty destructor *tok = proc_next_token(prep); - // Here we have only two array constructors: - // direct-declaration [ assignment-expression(opt) ] - // direct-declaration [ * ] (complete VLA) + // From the standard: + // direct-declarator [ type-qualifier-list(opt) assignment-expression(opt) ] + // direct-declarator [ static type-qualifier-list(opt) assignment-expression ] + // direct-declarator [ type-qualifier-list static assignment-expression ] + // direct-declarator [ type-qualifier-list(opt) * ] + // The optional type qualifiers and the keyword static shall appear only in a + // declaration of a function parameter with an array type, and then only in the outermost + // array type derivation. size_t nelems; _Bool is_incomplete; + while (1) { +#define DO_CHECKS \ + if (is_init || is_list || !allow_decl || (cur_bottom && (typ->typ != TYPE_ARRAY))) { \ + printf("Error: type qualifiers and 'static' may only appear in function argument array declarations\n"); \ + /* Empty destructor */ \ + goto failed; \ + } + if ((tok->tokt == PTOK_KEYWORD) && (tok->tokv.kw == KW_ATOMIC)) { + DO_CHECKS + array_atomic = 1; + *tok = proc_next_token(prep); + } else if ((tok->tokt == PTOK_KEYWORD) && (tok->tokv.kw == KW_CONST)) { + DO_CHECKS + array_const = 1; + *tok = proc_next_token(prep); + } else if ((tok->tokt == PTOK_KEYWORD) && (tok->tokv.kw == KW_RESTRICT)) { + DO_CHECKS + array_restrict = 1; + *tok = proc_next_token(prep); + } else if ((tok->tokt == PTOK_KEYWORD) && (tok->tokv.kw == KW_STATIC)) { + DO_CHECKS + array_static = 1; + *tok = proc_next_token(prep); + } else if ((tok->tokt == PTOK_KEYWORD) && (tok->tokv.kw == KW_VOLATILE)) { + DO_CHECKS + array_volatile = 1; + *tok = proc_next_token(prep); + } else break; +#undef DO_CHECKS + } if ((tok->tokt == PTOK_SYM) && (tok->tokv.sym == SYM_RSQBRACKET)) { + if (array_static) { + // Missing expression + printf("Error: unexpected token ']' in static length array declaration\n"); + // Empty destructor + goto failed; + } // Incomplete VLA nelems = (size_t)-1; is_incomplete = 1; } else if ((tok->tokt == PTOK_SYM) && (tok->tokv.sym == SYM_STAR)) { + if (array_static) { + // Missing expression + printf("Error: unexpected token '*' in static length array declaration\n"); + // Empty destructor + goto failed; + } // Complete VLA, expecting a ']' nelems = (size_t)-1; is_incomplete = 0; // Empty destructor *tok = proc_next_token(prep); if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_RSQBRACKET)) { + // TODO: ...[*expr] printf("Error: unexpected token during variable length array declaration\n"); proc_token_del(tok); goto failed; @@ -2488,27 +2590,32 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d goto failed; } num_constant_t cst; - if (!eval_expression(e, PDECL_CONST_MAP, &cst)) { + if (eval_expression(e, PDECL_CONST_MAP, &cst, is_init || is_list || !allow_decl)) { expr_del(e); - // Empty destructor - goto failed; - } - expr_del(e); - int is_neg; - switch (cst.typ) { - case NCT_FLOAT: is_neg = cst.val.f < 0; nelems = (size_t)cst.val.f; break; - case NCT_DOUBLE: is_neg = cst.val.d < 0; nelems = (size_t)cst.val.d; break; - case NCT_LDOUBLE: is_neg = cst.val.l < 0; nelems = (size_t)cst.val.l; break; - case NCT_INT32: is_neg = cst.val.i32 < 0; nelems = (size_t)cst.val.i32; break; - case NCT_UINT32: is_neg = 0; nelems = (size_t)cst.val.u32; break; - case NCT_INT64: is_neg = cst.val.i64 < 0; nelems = (size_t)cst.val.i64; break; - case NCT_UINT64: is_neg = 0; nelems = (size_t)cst.val.u64; break; - default: is_neg = 1; - } - if (is_neg) { - printf("Error: the size of an array must be nonnegative"); - // Empty destructor - goto failed; + int is_neg; + switch (cst.typ) { + case NCT_FLOAT: is_neg = cst.val.f < 0; nelems = (size_t)cst.val.f; break; + case NCT_DOUBLE: is_neg = cst.val.d < 0; nelems = (size_t)cst.val.d; break; + case NCT_LDOUBLE: is_neg = cst.val.l < 0; nelems = (size_t)cst.val.l; break; + case NCT_INT32: is_neg = cst.val.i32 < 0; nelems = (size_t)cst.val.i32; break; + case NCT_UINT32: is_neg = 0; nelems = (size_t)cst.val.u32; break; + case NCT_INT64: is_neg = cst.val.i64 < 0; nelems = (size_t)cst.val.i64; break; + case NCT_UINT64: is_neg = 0; nelems = (size_t)cst.val.u64; break; + default: is_neg = 1; + } + if (is_neg) { + printf("Error: the size of an array must be nonnegative"); + // Empty destructor + goto failed; + } + } else { + expr_del(e); + // Treated as '*' as function argument (TODO: as anything else) + if (is_init || is_list || !allow_decl) { + // Empty destructor + goto failed; + } + nelems = (size_t)-1; } } // Token is ']' @@ -2713,6 +2820,32 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d kh_val(dest->f->decl_map, it) = typ; } } else if (!is_init && !is_list) { + if (allow_decl) { + // Function argument + if (typ->typ == TYPE_ARRAY) { + // Convert to pointer + if (typ == base_type) { + typ = type_new(); + if (!typ) { + printf("Error: failed to allocate new type\n"); + // Empty destructor + goto failed; + } + if (!type_copy_into(typ, base_type)) { + printf("Error: failed to allocate new type\n"); + // Empty destructor + goto failed; + } + } + typ->typ = TYPE_PTR; + typ->val.typ = typ->val.array.typ; + if (array_atomic) typ->is_atomic = 1; + if (array_const) typ->is_const = 1; + if (array_restrict) typ->is_restrict = 1; + if (array_volatile) typ->is_volatile = 1; + typ = type_try_merge(typ, PDECL_TYPE_SET); + } + } dest->argt.dest = typ; if (cur_ident) string_del(cur_ident); goto success; @@ -2802,7 +2935,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d goto failed; } num_constant_t eval; - if (!eval_expression(e, dest->structms.const_map, &eval)) { + if (!eval_expression(e, dest->structms.const_map, &eval, 1)) { expr_del(e); // Empty destructor goto failed; @@ -3067,9 +3200,13 @@ file_t *parse_file(machine_t *target, const char *filename, FILE *file) { if (spec == SPEC_NONE) continue; // Declaration was an assert, typ is unchanged typ = type_try_merge(typ, ret->type_set); if ((tok.tokt != PTOK_SYM) || (tok.tokv.sym != SYM_SEMICOLON)) { - if (!parse_declarator(target, &(struct parse_declarator_dest_s){.f = ret}, prep, &tok, storage, fspec, typ, 1, 1, 1, 0)) goto failed; + if (!parse_declarator(target, &(struct parse_declarator_dest_s){.f = ret}, prep, &tok, storage, fspec, typ, 1, 1, 1, 0)) { + goto failed; + } } else { - if (validate_storage_type(target, storage, typ, tok.tokv.sym) != VALIDATION_LAST_DECL) goto failed; + if (validate_storage_type(target, storage, typ, tok.tokv.sym) != VALIDATION_LAST_DECL) { + goto failed; + } if (fspec != FSPEC_NONE) { printf("Error: unexpected function specifier\n"); // Empty destructor |