X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=parser.c;h=a9a40414fc9fd77799b8e7f932942bf21dcd81ed;hb=d7384b0b065dd6195ac6649c4d48a06905bc8fe7;hp=be864180eb0908506f563416d84034537a56284c;hpb=ae36169d2f7fe745297ff976c0765d7a4882995e;p=cparser diff --git a/parser.c b/parser.c index be86418..a9a4041 100644 --- a/parser.c +++ b/parser.c @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -27,7 +28,7 @@ #include "parser.h" #include "diagnostic.h" #include "format_check.h" -#include "lexer.h" +#include "preprocessor.h" #include "symbol_t.h" #include "token_t.h" #include "types.h" @@ -40,6 +41,7 @@ #include "walk.h" #include "warning.h" #include "printer.h" +#include "ast2firm.h" #include "adt/bitfiddle.h" #include "adt/error.h" #include "adt/array.h" @@ -59,7 +61,7 @@ struct declaration_specifiers_t { storage_class_t storage_class; unsigned char alignment; /**< Alignment, 0 if not set. */ bool is_inline : 1; - bool thread_local : 1; /**< GCC __thread */ + bool thread_local : 1; attribute_t *attributes; /**< list of attributes */ type_t *type; }; @@ -131,16 +133,13 @@ static elf_visibility_tag_t default_visibility = ELF_VISIBILITY_DEFAULT; #define PUSH_EXTENSION() \ (void)0; \ bool const old_gcc_extension = in_gcc_extension; \ - while (next_if(T___extension__)) { \ + while (accept(T___extension__)) { \ in_gcc_extension = true; \ } \ do {} while (0) #define POP_EXTENSION() \ ((void)(in_gcc_extension = old_gcc_extension)) -/** special symbol used for anonymous entities. */ -static symbol_t *sym_anonymous = NULL; - /** The token anchor set */ static unsigned short token_anchor_set[T_LAST_TOKEN]; @@ -185,7 +184,7 @@ static void semantic_comparison(binary_expression_t *expression); case T_static: \ case T_auto: \ case T_register: \ - case T___thread: + case T__Thread_local: #define TYPE_QUALIFIERS \ case T_const: \ @@ -247,19 +246,14 @@ static void semantic_comparison(binary_expression_t *expression); case '~': \ case T_ANDAND: \ case T_CHARACTER_CONSTANT: \ - case T_FLOATINGPOINT: \ - case T_FLOATINGPOINT_HEXADECIMAL: \ - case T_INTEGER: \ + case T_NUMBER: \ case T_MINUSMINUS: \ case T_PLUSPLUS: \ case T_STRING_LITERAL: \ - case T_WIDE_CHARACTER_CONSTANT: \ - case T_WIDE_STRING_LITERAL: \ + case T__Alignof: \ case T___FUNCDNAME__: \ case T___FUNCSIG__: \ - case T___FUNCTION__: \ case T___PRETTY_FUNCTION__: \ - case T___alignof__: \ case T___builtin_classify_type: \ case T___builtin_constant_p: \ case T___builtin_isgreater: \ @@ -303,7 +297,6 @@ static size_t get_statement_struct_size(statement_kind_t kind) [STATEMENT_GOTO] = sizeof(goto_statement_t), [STATEMENT_LABEL] = sizeof(label_statement_t), [STATEMENT_CASE_LABEL] = sizeof(case_label_statement_t), - [STATEMENT_WHILE] = sizeof(while_statement_t), [STATEMENT_DO_WHILE] = sizeof(do_while_statement_t), [STATEMENT_FOR] = sizeof(for_statement_t), [STATEMENT_ASM] = sizeof(asm_statement_t), @@ -329,10 +322,9 @@ static size_t get_expression_struct_size(expression_kind_t kind) [EXPR_LITERAL_BOOLEAN] = sizeof(literal_expression_t), [EXPR_LITERAL_INTEGER] = sizeof(literal_expression_t), [EXPR_LITERAL_FLOATINGPOINT] = sizeof(literal_expression_t), - [EXPR_LITERAL_CHARACTER] = sizeof(literal_expression_t), - [EXPR_LITERAL_WIDE_CHARACTER] = sizeof(literal_expression_t), + [EXPR_LITERAL_CHARACTER] = sizeof(string_literal_expression_t), + [EXPR_LITERAL_MS_NOOP] = sizeof(literal_expression_t), [EXPR_STRING_LITERAL] = sizeof(string_literal_expression_t), - [EXPR_WIDE_STRING_LITERAL] = sizeof(string_literal_expression_t), [EXPR_COMPOUND_LITERAL] = sizeof(compound_literal_expression_t), [EXPR_CALL] = sizeof(call_expression_t), [EXPR_UNARY_FIRST] = sizeof(unary_expression_t), @@ -376,7 +368,7 @@ static statement_t *allocate_statement_zero(statement_kind_t kind) res->base.kind = kind; res->base.parent = current_parent; - res->base.source_position = token.base.source_position; + res->base.source_position = *HERE; return res; } @@ -393,7 +385,7 @@ static expression_t *allocate_expression_zero(expression_kind_t kind) res->base.kind = kind; res->base.type = type_error_type; - res->base.source_position = token.base.source_position; + res->base.source_position = *HERE; return res; } @@ -433,8 +425,7 @@ static size_t get_initializer_size(initializer_kind_t kind) { static const size_t sizes[] = { [INITIALIZER_VALUE] = sizeof(initializer_value_t), - [INITIALIZER_STRING] = sizeof(initializer_string_t), - [INITIALIZER_WIDE_STRING] = sizeof(initializer_wide_string_t), + [INITIALIZER_STRING] = sizeof(initializer_value_t), [INITIALIZER_LIST] = sizeof(initializer_list_t), [INITIALIZER_DESIGNATOR] = sizeof(initializer_designator_t) }; @@ -477,8 +468,8 @@ static size_t label_top(void) static inline void next_token(void) { token = lookahead_buffer[lookahead_bufpos]; - lookahead_buffer[lookahead_bufpos] = lexer_token; - lexer_next_token(); + lookahead_buffer[lookahead_bufpos] = pp_token; + next_preprocessing_token(); lookahead_bufpos = (lookahead_bufpos + 1) % MAX_LOOKAHEAD; @@ -488,10 +479,23 @@ static inline void next_token(void) #endif } -static inline bool next_if(token_kind_t const type) +static inline void eat(token_kind_t const kind) { - if (token.kind == type) { - next_token(); + assert(token.kind == kind); + (void)kind; + next_token(); +} + +/** + * Consume the current token, if it is of the expected kind. + * + * @param kind The kind of token to consume. + * @return Whether the token was consumed. + */ +static inline bool accept(token_kind_t const kind) +{ + if (token.kind == kind) { + eat(kind); return true; } else { return false; @@ -599,11 +603,9 @@ static void eat_until_anchor(void) static void eat_block(void) { eat_until_matching_token('{'); - next_if('}'); + accept('}'); } -#define eat(token_kind) (assert(token.kind == (token_kind)), next_token()) - /** * Report a parse error because an expected token was not found. */ @@ -632,34 +634,34 @@ static void type_error_incompatible(const char *msg, msg, type1, type2); } -/** - * Expect the current token is the expected token. - * If not, generate an error and skip until the next anchor. - */ -static void expect(token_kind_t const expected) +static bool skip_till(token_kind_t const expected, char const *const context) { if (UNLIKELY(token.kind != expected)) { - parse_error_expected(NULL, expected, NULL); + parse_error_expected(context, expected, NULL); add_anchor_token(expected); eat_until_anchor(); rem_anchor_token(expected); if (token.kind != expected) - return; + return false; } - eat(expected); + return true; +} + +/** + * Expect the current token is the expected token. + * If not, generate an error and skip until the next anchor. + */ +static void expect(token_kind_t const expected) +{ + if (skip_till(expected, NULL)) + eat(expected); } static symbol_t *expect_identifier(char const *const context, source_position_t *const pos) { - if (token.kind != T_IDENTIFIER) { - parse_error_expected(context, T_IDENTIFIER, NULL); - add_anchor_token(T_IDENTIFIER); - eat_until_anchor(); - rem_anchor_token(T_IDENTIFIER); - if (token.kind != T_IDENTIFIER) - return NULL; - } - symbol_t *const sym = token.identifier.symbol; + if (!skip_till(T_IDENTIFIER, context)) + return NULL; + symbol_t *const sym = token.base.symbol; if (pos) *pos = *HERE; eat(T_IDENTIFIER); @@ -1038,27 +1040,67 @@ static expression_t *parse_assignment_expression(void) return parse_subexpression(PREC_ASSIGNMENT); } -static void warn_string_concat(const source_position_t *pos) +static void append_string(string_t const *const s) { - warningf(WARN_TRADITIONAL, pos, "traditional C rejects string constant concatenation"); + /* FIXME Using the ast_obstack is a hack. Using the symbol_obstack is not + * possible, because other tokens are grown there alongside. */ + obstack_grow(&ast_obstack, s->begin, s->size); } -static string_t parse_string_literals(void) +static string_t finish_string(string_encoding_t const enc) { - assert(token.kind == T_STRING_LITERAL); - string_t result = token.string.string; + obstack_1grow(&ast_obstack, '\0'); + size_t const size = obstack_object_size(&ast_obstack) - 1; + char const *const string = obstack_finish(&ast_obstack); + return (string_t){ string, size, enc }; +} - next_token(); +static string_t concat_string_literals(void) +{ + assert(token.kind == T_STRING_LITERAL); - while (token.kind == T_STRING_LITERAL) { - warn_string_concat(&token.base.source_position); - result = concat_strings(&result, &token.string.string); - next_token(); + string_t result; + if (look_ahead(1)->kind == T_STRING_LITERAL) { + append_string(&token.literal.string); + eat(T_STRING_LITERAL); + warningf(WARN_TRADITIONAL, HERE, "traditional C rejects string constant concatenation"); + string_encoding_t enc = token.literal.string.encoding; + do { + string_encoding_t const new_enc = token.literal.string.encoding; + if (new_enc != enc && new_enc != STRING_ENCODING_CHAR) { + if (enc == STRING_ENCODING_CHAR) { + enc = new_enc; + } else { + errorf(HERE, "concatenating string literals with encodings %s and %s", get_string_encoding_prefix(enc), get_string_encoding_prefix(new_enc)); + } + } + append_string(&token.literal.string); + eat(T_STRING_LITERAL); + } while (token.kind == T_STRING_LITERAL); + result = finish_string(enc); + } else { + result = token.literal.string; + eat(T_STRING_LITERAL); } return result; } +static string_t parse_string_literals(char const *const context) +{ + if (!skip_till(T_STRING_LITERAL, context)) + return (string_t){ "", 0, STRING_ENCODING_CHAR }; + + source_position_t const pos = *HERE; + string_t const res = concat_string_literals(); + + if (res.encoding != STRING_ENCODING_CHAR) { + errorf(&pos, "expected plain string literal, got %s string literal", get_string_encoding_prefix(res.encoding)); + } + + return res; +} + static attribute_t *allocate_attribute_zero(attribute_kind_t kind) { attribute_t *attribute = allocate_ast_zero(sizeof(*attribute)); @@ -1105,10 +1147,9 @@ static attribute_argument_t *parse_attribute_arguments(void) /* is it an identifier */ if (token.kind == T_IDENTIFIER && (look_ahead(1)->kind == ',' || look_ahead(1)->kind == ')')) { - symbol_t *symbol = token.identifier.symbol; argument->kind = ATTRIBUTE_ARGUMENT_SYMBOL; - argument->v.symbol = symbol; - next_token(); + argument->v.symbol = token.base.symbol; + eat(T_IDENTIFIER); } else { /* must be an expression */ expression_t *expression = parse_assignment_expression(); @@ -1120,7 +1161,7 @@ static attribute_argument_t *parse_attribute_arguments(void) /* append argument */ *anchor = argument; anchor = &argument->next; - } while (next_if(',')); + } while (accept(',')); expect(')'); return first; } @@ -1134,28 +1175,10 @@ static attribute_t *parse_attribute_asm(void) return attribute; } -static symbol_t *get_symbol_from_token(void) -{ - switch(token.kind) { - case T_CHARACTER_CONSTANT: - case T_EOF: - case T_FLOATINGPOINT: - case T_FLOATINGPOINT_HEXADECIMAL: - case T_INTEGER: - case T_STRING_LITERAL: - case T_WIDE_CHARACTER_CONSTANT: - case T_WIDE_STRING_LITERAL: - return NULL; - - default: - return token.identifier.symbol; - } -} - static attribute_t *parse_attribute_gnu_single(void) { /* parse "any-word" */ - symbol_t *symbol = get_symbol_from_token(); + symbol_t *const symbol = token.base.symbol; if (symbol == NULL) { parse_error_expected("while parsing attribute((", T_IDENTIFIER, NULL); return NULL; @@ -1165,6 +1188,12 @@ static attribute_t *parse_attribute_gnu_single(void) char const *const name = symbol->string; for (kind = ATTRIBUTE_GNU_FIRST;; ++kind) { if (kind > ATTRIBUTE_GNU_LAST) { + /* special case for "__const" */ + if (token.kind == T_const) { + kind = ATTRIBUTE_GNU_CONST; + break; + } + warningf(WARN_ATTRIBUTE, HERE, "unknown attribute '%s' ignored", name); /* TODO: we should still save the attribute in the list... */ kind = ATTRIBUTE_UNKNOWN; @@ -1180,7 +1209,7 @@ static attribute_t *parse_attribute_gnu_single(void) next_token(); /* parse arguments */ - if (next_if('(')) + if (accept('(')) attribute->a.arguments = parse_attribute_arguments(); return attribute; @@ -1192,18 +1221,18 @@ static attribute_t *parse_attribute_gnu(void) attribute_t **anchor = &first; eat(T___attribute__); + add_anchor_token(')'); + add_anchor_token(','); expect('('); expect('('); - add_anchor_token(')'); - add_anchor_token(','); if (token.kind != ')') do { attribute_t *attribute = parse_attribute_gnu_single(); if (attribute) { *anchor = attribute; anchor = &attribute->next; } - } while (next_if(',')); + } while (accept(',')); rem_anchor_token(','); rem_anchor_token(')'); @@ -1345,11 +1374,7 @@ static void mark_vars_read(expression_t *const expr, entity_t *lhs_ent) return; if (lhs_ent != entity && lhs_ent != ENT_ANY) { - if (entity->kind == ENTITY_VARIABLE) { - entity->variable.read = true; - } else { - entity->parameter.read = true; - } + entity->variable.read = true; } return; } @@ -1480,9 +1505,9 @@ unary: return; case EXPR_LITERAL_CASES: + case EXPR_LITERAL_CHARACTER: case EXPR_ERROR: case EXPR_STRING_LITERAL: - case EXPR_WIDE_STRING_LITERAL: case EXPR_COMPOUND_LITERAL: // TODO init? case EXPR_SIZEOF: case EXPR_CLASSIFY_TYPE: @@ -1510,8 +1535,8 @@ static designator_t *parse_designation(void) switch (token.kind) { case '[': designator = allocate_ast_zero(sizeof(designator[0])); - designator->source_position = token.base.source_position; - next_token(); + designator->source_position = *HERE; + eat('['); add_anchor_token(']'); designator->array_index = parse_constant_expression(); rem_anchor_token(']'); @@ -1519,8 +1544,8 @@ static designator_t *parse_designation(void) break; case '.': designator = allocate_ast_zero(sizeof(designator[0])); - designator->source_position = token.base.source_position; - next_token(); + designator->source_position = *HERE; + eat('.'); designator->symbol = expect_identifier("while parsing designator", NULL); if (!designator->symbol) return NULL; @@ -1536,31 +1561,6 @@ static designator_t *parse_designation(void) } } -static initializer_t *initializer_from_string(array_type_t *const type, - const string_t *const string) -{ - /* TODO: check len vs. size of array type */ - (void) type; - - initializer_t *initializer = allocate_initializer_zero(INITIALIZER_STRING); - initializer->string.string = *string; - - return initializer; -} - -static initializer_t *initializer_from_wide_string(array_type_t *const type, - const string_t *const string) -{ - /* TODO: check len vs. size of array type */ - (void) type; - - initializer_t *const initializer = - allocate_initializer_zero(INITIALIZER_WIDE_STRING); - initializer->wide_string.string = *string; - - return initializer; -} - /** * Build an initializer from a given expression. */ @@ -1569,39 +1569,36 @@ static initializer_t *initializer_from_expression(type_t *orig_type, { /* TODO check that expression is a constant expression */ - /* §6.7.8.14/15 char array may be initialized by string literals */ - type_t *type = skip_typeref(orig_type); - type_t *expr_type_orig = expression->base.type; - type_t *expr_type = skip_typeref(expr_type_orig); + type_t *const type = skip_typeref(orig_type); - if (is_type_array(type) && expr_type->kind == TYPE_POINTER) { + /* §6.7.8.14/15 char array may be initialized by string literals */ + if (expression->kind == EXPR_STRING_LITERAL && is_type_array(type)) { array_type_t *const array_type = &type->array; type_t *const element_type = skip_typeref(array_type->element_type); - - if (element_type->kind == TYPE_ATOMIC) { - atomic_type_kind_t akind = element_type->atomic.akind; - switch (expression->kind) { - case EXPR_STRING_LITERAL: - if (akind == ATOMIC_TYPE_CHAR - || akind == ATOMIC_TYPE_SCHAR - || akind == ATOMIC_TYPE_UCHAR) { - return initializer_from_string(array_type, - &expression->string_literal.value); - } - break; - - case EXPR_WIDE_STRING_LITERAL: { - type_t *bare_wchar_type = skip_typeref(type_wchar_t); - if (get_unqualified_type(element_type) == bare_wchar_type) { - return initializer_from_wide_string(array_type, - &expression->string_literal.value); - } - break; + switch (expression->string_literal.value.encoding) { + case STRING_ENCODING_CHAR: + case STRING_ENCODING_UTF8: { + if (is_type_atomic(element_type, ATOMIC_TYPE_CHAR) || + is_type_atomic(element_type, ATOMIC_TYPE_SCHAR) || + is_type_atomic(element_type, ATOMIC_TYPE_UCHAR)) { + goto make_string_init; } + break; + } - default: - break; + case STRING_ENCODING_CHAR16: + case STRING_ENCODING_CHAR32: + case STRING_ENCODING_WIDE: { + assert(is_type_pointer(expression->base.type)); + type_t *const init_type = get_unqualified_type(expression->base.type->pointer.points_to); + if (types_compatible(get_unqualified_type(element_type), init_type)) { +make_string_init:; + initializer_t *const init = allocate_initializer_zero(INITIALIZER_STRING); + init->value.value = expression; + return init; } + break; + } } } @@ -1655,7 +1652,7 @@ static initializer_t *parse_scalar_initializer(type_t *type, bool additional_warning_displayed = false; while (braces > 0) { - next_if(','); + accept(','); if (token.kind != '}') { if (!additional_warning_displayed) { warningf(WARN_OTHER, HERE, "additional elements in scalar initializer"); @@ -1853,7 +1850,8 @@ static bool walk_designator(type_path_t *path, const designator_t *designator, } } else { expression_t *array_index = designator->array_index; - assert(designator->array_index != NULL); + if (is_constant_expression(array_index) != EXPR_CLASS_CONSTANT) + return true; if (!is_type_array(type)) { if (is_type_valid(type)) { @@ -1946,7 +1944,7 @@ static void advance_current_object(type_path_t *path, size_t top_path_level) */ static void skip_initializers(void) { - next_if('{'); + accept('{'); while (token.kind != '}') { if (token.kind == T_EOF) @@ -1978,6 +1976,8 @@ static initializer_t *parse_sub_initializer(type_path_t *path, return create_empty_initializer(); } + initializer_t *result = NULL; + type_t *orig_type = path->top_type; type_t *type = NULL; @@ -1997,8 +1997,8 @@ static initializer_t *parse_sub_initializer(type_path_t *path, } else if (token.kind == T_IDENTIFIER && look_ahead(1)->kind == ':') { /* GNU-style designator ("identifier: value") */ designator = allocate_ast_zero(sizeof(designator[0])); - designator->source_position = token.base.source_position; - designator->symbol = token.identifier.symbol; + designator->source_position = *HERE; + designator->symbol = token.base.symbol; eat(T_IDENTIFIER); eat(':'); @@ -2027,9 +2027,7 @@ finish_designator: } else { if (type == NULL) { if (env->entity != NULL) { - errorf(HERE, - "extra brace group at end of initializer for '%Y'", - env->entity->base.symbol); + errorf(HERE, "extra brace group at end of initializer for '%N'", env->entity); } else { errorf(HERE, "extra brace group at end of initializer"); } @@ -2074,7 +2072,7 @@ finish_designator: source_position_t const* const pos = &expression->base.source_position; if (env->entity != NULL) { - warningf(WARN_OTHER, pos, "excess elements in initializer for '%Y'", env->entity->base.symbol); + warningf(WARN_OTHER, pos, "excess elements in initializer for '%N'", env->entity); } else { warningf(WARN_OTHER, pos, "excess elements in initializer"); } @@ -2082,17 +2080,15 @@ finish_designator: } /* handle { "string" } special case */ - if ((expression->kind == EXPR_STRING_LITERAL - || expression->kind == EXPR_WIDE_STRING_LITERAL) - && outer_type != NULL) { - sub = initializer_from_expression(outer_type, expression); - if (sub != NULL) { - next_if(','); + if (expression->kind == EXPR_STRING_LITERAL && outer_type != NULL) { + result = initializer_from_expression(outer_type, expression); + if (result != NULL) { + accept(','); if (token.kind != '}') { - warningf(WARN_OTHER, HERE, "excessive elements in initializer for type '%T'", orig_type); + warningf(WARN_OTHER, HERE, "excessive elements in initializer for type '%T'", outer_type); } /* TODO: eat , ... */ - return sub; + goto out; } } @@ -2133,12 +2129,8 @@ finish_designator: ARR_APP1(initializer_t*, initializers, sub); error_parse_next: - if (token.kind == '}') { + if (!accept(',')) break; - } - add_anchor_token('}'); - expect(','); - rem_anchor_token('}'); if (token.kind == '}') { break; } @@ -2156,22 +2148,19 @@ error_parse_next: size_t len = ARR_LEN(initializers); size_t size = sizeof(initializer_list_t) + len * sizeof(initializers[0]); - initializer_t *result = allocate_ast_zero(size); - result->kind = INITIALIZER_LIST; - result->list.len = len; + result = allocate_ast_zero(size); + result->kind = INITIALIZER_LIST; + result->list.len = len; memcpy(&result->list.initializers, initializers, len * sizeof(initializers[0])); - - DEL_ARR_F(initializers); - ascend_to(path, top_path_level+1); - - return result; + goto out; end_error: skip_initializers(); +out: DEL_ARR_F(initializers); ascend_to(path, top_path_level+1); - return NULL; + return result; } static expression_t *make_size_literal(size_t value) @@ -2233,13 +2222,10 @@ static initializer_t *parse_initializer(parse_initializer_env_t *env) size = max_index + 1; break; - case INITIALIZER_STRING: - size = result->string.string.size; - break; - - case INITIALIZER_WIDE_STRING: - size = result->wide_string.string.size; + case INITIALIZER_STRING: { + size = get_string_len(&get_init_string(result)->value) + 1; break; + } case INITIALIZER_DESIGNATOR: case INITIALIZER_VALUE: @@ -2291,9 +2277,9 @@ static compound_t *parse_compound_type_specifier(bool is_struct) entity_kind_tag_t const kind = is_struct ? ENTITY_STRUCT : ENTITY_UNION; if (token.kind == T_IDENTIFIER) { /* the compound has a name, check if we have seen it already */ - symbol = token.identifier.symbol; + symbol = token.base.symbol; entity = get_tag(symbol, kind); - next_token(); + eat(T_IDENTIFIER); if (entity != NULL) { if (entity->base.parent_scope != current_scope && @@ -2338,6 +2324,7 @@ static compound_t *parse_compound_type_specifier(bool is_struct) } if (attributes != NULL) { + entity->compound.attributes = attributes; handle_entity_attributes(attributes, entity); } @@ -2350,7 +2337,7 @@ static void parse_enum_entries(type_t *const enum_type) if (token.kind == '}') { errorf(HERE, "empty enum not allowed"); - next_token(); + eat('}'); return; } @@ -2364,7 +2351,7 @@ static void parse_enum_entries(type_t *const enum_type) entity->enum_value.enum_type = enum_type; rem_anchor_token('='); - if (next_if('=')) { + if (accept('=')) { expression_t *value = parse_constant_expression(); value = create_implicit_cast(value, enum_type); @@ -2374,7 +2361,7 @@ static void parse_enum_entries(type_t *const enum_type) } record_entity(entity, false); - } while (next_if(',') && token.kind != '}'); + } while (accept(',') && token.kind != '}'); rem_anchor_token(','); rem_anchor_token('}'); @@ -2390,9 +2377,9 @@ static type_t *parse_enum_specifier(void) eat(T_enum); switch (token.kind) { case T_IDENTIFIER: - symbol = token.identifier.symbol; + symbol = token.base.symbol; entity = get_tag(symbol, ENTITY_ENUM); - next_token(); + eat(T_IDENTIFIER); if (entity != NULL) { if (entity->base.parent_scope != current_scope && @@ -2464,14 +2451,14 @@ static type_t *parse_typeof(void) type_t *type; - expect('('); add_anchor_token(')'); + expect('('); expression_t *expression = NULL; switch (token.kind) { case T_IDENTIFIER: - if (is_typedef_symbol(token.identifier.symbol)) { + if (is_typedef_symbol(token.base.symbol)) { DECLARATION_START type = parse_typename(); } else { @@ -2493,6 +2480,7 @@ static type_t *parse_typeof(void) } typedef enum specifiers_t { + SPECIFIER_NONE = 0, SPECIFIER_SIGNED = 1 << 0, SPECIFIER_UNSIGNED = 1 << 1, SPECIFIER_LONG = 1 << 2, @@ -2530,10 +2518,10 @@ static attribute_t *parse_attribute_ms_property(attribute_t *attribute) { attribute_property_argument_t *const property = allocate_ast_zero(sizeof(*property)); - expect('('); - add_anchor_token(')'); add_anchor_token(','); + expect('('); + do { add_anchor_token('='); source_position_t pos; @@ -2558,7 +2546,7 @@ static attribute_t *parse_attribute_ms_property(attribute_t *attribute) symbol_t *const sym = expect_identifier("while parsing property declspec", NULL); if (prop != NULL) *prop = sym ? sym : sym_anonymous; - } while (next_if(',')); + } while (accept(',')); rem_anchor_token(','); rem_anchor_token(')'); @@ -2571,10 +2559,10 @@ static attribute_t *parse_attribute_ms_property(attribute_t *attribute) static attribute_t *parse_microsoft_extended_decl_modifier_single(void) { attribute_kind_t kind = ATTRIBUTE_UNKNOWN; - if (next_if(T_restrict)) { + if (accept(T_restrict)) { kind = ATTRIBUTE_MS_RESTRICT; } else if (token.kind == T_IDENTIFIER) { - const char *name = token.identifier.symbol->string; + char const *const name = token.base.symbol->string; for (attribute_kind_t k = ATTRIBUTE_MS_FIRST; k <= ATTRIBUTE_MS_LAST; ++k) { const char *attribute_name = get_attribute_name(k); @@ -2600,7 +2588,7 @@ static attribute_t *parse_microsoft_extended_decl_modifier_single(void) } /* parse arguments */ - if (next_if('(')) + if (accept('(')) attribute->a.arguments = parse_attribute_arguments(); return attribute; @@ -2610,10 +2598,9 @@ static attribute_t *parse_microsoft_extended_decl_modifier(attribute_t *first) { eat(T__declspec); + add_anchor_token(')'); expect('('); if (token.kind != ')') { - add_anchor_token(')'); - attribute_t **anchor = &first; do { while (*anchor != NULL) @@ -2626,10 +2613,9 @@ static attribute_t *parse_microsoft_extended_decl_modifier(attribute_t *first) *anchor = attribute; anchor = &attribute->next; - } while (next_if(',')); - - rem_anchor_token(')'); + } while (accept(',')); } + rem_anchor_token(')'); expect(')'); return first; } @@ -2658,7 +2644,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) bool saw_error = false; memset(specifiers, 0, sizeof(*specifiers)); - specifiers->source_position = token.base.source_position; + specifiers->source_position = *HERE; while (true) { specifiers->attributes = parse_attributes(specifiers->attributes); @@ -2673,7 +2659,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) specifiers->storage_class = class; \ if (specifiers->thread_local) \ goto check_thread_storage_class; \ - next_token(); \ + eat(token); \ break; MATCH_STORAGE_CLASS(T_typedef, STORAGE_CLASS_TYPEDEF) @@ -2687,9 +2673,9 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) = parse_microsoft_extended_decl_modifier(specifiers->attributes); break; - case T___thread: + case T__Thread_local: if (specifiers->thread_local) { - errorf(HERE, "duplicate '__thread'"); + errorf(HERE, "duplicate %K", &token); } else { specifiers->thread_local = true; check_thread_storage_class: @@ -2704,7 +2690,7 @@ check_thread_storage_class: case STORAGE_CLASS_REGISTER: wrong = "register"; goto wrong_thread_storage_class; case STORAGE_CLASS_TYPEDEF: wrong = "typedef"; goto wrong_thread_storage_class; wrong_thread_storage_class: - errorf(HERE, "'__thread' used with '%s'", wrong); + errorf(HERE, "%K used with '%s'", &token, wrong); break; } } @@ -2715,7 +2701,7 @@ wrong_thread_storage_class: #define MATCH_TYPE_QUALIFIER(token, qualifier) \ case token: \ qualifiers |= qualifier; \ - next_token(); \ + eat(token); \ break MATCH_TYPE_QUALIFIER(T_const, TYPE_QUALIFIER_CONST); @@ -2735,7 +2721,7 @@ wrong_thread_storage_class: } else { \ type_specifiers |= specifier; \ } \ - next_token(); \ + eat(token); \ break MATCH_SPECIFIER(T__Bool, SPECIFIER_BOOL, "_Bool"); @@ -2758,13 +2744,13 @@ wrong_thread_storage_class: MATCH_SPECIFIER(T_wchar_t, SPECIFIER_WCHAR_T, "wchar_t"); case T_inline: - next_token(); + eat(T_inline); specifiers->is_inline = true; break; #if 0 case T__forceinline: - next_token(); + eat(T__forceinline); specifiers->modifiers |= DM_FORCEINLINE; break; #endif @@ -2777,7 +2763,7 @@ wrong_thread_storage_class: } else { type_specifiers |= SPECIFIER_LONG; } - next_token(); + eat(T_long); break; #define CHECK_DOUBLE_TYPE() \ @@ -2805,7 +2791,7 @@ wrong_thread_storage_class: case T___builtin_va_list: CHECK_DOUBLE_TYPE(); type = duplicate_type(type_valist); - next_token(); + eat(T___builtin_va_list); break; case T_IDENTIFIER: { @@ -2826,7 +2812,7 @@ wrong_thread_storage_class: case '&': case '*': errorf(HERE, "discarding stray %K in declaration specifier", &token); - next_token(); + eat(T_IDENTIFIER); continue; default: @@ -2834,7 +2820,7 @@ wrong_thread_storage_class: } } - type_t *const typedef_type = get_typedef_type(token.identifier.symbol); + type_t *const typedef_type = get_typedef_type(token.base.symbol); if (typedef_type == NULL) { /* Be somewhat resilient to typos like 'vodi f()' at the beginning of a * declaration, so it doesn't generate 'implicit int' followed by more @@ -2847,14 +2833,12 @@ wrong_thread_storage_class: case '*': { errorf(HERE, "%K does not name a type", &token); - symbol_t *symbol = token.identifier.symbol; - entity_t *entity - = create_error_entity(symbol, ENTITY_TYPEDEF); + entity_t *const entity = create_error_entity(token.base.symbol, ENTITY_TYPEDEF); type = allocate_type_zero(TYPE_TYPEDEF); type->typedeft.typedefe = &entity->typedefe; - next_token(); + eat(T_IDENTIFIER); saw_error = true; continue; } @@ -2864,7 +2848,7 @@ wrong_thread_storage_class: } } - next_token(); + eat(T_IDENTIFIER); type = typedef_type; break; } @@ -3035,7 +3019,8 @@ warn_about_long_long: } else { errorf(pos, "multiple datatypes in declaration"); } - goto end_error; + specifiers->type = type_error_type; + return; } } @@ -3064,10 +3049,6 @@ warn_about_long_long: if (specifiers->attributes != NULL) type = handle_type_attributes(specifiers->attributes, type); specifiers->type = type; - return; - -end_error: - specifiers->type = type_error_type; } static type_qualifiers_t parse_type_qualifiers(void) @@ -3100,13 +3081,13 @@ static void parse_identifier_list(scope_t *scope) { assert(token.kind == T_IDENTIFIER); do { - entity_t *const entity = allocate_entity_zero(ENTITY_PARAMETER, NAMESPACE_NORMAL, token.identifier.symbol, HERE); + entity_t *const entity = allocate_entity_zero(ENTITY_PARAMETER, NAMESPACE_NORMAL, token.base.symbol, HERE); /* a K&R parameter has no type, yet */ - next_token(); + eat(T_IDENTIFIER); if (scope != NULL) append_entity(scope, entity); - } while (next_if(',') && token.kind == T_IDENTIFIER); + } while (accept(',') && token.kind == T_IDENTIFIER); } static entity_t *parse_parameter(void) @@ -3140,8 +3121,7 @@ static bool has_parameters(void) if (look_ahead(1)->kind != ')') return true; if (token.kind == T_IDENTIFIER) { - entity_t const *const entity - = get_entity(token.identifier.symbol, NAMESPACE_NORMAL); + entity_t const *const entity = get_entity(token.base.symbol, NAMESPACE_NORMAL); if (entity == NULL) return true; if (entity->kind != ENTITY_TYPEDEF) @@ -3170,11 +3150,11 @@ static bool has_parameters(void) */ static void parse_parameters(function_type_t *type, scope_t *scope) { - eat('('); add_anchor_token(')'); + eat('('); - if (token.kind == T_IDENTIFIER && - !is_typedef_symbol(token.identifier.symbol) && + if (token.kind == T_IDENTIFIER && + !is_typedef_symbol(token.base.symbol) && (look_ahead(1)->kind == ',' || look_ahead(1)->kind == ')')) { type->kr_style_parameters = true; parse_identifier_list(scope); @@ -3188,7 +3168,7 @@ static void parse_parameters(function_type_t *type, scope_t *scope) do { switch (token.kind) { case T_DOTDOTDOT: - next_token(); + eat(T_DOTDOTDOT); type->variadic = true; goto parameters_finished; @@ -3220,7 +3200,7 @@ static void parse_parameters(function_type_t *type, scope_t *scope) default: goto parameters_finished; } - } while (next_if(',')); + } while (accept(',')); parameters_finished: rem_anchor_token(','); } @@ -3317,12 +3297,12 @@ static construct_type_t *parse_array_declarator(void) eat('['); add_anchor_token(']'); - bool is_static = next_if(T_static); + bool is_static = accept(T_static); type_qualifiers_t type_qualifiers = parse_type_qualifiers(); if (!is_static) - is_static = next_if(T_static); + is_static = accept(T_static); array->type_qualifiers = type_qualifiers; array->is_static = is_static; @@ -3330,7 +3310,7 @@ static construct_type_t *parse_array_declarator(void) expression_t *size = NULL; if (token.kind == '*' && look_ahead(1)->kind == ']') { array->is_variable = true; - next_token(); + eat('*'); } else if (token.kind != ']') { size = parse_assignment_expression(); @@ -3429,10 +3409,10 @@ ptr_operator_end: ; if (env->must_be_abstract) { errorf(HERE, "no identifier expected in typename"); } else { - env->symbol = token.identifier.symbol; - env->source_position = token.base.source_position; + env->symbol = token.base.symbol; + env->source_position = *HERE; } - next_token(); + eat(T_IDENTIFIER); break; case '(': { @@ -3440,7 +3420,7 @@ ptr_operator_end: ; token_t const *const la1 = look_ahead(1); switch (la1->kind) { case T_IDENTIFIER: - if (is_typedef_symbol(la1->identifier.symbol)) { + if (is_typedef_symbol(la1->base.symbol)) { case ')': /* §6.7.6:2 footnote 126: Empty parentheses in a type name are * interpreted as ``function with no parameter specification'', rather @@ -3457,7 +3437,7 @@ ptr_operator_end: ; case '[': case T___attribute__: /* FIXME __attribute__ might also introduce a parameter of a function declarator. */ /* Paranthesized declarator. */ - next_token(); + eat('('); add_anchor_token(')'); inner_types = parse_inner_declarator(env); if (inner_types != NULL) { @@ -3712,15 +3692,12 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, if (env.symbol != NULL) { if (specifiers->is_inline && is_type_valid(type)) { - errorf(&env.source_position, - "compound member '%Y' declared 'inline'", env.symbol); + errorf(&env.source_position, "'%N' declared 'inline'", entity); } if (specifiers->thread_local || specifiers->storage_class != STORAGE_CLASS_NONE) { - errorf(&env.source_position, - "compound member '%Y' must have no storage class", - env.symbol); + errorf(&env.source_position, "'%N' must have no storage class", entity); } } } else if (flags & DECL_IS_PARAMETER) { @@ -3768,7 +3745,7 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, } } if (invalid_storage_class) { - errorf(&env.source_position, "invalid storage class for variable '%N'", entity); + errorf(&env.source_position, "invalid storage class for '%N'", entity); } } } @@ -4104,12 +4081,12 @@ warn_redundant_declaration: ; } else if (!is_definition && is_type_valid(prev_type) && !pos->is_system_header) { - warningf(WARN_REDUNDANT_DECLS, pos, "redundant declaration for '%Y' (declared %P)", symbol, ppos); + warningf(WARN_REDUNDANT_DECLS, pos, "redundant declaration for '%N' (declared %P)", entity, ppos); } } else if (current_function == NULL) { if (old_storage_class != STORAGE_CLASS_STATIC && new_storage_class == STORAGE_CLASS_STATIC) { - errorf(pos, "static declaration of '%Y' follows non-static declaration (declared %P)", symbol, ppos); + errorf(pos, "static declaration of '%N' follows non-static declaration (declared %P)", entity, ppos); } else if (old_storage_class == STORAGE_CLASS_EXTERN) { prev_decl->storage_class = STORAGE_CLASS_NONE; prev_decl->declared_storage_class = STORAGE_CLASS_NONE; @@ -4122,9 +4099,9 @@ warn_redundant_declaration: ; } else if (is_type_valid(prev_type)) { if (old_storage_class == new_storage_class) { error_redeclaration: - errorf(pos, "redeclaration of '%Y' (declared %P)", symbol, ppos); + errorf(pos, "redeclaration of '%N' (declared %P)", entity, ppos); } else { - errorf(pos, "redeclaration of '%Y' with different linkage (declared %P)", symbol, ppos); + errorf(pos, "redeclaration of '%N' with different linkage (declared %P)", entity, ppos); } } } @@ -4173,8 +4150,7 @@ finish: static void parser_error_multiple_definition(entity_t *entity, const source_position_t *source_position) { - errorf(source_position, "multiple definition of '%Y' (declared %P)", - entity->base.symbol, &entity->base.source_position); + errorf(source_position, "redefinition of '%N' (declared %P)", entity, &entity->base.source_position); } static bool is_declaration_specifier(const token_t *token) @@ -4183,7 +4159,7 @@ static bool is_declaration_specifier(const token_t *token) DECLARATION_START return true; case T_IDENTIFIER: - return is_typedef_symbol(token->identifier.symbol); + return is_typedef_symbol(token->base.symbol); default: return false; @@ -4322,7 +4298,7 @@ static void parse_declaration_rest(entity_t *ndeclaration, check_variable_type_complete(entity); - if (!next_if(',')) + if (!accept(',')) break; add_anchor_token('='); @@ -4612,8 +4588,7 @@ static void check_declarations(void) warn_unused_entity(WARN_UNUSED_PARAMETER, scope->entities, NULL); } if (is_warn_on(WARN_UNUSED_VARIABLE)) { - walk_statements(current_function->statement, check_unused_variables, - NULL); + walk_statements(current_function->body, check_unused_variables, NULL); } } @@ -4656,8 +4631,8 @@ static bool expression_returns(expression_t const *const expr) case EXPR_REFERENCE: case EXPR_ENUM_CONSTANT: case EXPR_LITERAL_CASES: + case EXPR_LITERAL_CHARACTER: case EXPR_STRING_LITERAL: - case EXPR_WIDE_STRING_LITERAL: case EXPR_COMPOUND_LITERAL: // TODO descend into initialisers case EXPR_LABEL_ADDRESS: case EXPR_CLASSIFY_TYPE: @@ -4742,7 +4717,6 @@ static bool initializer_returns(initializer_t const *const init) } case INITIALIZER_STRING: - case INITIALIZER_WIDE_STRING: case INITIALIZER_DESIGNATOR: // designators have no payload return true; } @@ -4831,7 +4805,7 @@ static void check_reachable(statement_t *const stmt) return; if (is_constant_expression(expr) == EXPR_CLASS_CONSTANT) { - long const val = fold_constant_to_int(expr); + ir_tarval *const val = fold_constant_to_tarval(expr); case_label_statement_t * defaults = NULL; for (case_label_statement_t *i = switchs->first_case; i != NULL; i = i->next) { if (i->expression == NULL) { @@ -4839,7 +4813,9 @@ static void check_reachable(statement_t *const stmt) continue; } - if (i->first_case <= val && val <= i->last_case) { + if (i->first_case == val || i->last_case == val || + ((tarval_cmp(i->first_case, val) & ir_relation_less_equal) + && (tarval_cmp(val, i->last_case) & ir_relation_less_equal))) { check_reachable((statement_t*)i); return; } @@ -4884,7 +4860,6 @@ static void check_reachable(statement_t *const stmt) next = parent; switch (parent->kind) { - case STATEMENT_WHILE: goto continue_while; case STATEMENT_DO_WHILE: goto continue_do_while; case STATEMENT_FOR: goto continue_for; @@ -4900,7 +4875,6 @@ static void check_reachable(statement_t *const stmt) switch (parent->kind) { case STATEMENT_SWITCH: - case STATEMENT_WHILE: case STATEMENT_DO_WHILE: case STATEMENT_FOR: last = parent; @@ -4938,25 +4912,6 @@ found_break_parent: next = stmt->case_label.statement; break; - case STATEMENT_WHILE: { - while_statement_t const *const whiles = &stmt->whiles; - expression_t const *const cond = whiles->condition; - - if (!expression_returns(cond)) - return; - - int const val = determine_truth(cond); - - if (val >= 0) - check_reachable(whiles->body); - - if (val > 0) - return; - - next = stmt->base.next; - break; - } - case STATEMENT_DO_WHILE: next = stmt->do_while.body; break; @@ -5061,31 +5016,6 @@ found_break_parent: next = next->base.next; break; - case STATEMENT_WHILE: { -continue_while: - if (next->base.reachable) - return; - next->base.reachable = true; - - while_statement_t const *const whiles = &next->whiles; - expression_t const *const cond = whiles->condition; - - if (!expression_returns(cond)) - return; - - int const val = determine_truth(cond); - - if (val >= 0) - check_reachable(whiles->body); - - if (val > 0) - return; - - last = next; - next = next->base.next; - break; - } - case STATEMENT_DO_WHILE: { continue_do_while: if (next->base.reachable) @@ -5355,7 +5285,7 @@ static void parse_external_declaration(void) environment_push(parameter); } - if (function->statement != NULL) { + if (function->body != NULL) { parser_error_multiple_definition(entity, HERE); eat_block(); } else { @@ -5372,7 +5302,7 @@ static void parse_external_declaration(void) label_anchor = &label_first; statement_t *const body = parse_compound_statement(false); - function->statement = body; + function->body = body; first_err = true; check_labels(); check_declarations(); @@ -5507,8 +5437,7 @@ static expression_t *find_create_select(const source_position_t *pos, symbol_t *iter_symbol = iter->base.symbol; if (iter_symbol == NULL) { type_t *type = iter->declaration.type; - if (type->kind != TYPE_COMPOUND_STRUCT - && type->kind != TYPE_COMPOUND_UNION) + if (!is_type_compound(type)) continue; compound_t *sub_compound = type->compound.compound; @@ -5618,7 +5547,7 @@ static void parse_compound_declarators(compound_t *compound, entity_t *prev = find_compound_entry(compound, symbol); if (prev != NULL) { source_position_t const *const ppos = &prev->base.source_position; - errorf(pos, "multiple declarations of symbol '%Y' (declared %P)", symbol, ppos); + errorf(pos, "multiple declarations of '%N' (declared %P)", entity, ppos); } } @@ -5647,7 +5576,7 @@ static void parse_compound_declarators(compound_t *compound, append_entity(&compound->members, entity); } } - } while (next_if(',')); + } while (accept(',')); rem_anchor_token(','); rem_anchor_token(';'); expect(';'); @@ -5715,14 +5644,17 @@ struct expression_parser_function_t { static expression_parser_function_t expression_parsers[T_LAST_TOKEN]; -static type_t *get_string_type(void) -{ - return is_warn_on(WARN_WRITE_STRINGS) ? type_const_char_ptr : type_char_ptr; -} - -static type_t *get_wide_string_type(void) +static type_t *get_string_type(string_encoding_t const enc) { - return is_warn_on(WARN_WRITE_STRINGS) ? type_const_wchar_t_ptr : type_wchar_t_ptr; + bool const warn = is_warn_on(WARN_WRITE_STRINGS); + switch (enc) { + case STRING_ENCODING_CHAR: + case STRING_ENCODING_UTF8: return warn ? type_const_char_ptr : type_char_ptr; + case STRING_ENCODING_CHAR16: return warn ? type_char16_t_const_ptr : type_char16_t_ptr; + case STRING_ENCODING_CHAR32: return warn ? type_char32_t_const_ptr : type_char32_t_ptr; + case STRING_ENCODING_WIDE: return warn ? type_const_wchar_t_ptr : type_wchar_t_ptr; + } + panic("invalid string encoding"); } /** @@ -5730,31 +5662,10 @@ static type_t *get_wide_string_type(void) */ static expression_t *parse_string_literal(void) { - source_position_t begin = token.base.source_position; - string_t res = token.string.string; - bool is_wide = (token.kind == T_WIDE_STRING_LITERAL); - - next_token(); - while (token.kind == T_STRING_LITERAL - || token.kind == T_WIDE_STRING_LITERAL) { - warn_string_concat(&token.base.source_position); - res = concat_strings(&res, &token.string.string); - next_token(); - is_wide |= token.kind == T_WIDE_STRING_LITERAL; - } - - expression_t *literal; - if (is_wide) { - literal = allocate_expression_zero(EXPR_WIDE_STRING_LITERAL); - literal->base.type = get_wide_string_type(); - } else { - literal = allocate_expression_zero(EXPR_STRING_LITERAL); - literal->base.type = get_string_type(); - } - literal->base.source_position = begin; - literal->literal.value = res; - - return literal; + expression_t *const expr = allocate_expression_zero(EXPR_STRING_LITERAL); + expr->string_literal.value = concat_string_literals(); + expr->base.type = get_string_type(expr->string_literal.value.encoding); + return expr; } /** @@ -5767,157 +5678,244 @@ static expression_t *parse_boolean_literal(bool value) literal->literal.value.begin = value ? "true" : "false"; literal->literal.value.size = value ? 4 : 5; - next_token(); + eat(value ? T_true : T_false); return literal; } -static void warn_traditional_suffix(void) +static void warn_traditional_suffix(char const *const suffix) { - warningf(WARN_TRADITIONAL, HERE, "traditional C rejects the '%S' suffix", - &token.number.suffix); + warningf(WARN_TRADITIONAL, HERE, "traditional C rejects the '%s' suffix", suffix); } -static void check_integer_suffix(void) +static void check_integer_suffix(expression_t *const expr, char const *const suffix) { - const string_t *suffix = &token.number.suffix; - if (suffix->size == 0) - return; - - bool not_traditional = false; - const char *c = suffix->begin; - if (*c == 'l' || *c == 'L') { - ++c; - if (*c == *(c-1)) { - not_traditional = true; - ++c; - if (*c == 'u' || *c == 'U') { + unsigned spec = SPECIFIER_NONE; + char const *c = suffix; + for (;;) { + specifiers_t add; + if (*c == 'L' || *c == 'l') { + add = SPECIFIER_LONG; + if (*c == c[1]) { + add |= SPECIFIER_LONG_LONG; ++c; } - } else if (*c == 'u' || *c == 'U') { - not_traditional = true; - ++c; + } else if (*c == 'U' || *c == 'u') { + add = SPECIFIER_UNSIGNED; + } else { + break; } - } else if (*c == 'u' || *c == 'U') { - not_traditional = true; ++c; - if (*c == 'l' || *c == 'L') { - ++c; - if (*c == *(c-1)) { - ++c; - } - } - } - if (*c != '\0') { - errorf(&token.base.source_position, - "invalid suffix '%S' on integer constant", suffix); - } else if (not_traditional) { - warn_traditional_suffix(); + if (spec & add) + goto error; + spec |= add; + } + + if (*c == '\0') { + type_t *type; + switch (spec) { + case SPECIFIER_NONE: type = type_int; break; + case SPECIFIER_LONG: type = type_long; break; + case SPECIFIER_LONG | SPECIFIER_LONG_LONG: type = type_long_long; break; + case SPECIFIER_UNSIGNED: type = type_unsigned_int; break; + case SPECIFIER_UNSIGNED | SPECIFIER_LONG: type = type_unsigned_long; break; + case SPECIFIER_UNSIGNED | SPECIFIER_LONG | SPECIFIER_LONG_LONG: type = type_unsigned_long_long; break; + default: panic("inconsistent suffix"); + } + if (spec != SPECIFIER_NONE && spec != SPECIFIER_LONG) { + warn_traditional_suffix(suffix); + } + expr->base.type = type; + /* Integer type depends on the size of the number and the size + * representable by the types. The backend/codegeneration has to + * determine that. */ + determine_literal_type(&expr->literal); + } else { +error: + errorf(HERE, "invalid suffix '%s' on integer constant", suffix); } } -static type_t *check_floatingpoint_suffix(void) +static void check_floatingpoint_suffix(expression_t *const expr, char const *const suffix) { - const string_t *suffix = &token.number.suffix; - type_t *type = type_double; - if (suffix->size == 0) - return type; - - bool not_traditional = false; - const char *c = suffix->begin; - if (*c == 'f' || *c == 'F') { - ++c; - type = type_float; - } else if (*c == 'l' || *c == 'L') { - ++c; - type = type_long_double; - } - if (*c != '\0') { - errorf(&token.base.source_position, - "invalid suffix '%S' on floatingpoint constant", suffix); - } else if (not_traditional) { - warn_traditional_suffix(); + type_t *type; + char const *c = suffix; + switch (*c) { + case 'F': + case 'f': type = type_float; ++c; break; + case 'L': + case 'l': type = type_long_double; ++c; break; + default: type = type_double; break; } - return type; + if (*c == '\0') { + expr->base.type = type; + if (suffix[0] != '\0') { + warn_traditional_suffix(suffix); + } + } else { + errorf(HERE, "invalid suffix '%s' on floatingpoint constant", suffix); + } } -/** - * Parse an integer constant. - */ static expression_t *parse_number_literal(void) { - expression_kind_t kind; - type_t *type; + string_t const *const str = &token.literal.string; + char const * i = str->begin; + unsigned digits = 0; + bool is_float = false; - switch (token.kind) { - case T_INTEGER: - kind = EXPR_LITERAL_INTEGER; - check_integer_suffix(); - type = type_int; + /* Parse base prefix. */ + unsigned base; + if (*i == '0') { + switch (*++i) { + case 'B': case 'b': base = 2; ++i; break; + case 'X': case 'x': base = 16; ++i; break; + default: base = 8; digits |= 1U << 0; break; + } + } else { + base = 10; + } + + /* Parse mantissa. */ + for (;; ++i) { + unsigned digit; + switch (*i) { + case '.': + if (is_float) { + errorf(HERE, "multiple decimal points in %K", &token); + i = 0; + goto done; + } + is_float = true; + if (base == 8) + base = 10; + continue; + + case '0': digit = 0; break; + case '1': digit = 1; break; + case '2': digit = 2; break; + case '3': digit = 3; break; + case '4': digit = 4; break; + case '5': digit = 5; break; + case '6': digit = 6; break; + case '7': digit = 7; break; + case '8': digit = 8; break; + case '9': digit = 9; break; + case 'A': case 'a': digit = 10; break; + case 'B': case 'b': digit = 11; break; + case 'C': case 'c': digit = 12; break; + case 'D': case 'd': digit = 13; break; + case 'E': case 'e': digit = 14; break; + case 'F': case 'f': digit = 15; break; + + default: goto done_mantissa; + } + + if (digit >= 10 && base != 16) + goto done_mantissa; + + digits |= 1U << digit; + } +done_mantissa: + + /* Parse exponent. */ + switch (base) { + case 2: + if (is_float) + errorf(HERE, "binary floating %K not allowed", &token); break; - case T_FLOATINGPOINT: - case T_FLOATINGPOINT_HEXADECIMAL: - kind = EXPR_LITERAL_FLOATINGPOINT; - type = check_floatingpoint_suffix(); + case 8: + case 10: + if (*i == 'E' || *i == 'e') { + base = 10; + goto parse_exponent; + } break; - default: - panic("unexpected token type in parse_number_literal"); - } + case 16: + if (*i == 'P' || *i == 'p') { +parse_exponent: + ++i; + is_float = true; - expression_t *literal = allocate_expression_zero(kind); - literal->base.type = type; - literal->literal.value = token.number.number; - literal->literal.suffix = token.number.suffix; - next_token(); + if (*i == '-' || *i == '+') + ++i; - /* integer type depends on the size of the number and the size - * representable by the types. The backend/codegeneration has to determine - * that - */ - determine_literal_type(&literal->literal); - return literal; -} + if (isdigit(*i)) { + do { + ++i; + } while (isdigit(*i)); + } else { + errorf(HERE, "exponent of %K has no digits", &token); + } + } else if (is_float) { + errorf(HERE, "hexadecimal floating %K requires an exponent", &token); + i = 0; + } + break; -/** - * Parse a character constant. - */ -static expression_t *parse_character_constant(void) -{ - expression_t *literal = allocate_expression_zero(EXPR_LITERAL_CHARACTER); - literal->base.type = c_mode & _CXX ? type_char : type_int; - literal->literal.value = token.string.string; + default: + panic("invalid base"); + } - size_t len = literal->literal.value.size; - if (len > 1) { - if (!GNU_MODE && !(c_mode & _C99)) { - errorf(HERE, "more than 1 character in character constant"); +done:; + expression_t *const expr = allocate_expression_zero(is_float ? EXPR_LITERAL_FLOATINGPOINT : EXPR_LITERAL_INTEGER); + expr->literal.value = *str; + + if (i) { + if (digits == 0) { + errorf(HERE, "%K has no digits", &token); + } else if (digits & ~((1U << base) - 1)) { + errorf(HERE, "invalid digit in %K", &token); } else { - literal->base.type = type_int; - warningf(WARN_MULTICHAR, HERE, "multi-character character constant"); + expr->literal.suffix = i; + if (is_float) { + check_floatingpoint_suffix(expr, i); + } else { + check_integer_suffix(expr, i); + } } } - next_token(); - return literal; + eat(T_NUMBER); + return expr; } /** - * Parse a wide character constant. + * Parse a character constant. */ -static expression_t *parse_wide_character_constant(void) +static expression_t *parse_character_constant(void) { - expression_t *literal = allocate_expression_zero(EXPR_LITERAL_WIDE_CHARACTER); - literal->base.type = type_int; - literal->literal.value = token.string.string; + expression_t *const literal = allocate_expression_zero(EXPR_LITERAL_CHARACTER); + literal->string_literal.value = token.literal.string; + + size_t const size = get_string_len(&token.literal.string); + switch (token.literal.string.encoding) { + case STRING_ENCODING_CHAR: + case STRING_ENCODING_UTF8: + literal->base.type = c_mode & _CXX ? type_char : type_int; + if (size > 1) { + if (!GNU_MODE && !(c_mode & _C99)) { + errorf(HERE, "more than 1 character in character constant"); + } else { + literal->base.type = type_int; + warningf(WARN_MULTICHAR, HERE, "multi-character character constant"); + } + } + break; - size_t len = wstrlen(&literal->literal.value); - if (len > 1) { - warningf(WARN_MULTICHAR, HERE, "multi-character character constant"); + case STRING_ENCODING_CHAR16: literal->base.type = type_char16_t; goto warn_multi; + case STRING_ENCODING_CHAR32: literal->base.type = type_char32_t; goto warn_multi; + case STRING_ENCODING_WIDE: literal->base.type = type_wchar_t; goto warn_multi; +warn_multi: + if (size > 1) { + warningf(WARN_MULTICHAR, HERE, "multi-character character constant"); + } + break; } - next_token(); + eat(T_CHARACTER_CONSTANT); return literal; } @@ -6006,13 +6004,9 @@ type_t *revert_automatic_type_conversion(const expression_t *expression) } case EXPR_STRING_LITERAL: { - size_t size = expression->string_literal.value.size; - return make_array_type(type_char, size, TYPE_QUALIFIER_NONE); - } - - case EXPR_WIDE_STRING_LITERAL: { - size_t size = wstrlen(&expression->string_literal.value); - return make_array_type(type_wchar_t, size, TYPE_QUALIFIER_NONE); + size_t const size = get_string_len(&expression->string_literal.value) + 1; + type_t *const elem = get_unqualified_type(expression->base.type->pointer.points_to); + return make_array_type(elem, size, TYPE_QUALIFIER_NONE); } case EXPR_COMPOUND_LITERAL: @@ -6054,7 +6048,7 @@ static entity_t *parse_qualified_identifier(void) source_position_t pos; const scope_t *lookup_scope = NULL; - if (next_if(T_COLONCOLON)) + if (accept(T_COLONCOLON)) lookup_scope = &unit->scope; entity_t *entity; @@ -6066,7 +6060,7 @@ static entity_t *parse_qualified_identifier(void) /* lookup entity */ entity = lookup_entity(lookup_scope, symbol, NAMESPACE_NORMAL); - if (!next_if(T_COLONCOLON)) + if (!accept(T_COLONCOLON)) break; switch (entity->kind) { @@ -6083,7 +6077,7 @@ static entity_t *parse_qualified_identifier(void) symbol, get_entity_kind_name(entity->kind)); /* skip further qualifications */ - while (next_if(T_IDENTIFIER) && next_if(T_COLONCOLON)) {} + while (accept(T_IDENTIFIER) && accept(T_COLONCOLON)) {} return create_error_entity(sym_anonymous, ENTITY_VARIABLE); } @@ -6092,9 +6086,8 @@ static entity_t *parse_qualified_identifier(void) if (entity == NULL) { if (!strict_mode && token.kind == '(') { /* an implicitly declared function */ - warningf(WARN_IMPLICIT_FUNCTION_DECLARATION, &pos, - "implicit declaration of function '%Y'", symbol); entity = create_implicit_function(symbol, &pos); + warningf(WARN_IMPLICIT_FUNCTION_DECLARATION, &pos, "implicit declaration of '%N'", entity); } else { errorf(&pos, "unknown identifier '%Y' found.", symbol); entity = create_error_entity(symbol, ENTITY_VARIABLE); @@ -6106,7 +6099,7 @@ static entity_t *parse_qualified_identifier(void) static expression_t *parse_reference(void) { - source_position_t const pos = token.base.source_position; + source_position_t const pos = *HERE; entity_t *const entity = parse_qualified_identifier(); type_t *orig_type; @@ -6140,12 +6133,8 @@ static expression_t *parse_reference(void) && (current_function != NULL && entity->base.parent_scope->depth < current_function->parameters.depth) && (entity->kind == ENTITY_VARIABLE || entity->kind == ENTITY_PARAMETER)) { - if (entity->kind == ENTITY_VARIABLE) { - /* access of a variable from an outer function */ - entity->variable.address_taken = true; - } else if (entity->kind == ENTITY_PARAMETER) { - entity->parameter.address_taken = true; - } + /* access of a variable from an outer function */ + entity->variable.address_taken = true; current_function->need_closure = true; } @@ -6198,21 +6187,24 @@ static bool semantic_cast(expression_t *cast) return true; } -static expression_t *parse_compound_literal(source_position_t const *const pos, type_t *type) +static expression_t *parse_compound_literal(source_position_t const *const pos, + type_t *type) { expression_t *expression = allocate_expression_zero(EXPR_COMPOUND_LITERAL); expression->base.source_position = *pos; + bool global_scope = current_scope == file_scope; parse_initializer_env_t env; env.type = type; env.entity = NULL; - env.must_be_constant = false; + env.must_be_constant = global_scope; initializer_t *initializer = parse_initializer(&env); type = env.type; - expression->compound_literal.initializer = initializer; - expression->compound_literal.type = type; - expression->base.type = automatic_type_conversion(type); + expression->base.type = automatic_type_conversion(type); + expression->compound_literal.initializer = initializer; + expression->compound_literal.type = type; + expression->compound_literal.global_scope = global_scope; return expression; } @@ -6297,7 +6289,7 @@ static expression_t *parse_parenthesized_expression(void) return parse_statement_expression(); case T_IDENTIFIER: - if (is_typedef_symbol(la1->identifier.symbol)) { + if (is_typedef_symbol(la1->base.symbol)) { DECLARATION_START return parse_cast(); } @@ -6313,68 +6305,21 @@ static expression_t *parse_parenthesized_expression(void) return result; } -static expression_t *parse_function_keyword(void) +static expression_t *parse_function_keyword(funcname_kind_t const kind) { - /* TODO */ - if (current_function == NULL) { - errorf(HERE, "'__func__' used outside of a function"); + errorf(HERE, "%K used outside of a function", &token); } expression_t *expression = allocate_expression_zero(EXPR_FUNCNAME); expression->base.type = type_char_ptr; - expression->funcname.kind = FUNCNAME_FUNCTION; + expression->funcname.kind = kind; next_token(); return expression; } -static expression_t *parse_pretty_function_keyword(void) -{ - if (current_function == NULL) { - errorf(HERE, "'__PRETTY_FUNCTION__' used outside of a function"); - } - - expression_t *expression = allocate_expression_zero(EXPR_FUNCNAME); - expression->base.type = type_char_ptr; - expression->funcname.kind = FUNCNAME_PRETTY_FUNCTION; - - eat(T___PRETTY_FUNCTION__); - - return expression; -} - -static expression_t *parse_funcsig_keyword(void) -{ - if (current_function == NULL) { - errorf(HERE, "'__FUNCSIG__' used outside of a function"); - } - - expression_t *expression = allocate_expression_zero(EXPR_FUNCNAME); - expression->base.type = type_char_ptr; - expression->funcname.kind = FUNCNAME_FUNCSIG; - - eat(T___FUNCSIG__); - - return expression; -} - -static expression_t *parse_funcdname_keyword(void) -{ - if (current_function == NULL) { - errorf(HERE, "'__FUNCDNAME__' used outside of a function"); - } - - expression_t *expression = allocate_expression_zero(EXPR_FUNCNAME); - expression->base.type = type_char_ptr; - expression->funcname.kind = FUNCNAME_FUNCDNAME; - - eat(T___FUNCDNAME__); - - return expression; -} - static designator_t *parse_designator(void) { designator_t *const result = allocate_ast_zero(sizeof(result[0])); @@ -6384,7 +6329,7 @@ static designator_t *parse_designator(void) designator_t *last_designator = result; while (true) { - if (next_if('.')) { + if (accept('.')) { designator_t *const designator = allocate_ast_zero(sizeof(result[0])); designator->symbol = expect_identifier("while parsing member designator", &designator->source_position); if (!designator->symbol) @@ -6394,7 +6339,7 @@ static designator_t *parse_designator(void) last_designator = designator; continue; } - if (next_if('[')) { + if (accept('[')) { add_anchor_token(']'); designator_t *designator = allocate_ast_zero(sizeof(result[0])); designator->source_position = *HERE; @@ -6425,9 +6370,9 @@ static expression_t *parse_offsetof(void) eat(T___builtin_offsetof); - expect('('); add_anchor_token(')'); add_anchor_token(','); + expect('('); type_t *type = parse_typename(); rem_anchor_token(','); expect(','); @@ -6454,8 +6399,25 @@ static expression_t *parse_offsetof(void) return expression; } +static bool is_last_parameter(expression_t *const param) +{ + if (param->kind == EXPR_REFERENCE) { + entity_t *const entity = param->reference.entity; + if (entity->kind == ENTITY_PARAMETER && + !entity->base.next && + entity->base.parent_scope == ¤t_function->parameters) { + return true; + } + } + + if (!is_type_valid(skip_typeref(param->base.type))) + return true; + + return false; +} + /** - * Parses a _builtin_va_start() expression. + * Parses a __builtin_va_start() expression. */ static expression_t *parse_va_start(void) { @@ -6463,31 +6425,25 @@ static expression_t *parse_va_start(void) eat(T___builtin_va_start); - expect('('); add_anchor_token(')'); add_anchor_token(','); + expect('('); expression->va_starte.ap = parse_assignment_expression(); rem_anchor_token(','); expect(','); - expression_t *const expr = parse_assignment_expression(); - if (expr->kind == EXPR_REFERENCE) { - entity_t *const entity = expr->reference.entity; - if (!current_function->base.type->function.variadic) { - errorf(&expr->base.source_position, - "'va_start' used in non-variadic function"); - } else if (entity->base.parent_scope != ¤t_function->parameters || - entity->base.next != NULL || - entity->kind != ENTITY_PARAMETER) { - errorf(&expr->base.source_position, - "second argument of 'va_start' must be last parameter of the current function"); - } else { - expression->va_starte.parameter = &entity->variable; - } - } else { - expression = create_error_expression(); - } + expression_t *const param = parse_assignment_expression(); + expression->va_starte.parameter = param; rem_anchor_token(')'); expect(')'); + + if (!current_function) { + errorf(&expression->base.source_position, "'va_start' used outside of function"); + } else if (!current_function->base.type->function.variadic) { + errorf(&expression->base.source_position, "'va_start' used in non-variadic function"); + } else if (!is_last_parameter(param)) { + errorf(¶m->base.source_position, "second argument of 'va_start' must be last parameter of the current function"); + } + return expression; } @@ -6500,9 +6456,9 @@ static expression_t *parse_va_arg(void) eat(T___builtin_va_arg); - expect('('); add_anchor_token(')'); add_anchor_token(','); + expect('('); call_argument_t ap; ap.expression = parse_assignment_expression(); expression->va_arge.ap = ap.expression; @@ -6526,9 +6482,9 @@ static expression_t *parse_va_copy(void) eat(T___builtin_va_copy); - expect('('); add_anchor_token(')'); add_anchor_token(','); + expect('('); expression_t *dst = parse_assignment_expression(); assign_error_t error = semantic_assign(type_valist, dst); report_assign_error(error, type_valist, dst, "call argument 1", @@ -6557,8 +6513,8 @@ static expression_t *parse_builtin_constant(void) eat(T___builtin_constant_p); - expect('('); add_anchor_token(')'); + expect('('); expression->builtin_constant.value = parse_assignment_expression(); rem_anchor_token(')'); expect(')'); @@ -6576,9 +6532,9 @@ static expression_t *parse_builtin_types_compatible(void) eat(T___builtin_types_compatible_p); - expect('('); add_anchor_token(')'); add_anchor_token(','); + expect('('); expression->builtin_types_compatible.left = parse_typename(); rem_anchor_token(','); expect(','); @@ -6595,36 +6551,22 @@ static expression_t *parse_builtin_types_compatible(void) */ static expression_t *parse_compare_builtin(void) { - expression_t *expression; - + expression_kind_t kind; switch (token.kind) { - case T___builtin_isgreater: - expression = allocate_expression_zero(EXPR_BINARY_ISGREATER); - break; - case T___builtin_isgreaterequal: - expression = allocate_expression_zero(EXPR_BINARY_ISGREATEREQUAL); - break; - case T___builtin_isless: - expression = allocate_expression_zero(EXPR_BINARY_ISLESS); - break; - case T___builtin_islessequal: - expression = allocate_expression_zero(EXPR_BINARY_ISLESSEQUAL); - break; - case T___builtin_islessgreater: - expression = allocate_expression_zero(EXPR_BINARY_ISLESSGREATER); - break; - case T___builtin_isunordered: - expression = allocate_expression_zero(EXPR_BINARY_ISUNORDERED); - break; - default: - internal_errorf(HERE, "invalid compare builtin found"); - } - expression->base.source_position = *HERE; + case T___builtin_isgreater: kind = EXPR_BINARY_ISGREATER; break; + case T___builtin_isgreaterequal: kind = EXPR_BINARY_ISGREATEREQUAL; break; + case T___builtin_isless: kind = EXPR_BINARY_ISLESS; break; + case T___builtin_islessequal: kind = EXPR_BINARY_ISLESSEQUAL; break; + case T___builtin_islessgreater: kind = EXPR_BINARY_ISLESSGREATER; break; + case T___builtin_isunordered: kind = EXPR_BINARY_ISUNORDERED; break; + default: internal_errorf(HERE, "invalid compare builtin found"); + } + expression_t *const expression = allocate_expression_zero(kind); next_token(); - expect('('); add_anchor_token(')'); add_anchor_token(','); + expect('('); expression->binary.left = parse_assignment_expression(); rem_anchor_token(','); expect(','); @@ -6658,8 +6600,8 @@ static expression_t *parse_assume(void) eat(T__assume); - expect('('); add_anchor_token(')'); + expect('('); expression->unary.value = parse_assignment_expression(); rem_anchor_token(')'); expect(')'); @@ -6671,12 +6613,15 @@ static expression_t *parse_assume(void) /** * Return the label for the current symbol or create a new one. */ -static label_t *get_label(void) +static label_t *get_label(char const *const context) { - assert(token.kind == T_IDENTIFIER); assert(current_function != NULL); - entity_t *label = get_entity(token.identifier.symbol, NAMESPACE_LABEL); + symbol_t *const sym = expect_identifier(context, NULL); + if (!sym) + return NULL; + + entity_t *label = get_entity(sym, NAMESPACE_LABEL); /* If we find a local label, we already created the declaration. */ if (label != NULL && label->kind == ENTITY_LOCAL_LABEL) { if (label->base.parent_scope != current_scope) { @@ -6686,11 +6631,10 @@ static label_t *get_label(void) } else if (label == NULL || label->base.parent_scope != ¤t_function->parameters) { /* There is no matching label in the same function, so create a new one. */ source_position_t const nowhere = { NULL, 0, 0, false }; - label = allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, token.identifier.symbol, &nowhere); + label = allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, sym, &nowhere); label_push(label); } - eat(T_IDENTIFIER); return &label->label; } @@ -6699,14 +6643,13 @@ static label_t *get_label(void) */ static expression_t *parse_label_address(void) { - source_position_t source_position = token.base.source_position; + source_position_t const source_position = *HERE; eat(T_ANDAND); - if (token.kind != T_IDENTIFIER) { - parse_error_expected("while parsing label address", T_IDENTIFIER, NULL); + + label_t *const label = get_label("while parsing label address"); + if (!label) return create_error_expression(); - } - label_t *const label = get_label(); label->used = true; label->address_taken = true; @@ -6740,7 +6683,7 @@ static expression_t *parse_noop_expression(void) if (token.kind != ')') do { (void)parse_assignment_expression(); - } while (next_if(',')); + } while (accept(',')); rem_anchor_token(','); rem_anchor_token(')'); @@ -6758,18 +6701,13 @@ static expression_t *parse_primary_expression(void) switch (token.kind) { case T_false: return parse_boolean_literal(false); case T_true: return parse_boolean_literal(true); - case T_INTEGER: - case T_FLOATINGPOINT: - case T_FLOATINGPOINT_HEXADECIMAL: return parse_number_literal(); + case T_NUMBER: return parse_number_literal(); case T_CHARACTER_CONSTANT: return parse_character_constant(); - case T_WIDE_CHARACTER_CONSTANT: return parse_wide_character_constant(); - case T_STRING_LITERAL: - case T_WIDE_STRING_LITERAL: return parse_string_literal(); - case T___FUNCTION__: - case T___func__: return parse_function_keyword(); - case T___PRETTY_FUNCTION__: return parse_pretty_function_keyword(); - case T___FUNCSIG__: return parse_funcsig_keyword(); - case T___FUNCDNAME__: return parse_funcdname_keyword(); + case T_STRING_LITERAL: return parse_string_literal(); + case T___func__: return parse_function_keyword(FUNCNAME_FUNCTION); + case T___PRETTY_FUNCTION__: return parse_function_keyword(FUNCNAME_PRETTY_FUNCTION); + case T___FUNCSIG__: return parse_function_keyword(FUNCNAME_FUNCSIG); + case T___FUNCDNAME__: return parse_function_keyword(FUNCNAME_FUNCDNAME); case T___builtin_offsetof: return parse_offsetof(); case T___builtin_va_start: return parse_va_start(); case T___builtin_va_arg: return parse_va_arg(); @@ -6795,7 +6733,7 @@ static expression_t *parse_primary_expression(void) case T_COLONCOLON: return parse_reference(); case T_IDENTIFIER: - if (!is_typedef_symbol(token.identifier.symbol)) { + if (!is_typedef_symbol(token.base.symbol)) { return parse_reference(); } /* FALLTHROUGH */ @@ -6849,7 +6787,8 @@ static expression_t *parse_array_expression(expression_t *left) check_idx: res_type = automatic_type_conversion(res_type); if (!is_type_integer(idx_type)) { - errorf(&idx->base.source_position, "array subscript must have integer type"); + if (is_type_valid(idx_type)) + errorf(&idx->base.source_position, "array subscript must have integer type"); } else if (is_type_atomic(idx_type, ATOMIC_TYPE_CHAR)) { source_position_t const *const pos = &idx->base.source_position; warningf(WARN_CHAR_SUBSCRIPTS, pos, "array subscript has char type"); @@ -6883,13 +6822,13 @@ static expression_t *parse_typeprop(expression_kind_t const kind) expression_t *tp_expression = allocate_expression_zero(kind); tp_expression->base.type = type_size_t; - eat(kind == EXPR_SIZEOF ? T_sizeof : T___alignof__); + eat(kind == EXPR_SIZEOF ? T_sizeof : T__Alignof); type_t *orig_type; expression_t *expression; if (token.kind == '(' && is_declaration_specifier(look_ahead(1))) { source_position_t const pos = *HERE; - next_token(); + eat('('); add_anchor_token(')'); orig_type = parse_typename(); rem_anchor_token(')'); @@ -6986,9 +6925,7 @@ static expression_t *parse_select_expression(expression_t *addr) type_left = type; } - if (type_left->kind != TYPE_COMPOUND_STRUCT && - type_left->kind != TYPE_COMPOUND_UNION) { - + if (!is_type_compound(type_left)) { if (is_type_valid(type_left) && !saw_error) { errorf(&pos, "request for member '%Y' in something not a struct or union, but '%T'", @@ -7113,7 +7050,6 @@ static void handle_builtin_argument_restrictions(call_expression_t *call) "third argument of '%Y' must be a constant expression", call->function->reference.entity->base.symbol); } - locality = rw->next; } break; default: @@ -7179,7 +7115,7 @@ static expression_t *parse_call_expression(expression_t *expression) *anchor = argument; anchor = &argument->next; - } while (next_if(',')); + } while (accept(',')); } rem_anchor_token(','); rem_anchor_token(')'); @@ -7441,8 +7377,8 @@ static expression_t *parse_builtin_classify_type(void) eat(T___builtin_classify_type); - expect('('); add_anchor_token(')'); + expect('('); expression_t *expression = parse_expression(); rem_anchor_token(')'); expect(')'); @@ -7462,7 +7398,7 @@ static expression_t *parse_delete(void) eat(T_delete); - if (next_if('[')) { + if (accept('[')) { result->kind = EXPR_UNARY_DELETE_ARRAY; expect(']'); } @@ -7610,9 +7546,8 @@ static void semantic_unexpr_arithmetic(unary_expression_t *expression) type_t *const type = skip_typeref(orig_type); if (!is_type_arithmetic(type)) { if (is_type_valid(type)) { - /* TODO: improve error message */ - errorf(&expression->base.source_position, - "operation needs an arithmetic type"); + source_position_t const *const pos = &expression->base.source_position; + errorf(pos, "operand of unary expression must have arithmetic type, but is '%T'", orig_type); } return; } else if (is_type_integer(type)) { @@ -7690,12 +7625,7 @@ static void set_address_taken(expression_t *expression, bool may_be_register) errorf(pos, "address of register '%N' requested", entity); } - if (entity->kind == ENTITY_VARIABLE) { - entity->variable.address_taken = true; - } else { - assert(entity->kind == ENTITY_PARAMETER); - entity->parameter.address_taken = true; - } + entity->variable.address_taken = true; } /** @@ -7852,10 +7782,9 @@ static void semantic_binexpr_arithmetic(binary_expression_t *expression) type_t *const type_right = skip_typeref(orig_type_right); if (!is_type_arithmetic(type_left) || !is_type_arithmetic(type_right)) { - /* TODO: improve error message */ if (is_type_valid(type_left) && is_type_valid(type_right)) { - errorf(&expression->base.source_position, - "operation needs arithmetic types"); + source_position_t const *const pos = &expression->base.source_position; + errorf(pos, "operands of binary expression must have arithmetic types, but are '%T' and '%T'", orig_type_left, orig_type_right); } return; } @@ -7876,10 +7805,9 @@ static void semantic_binexpr_integer(binary_expression_t *const expression) type_t *const type_right = skip_typeref(orig_type_right); if (!is_type_integer(type_left) || !is_type_integer(type_right)) { - /* TODO: improve error message */ if (is_type_valid(type_left) && is_type_valid(type_right)) { - errorf(&expression->base.source_position, - "operation needs integer types"); + source_position_t const *const pos = &expression->base.source_position; + errorf(pos, "operands of binary expression must have integer types, but are '%T' and '%T'", orig_type_left, orig_type_right); } return; } @@ -7906,14 +7834,23 @@ static void warn_div_by_zero(binary_expression_t const *const expression) } /** - * Check the semantic restrictions for a div/mod expression. + * Check the semantic restrictions for a div expression. */ -static void semantic_divmod_arithmetic(binary_expression_t *expression) +static void semantic_div(binary_expression_t *expression) { semantic_binexpr_arithmetic(expression); warn_div_by_zero(expression); } +/** + * Check the semantic restrictions for a mod expression. + */ +static void semantic_mod(binary_expression_t *expression) +{ + semantic_binexpr_integer(expression); + warn_div_by_zero(expression); +} + static void warn_addsub_in_shift(const expression_t *const expr) { if (expr->base.parenthesized) @@ -7940,10 +7877,9 @@ static bool semantic_shift(binary_expression_t *expression) type_t * type_right = skip_typeref(orig_type_right); if (!is_type_integer(type_left) || !is_type_integer(type_right)) { - /* TODO: improve error message */ if (is_type_valid(type_left) && is_type_valid(type_right)) { - errorf(&expression->base.source_position, - "operands of shift operation must have integer types"); + source_position_t const *const pos = &expression->base.source_position; + errorf(pos, "operands of shift expression must have integer types, but are '%T' and '%T'", orig_type_left, orig_type_right); } return false; } @@ -8067,8 +8003,7 @@ static void warn_string_literal_address(expression_t const* expr) expr = expr->unary.value; } - if (expr->kind == EXPR_STRING_LITERAL - || expr->kind == EXPR_WIDE_STRING_LITERAL) { + if (expr->kind == EXPR_STRING_LITERAL) { source_position_t const *const pos = &expr->base.source_position; warningf(WARN_ADDRESS, pos, "comparison with string literal results in unspecified behaviour"); } @@ -8406,11 +8341,9 @@ static bool expression_has_effect(const expression_t *const expr) case EXPR_LITERAL_MS_NOOP: return true; case EXPR_LITERAL_BOOLEAN: case EXPR_LITERAL_CHARACTER: - case EXPR_LITERAL_WIDE_CHARACTER: case EXPR_LITERAL_INTEGER: case EXPR_LITERAL_FLOATINGPOINT: case EXPR_STRING_LITERAL: return false; - case EXPR_WIDE_STRING_LITERAL: return false; case EXPR_CALL: { const call_expression_t *const call = &expr->call; @@ -8550,8 +8483,8 @@ static expression_t *parse_##binexpression_type(expression_t *left) \ } CREATE_BINEXPR_PARSER('*', EXPR_BINARY_MUL, PREC_CAST, semantic_binexpr_arithmetic) -CREATE_BINEXPR_PARSER('/', EXPR_BINARY_DIV, PREC_CAST, semantic_divmod_arithmetic) -CREATE_BINEXPR_PARSER('%', EXPR_BINARY_MOD, PREC_CAST, semantic_divmod_arithmetic) +CREATE_BINEXPR_PARSER('/', EXPR_BINARY_DIV, PREC_CAST, semantic_div) +CREATE_BINEXPR_PARSER('%', EXPR_BINARY_MOD, PREC_CAST, semantic_mod) CREATE_BINEXPR_PARSER('+', EXPR_BINARY_ADD, PREC_MULTIPLICATIVE, semantic_add) CREATE_BINEXPR_PARSER('-', EXPR_BINARY_SUB, PREC_MULTIPLICATIVE, semantic_sub) CREATE_BINEXPR_PARSER(T_LESSLESS, EXPR_BINARY_SHIFTLEFT, PREC_ADDITIVE, semantic_shift_op) @@ -8628,10 +8561,7 @@ static void register_expression_parser(parse_expression_function parser, { expression_parser_function_t *entry = &expression_parsers[token_kind]; - if (entry->parser != NULL) { - diagnosticf("for token '%k'\n", (token_kind_t)token_kind); - panic("trying to register multiple expression parsers for a token"); - } + assert(!entry->parser); entry->parser = parser; } @@ -8647,11 +8577,7 @@ static void register_infix_parser(parse_expression_infix_function parser, { expression_parser_function_t *entry = &expression_parsers[token_kind]; - if (entry->infix_parser != NULL) { - diagnosticf("for token '%k'\n", (token_kind_t)token_kind); - panic("trying to register multiple infix expression parsers for a " - "token"); - } + assert(!entry->infix_parser); entry->infix_parser = parser; entry->infix_precedence = precedence; } @@ -8710,7 +8636,7 @@ static void init_expression_parsers(void) register_expression_parser(parse_EXPR_UNARY_PREFIX_INCREMENT, T_PLUSPLUS); register_expression_parser(parse_EXPR_UNARY_PREFIX_DECREMENT, T_MINUSMINUS); register_expression_parser(parse_sizeof, T_sizeof); - register_expression_parser(parse_alignof, T___alignof__); + register_expression_parser(parse_alignof, T__Alignof); register_expression_parser(parse_extension, T___extension__); register_expression_parser(parse_builtin_classify_type, T___builtin_classify_type); register_expression_parser(parse_delete, T_delete); @@ -8720,120 +8646,131 @@ static void init_expression_parsers(void) /** * Parse a asm statement arguments specification. */ -static asm_argument_t *parse_asm_arguments(bool is_out) +static void parse_asm_arguments(asm_argument_t **anchor, bool const is_out) { - asm_argument_t *result = NULL; - asm_argument_t **anchor = &result; - - while (token.kind == T_STRING_LITERAL || token.kind == '[') { - asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0])); + if (token.kind == T_STRING_LITERAL || token.kind == '[') { + add_anchor_token(','); + do { + asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0])); - if (next_if('[')) { - add_anchor_token(']'); - argument->symbol = expect_identifier("while parsing asm argument", NULL); - rem_anchor_token(']'); - expect(']'); - if (!argument->symbol) - return NULL; - } + add_anchor_token(')'); + add_anchor_token('('); + add_anchor_token(T_STRING_LITERAL); - argument->constraints = parse_string_literals(); - expect('('); - add_anchor_token(')'); - expression_t *expression = parse_expression(); - rem_anchor_token(')'); - if (is_out) { - /* Ugly GCC stuff: Allow lvalue casts. Skip casts, when they do not - * change size or type representation (e.g. int -> long is ok, but - * int -> float is not) */ - if (expression->kind == EXPR_UNARY_CAST) { - type_t *const type = expression->base.type; - type_kind_t const kind = type->kind; - if (kind == TYPE_ATOMIC || kind == TYPE_POINTER) { - unsigned flags; - unsigned size; - if (kind == TYPE_ATOMIC) { - atomic_type_kind_t const akind = type->atomic.akind; - flags = get_atomic_type_flags(akind) & ~ATOMIC_TYPE_FLAG_SIGNED; - size = get_atomic_type_size(akind); - } else { - flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC; - size = get_type_size(type_void_ptr); - } + if (accept('[')) { + add_anchor_token(']'); + argument->symbol = expect_identifier("while parsing asm argument", NULL); + rem_anchor_token(']'); + expect(']'); + } - do { - expression_t *const value = expression->unary.value; - type_t *const value_type = value->base.type; - type_kind_t const value_kind = value_type->kind; - - unsigned value_flags; - unsigned value_size; - if (value_kind == TYPE_ATOMIC) { - atomic_type_kind_t const value_akind = value_type->atomic.akind; - value_flags = get_atomic_type_flags(value_akind) & ~ATOMIC_TYPE_FLAG_SIGNED; - value_size = get_atomic_type_size(value_akind); - } else if (value_kind == TYPE_POINTER) { - value_flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC; - value_size = get_type_size(type_void_ptr); + rem_anchor_token(T_STRING_LITERAL); + argument->constraints = parse_string_literals("asm argument"); + rem_anchor_token('('); + expect('('); + expression_t *expression = parse_expression(); + if (is_out) { + /* Ugly GCC stuff: Allow lvalue casts. Skip casts, when they do not + * change size or type representation (e.g. int -> long is ok, but + * int -> float is not) */ + if (expression->kind == EXPR_UNARY_CAST) { + type_t *const type = expression->base.type; + type_kind_t const kind = type->kind; + if (kind == TYPE_ATOMIC || kind == TYPE_POINTER) { + unsigned flags; + unsigned size; + if (kind == TYPE_ATOMIC) { + atomic_type_kind_t const akind = type->atomic.akind; + flags = get_atomic_type_flags(akind) & ~ATOMIC_TYPE_FLAG_SIGNED; + size = get_atomic_type_size(akind); } else { - break; + flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC; + size = get_type_size(type_void_ptr); } - if (value_flags != flags || value_size != size) - break; + do { + expression_t *const value = expression->unary.value; + type_t *const value_type = value->base.type; + type_kind_t const value_kind = value_type->kind; + + unsigned value_flags; + unsigned value_size; + if (value_kind == TYPE_ATOMIC) { + atomic_type_kind_t const value_akind = value_type->atomic.akind; + value_flags = get_atomic_type_flags(value_akind) & ~ATOMIC_TYPE_FLAG_SIGNED; + value_size = get_atomic_type_size(value_akind); + } else if (value_kind == TYPE_POINTER) { + value_flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC; + value_size = get_type_size(type_void_ptr); + } else { + break; + } - expression = value; - } while (expression->kind == EXPR_UNARY_CAST); + if (value_flags != flags || value_size != size) + break; + + expression = value; + } while (expression->kind == EXPR_UNARY_CAST); + } } - } - if (!is_lvalue(expression)) { - errorf(&expression->base.source_position, - "asm output argument is not an lvalue"); - } + if (!is_lvalue(expression)) + errorf(&expression->base.source_position, "asm output argument is not an lvalue"); - if (argument->constraints.begin[0] == '=') - determine_lhs_ent(expression, NULL); - else + if (argument->constraints.begin[0] == '=') + determine_lhs_ent(expression, NULL); + else + mark_vars_read(expression, NULL); + } else { mark_vars_read(expression, NULL); - } else { - mark_vars_read(expression, NULL); - } - argument->expression = expression; - expect(')'); + } + argument->expression = expression; + rem_anchor_token(')'); + expect(')'); - set_address_taken(expression, true); + set_address_taken(expression, true); - *anchor = argument; - anchor = &argument->next; - - if (!next_if(',')) - break; + *anchor = argument; + anchor = &argument->next; + } while (accept(',')); + rem_anchor_token(','); } - - return result; } /** * Parse a asm statement clobber specification. */ -static asm_clobber_t *parse_asm_clobbers(void) +static void parse_asm_clobbers(asm_clobber_t **anchor) { - asm_clobber_t *result = NULL; - asm_clobber_t **anchor = &result; + if (token.kind == T_STRING_LITERAL) { + add_anchor_token(','); + do { + asm_clobber_t *clobber = allocate_ast_zero(sizeof(clobber[0])); + clobber->clobber = parse_string_literals(NULL); - while (token.kind == T_STRING_LITERAL) { - asm_clobber_t *clobber = allocate_ast_zero(sizeof(clobber[0])); - clobber->clobber = parse_string_literals(); + *anchor = clobber; + anchor = &clobber->next; + } while (accept(',')); + rem_anchor_token(','); + } +} - *anchor = clobber; - anchor = &clobber->next; +static void parse_asm_labels(asm_label_t **anchor) +{ + if (token.kind == T_IDENTIFIER) { + add_anchor_token(','); + do { + label_t *const label = get_label("while parsing 'asm goto' labels"); + if (label) { + asm_label_t *const asm_label = allocate_ast_zero(sizeof(*asm_label)); + asm_label->label = label; - if (!next_if(',')) - break; + *anchor = asm_label; + anchor = &asm_label->next; + } + } while (accept(',')); + rem_anchor_token(','); } - - return result; } /** @@ -8845,40 +8782,35 @@ static statement_t *parse_asm_statement(void) asm_statement_t *asm_statement = &statement->asms; eat(T_asm); + add_anchor_token(')'); + add_anchor_token(':'); + add_anchor_token(T_STRING_LITERAL); - if (next_if(T_volatile)) + if (accept(T_volatile)) asm_statement->is_volatile = true; + bool const asm_goto = accept(T_goto); + expect('('); - add_anchor_token(')'); - if (token.kind != T_STRING_LITERAL) { - parse_error_expected("after asm(", T_STRING_LITERAL, NULL); - goto end_of_asm; - } - asm_statement->asm_text = parse_string_literals(); + rem_anchor_token(T_STRING_LITERAL); + asm_statement->asm_text = parse_string_literals("asm statement"); - add_anchor_token(':'); - if (!next_if(':')) { - rem_anchor_token(':'); - goto end_of_asm; - } + if (accept(':')) parse_asm_arguments(&asm_statement->outputs, true); + if (accept(':')) parse_asm_arguments(&asm_statement->inputs, false); + if (accept(':')) parse_asm_clobbers( &asm_statement->clobbers); - asm_statement->outputs = parse_asm_arguments(true); - if (!next_if(':')) { - rem_anchor_token(':'); - goto end_of_asm; - } - - asm_statement->inputs = parse_asm_arguments(false); - if (!next_if(':')) { - rem_anchor_token(':'); - goto end_of_asm; - } rem_anchor_token(':'); + if (accept(':')) { + if (!asm_goto) + warningf(WARN_OTHER, &statement->base.source_position, "assembler statement with labels should be 'asm goto'"); + parse_asm_labels(&asm_statement->labels); + if (asm_statement->labels) + errorf(&statement->base.source_position, "'asm goto' not supported"); + } else { + if (asm_goto) + warningf(WARN_OTHER, &statement->base.source_position, "'asm goto' without labels"); + } - asm_statement->clobbers = parse_asm_clobbers(); - -end_of_asm: rem_anchor_token(')'); expect(')'); expect(';'); @@ -8907,7 +8839,7 @@ static statement_t *parse_label_inner_statement(statement_t const *const label, * statement after a label. label:; is commonly used to have a label * before a closing brace. */ inner_stmt = create_empty_statement(); - next_token(); + eat(';'); break; } /* FALLTHROUGH */ @@ -8959,13 +8891,13 @@ static statement_t *parse_case_statement(void) } statement->case_label.is_bad = true; } else { - long const val = fold_constant_to_int(expression); + ir_tarval *val = fold_constant_to_tarval(expression); statement->case_label.first_case = val; statement->case_label.last_case = val; } if (GNU_MODE) { - if (next_if(T_DOTDOTDOT)) { + if (accept(T_DOTDOTDOT)) { expression_t *end_range = parse_expression(); expression_type = expression->base.type; skipped = skip_typeref(expression_type); @@ -8983,10 +8915,11 @@ static statement_t *parse_case_statement(void) } statement->case_label.is_bad = true; } else { - long const val = fold_constant_to_int(end_range); + ir_tarval *val = fold_constant_to_tarval(end_range); statement->case_label.last_case = val; - if (val < statement->case_label.first_case) { + if (tarval_cmp(val, statement->case_label.first_case) + == ir_relation_less) { statement->case_label.is_empty_range = true; warningf(WARN_OTHER, pos, "empty range specified"); } @@ -9077,7 +9010,7 @@ static statement_t *parse_default_statement(void) static statement_t *parse_label_statement(void) { statement_t *const statement = allocate_statement_zero(STATEMENT_LABEL); - label_t *const label = get_label(); + label_t *const label = get_label(NULL /* Cannot fail, token is T_IDENTIFIER. */); statement->label.label = label; PUSH_PARENT(statement); @@ -9091,6 +9024,7 @@ static statement_t *parse_label_statement(void) } else { label->base.source_position = *pos; label->statement = statement; + label->n_users += 1; } eat(':'); @@ -9125,8 +9059,8 @@ static statement_t *parse_inner_statement(void) */ static expression_t *parse_condition(void) { - expect('('); add_anchor_token(')'); + expect('('); expression_t *const expr = parse_expression(); mark_vars_read(expr, NULL); rem_anchor_token(')'); @@ -9163,7 +9097,7 @@ static statement_t *parse_if(void) "suggest braces around empty body in an ‘if’ statement"); } - if (next_if(T_else)) { + if (accept(T_else)) { statement->ifs.false_statement = parse_inner_statement(); if (statement->ifs.false_statement->kind == STATEMENT_EMPTY) { @@ -9190,28 +9124,32 @@ static void check_enum_cases(const switch_statement_t *statement) { if (!is_warn_on(WARN_SWITCH_ENUM)) return; - const type_t *type = skip_typeref(statement->expression->base.type); + type_t *type = skip_typeref(statement->expression->base.type); if (! is_type_enum(type)) return; - const enum_type_t *enumt = &type->enumt; + enum_type_t *enumt = &type->enumt; /* if we have a default, no warnings */ if (statement->default_label != NULL) return; + determine_enum_values(enumt); + /* FIXME: calculation of value should be done while parsing */ /* TODO: quadratic algorithm here. Change to an n log n one */ - long last_value = -1; - const entity_t *entry = enumt->enume->base.next; + const entity_t *entry = enumt->enume->base.next; for (; entry != NULL && entry->kind == ENTITY_ENUM_VALUE; entry = entry->base.next) { - const expression_t *expression = entry->enum_value.value; - long value = expression != NULL ? fold_constant_to_int(expression) : last_value + 1; - bool found = false; - for (const case_label_statement_t *l = statement->first_case; l != NULL; l = l->next) { + ir_tarval *value = entry->enum_value.tv; + bool found = false; + for (const case_label_statement_t *l = statement->first_case; l != NULL; + l = l->next) { if (l->expression == NULL) continue; - if (l->first_case <= value && value <= l->last_case) { + if (l->first_case == l->last_case && l->first_case != value) + continue; + if ((tarval_cmp(l->first_case, value) & ir_relation_less_equal) + && (tarval_cmp(value, l->last_case) & ir_relation_less_equal)) { found = true; break; } @@ -9220,7 +9158,6 @@ static void check_enum_cases(const switch_statement_t *statement) source_position_t const *const pos = &statement->base.source_position; warningf(WARN_SWITCH_ENUM, pos, "'%N' not handled in switch", entry); } - last_value = value; } } @@ -9281,20 +9218,20 @@ static statement_t *parse_loop_body(statement_t *const loop) */ static statement_t *parse_while(void) { - statement_t *statement = allocate_statement_zero(STATEMENT_WHILE); + statement_t *statement = allocate_statement_zero(STATEMENT_FOR); eat(T_while); PUSH_PARENT(statement); - PUSH_SCOPE_STATEMENT(&statement->whiles.scope); + PUSH_SCOPE_STATEMENT(&statement->fors.scope); expression_t *const cond = parse_condition(); - statement->whiles.condition = cond; + statement->fors.condition = cond; /* §6.8.5:2 The controlling expression of an iteration statement shall * have scalar type. */ semantic_condition(cond, "condition of 'while'-statement"); - statement->whiles.body = parse_loop_body(statement); + statement->fors.body = parse_loop_body(statement); POP_SCOPE(); POP_PARENT(); @@ -9342,12 +9279,12 @@ static statement_t *parse_for(void) PUSH_PARENT(statement); PUSH_SCOPE_STATEMENT(&statement->fors.scope); - expect('('); add_anchor_token(')'); + expect('('); PUSH_EXTENSION(); - if (next_if(';')) { + if (accept(';')) { } else if (is_declaration_specifier(&token)) { parse_declaration(record_entity, DECL_FLAGS_NONE); } else { @@ -9424,8 +9361,10 @@ static statement_t *parse_goto(void) } else { statement = allocate_statement_zero(STATEMENT_GOTO); eat(T_goto); - if (token.kind == T_IDENTIFIER) { - label_t *const label = get_label(); + + label_t *const label = get_label("while parsing goto"); + if (label) { + label->n_users += 1; label->used = true; statement->gotos.label = label; @@ -9433,11 +9372,6 @@ static statement_t *parse_goto(void) *goto_anchor = &statement->gotos; goto_anchor = &statement->gotos.next; } else { - if (GNU_MODE) - parse_error_expected("while parsing goto", T_IDENTIFIER, '*', NULL); - else - parse_error_expected("while parsing goto", T_IDENTIFIER, NULL); - eat_until_anchor(); statement->gotos.label = &allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, sym_anonymous, &builtin_source_position)->label; } } @@ -9529,22 +9463,6 @@ static bool expression_is_local_variable(const expression_t *expression) return is_local_variable(entity); } -/** - * Check if a given expression represents a local variable and - * return its declaration then, else return NULL. - */ -entity_t *expression_is_variable(const expression_t *expression) -{ - if (expression->base.kind != EXPR_REFERENCE) { - return NULL; - } - entity_t *entity = expression->reference.entity; - if (entity->kind != ENTITY_VARIABLE) - return NULL; - - return entity; -} - static void err_or_warn(source_position_t const *const pos, char const *const msg) { if (c_mode & _CXX || strict_mode) { @@ -9664,7 +9582,7 @@ static statement_t *parse_ms_try_statment(void) POP_PARENT(); - if (next_if(T___except)) { + if (accept(T___except)) { expression_t *const expr = parse_condition(); type_t * type = skip_typeref(expr->base.type); if (is_type_integer(type)) { @@ -9675,7 +9593,7 @@ static statement_t *parse_ms_try_statment(void) type = type_error_type; } statement->ms_try.except_expression = create_implicit_cast(expr, type); - } else if (!next_if(T__finally)) { + } else if (!accept(T__finally)) { parse_error_expected("while parsing __try statement", T___except, T___finally, NULL); } statement->ms_try.final_statement = parse_compound_statement(false); @@ -9699,29 +9617,31 @@ static statement_t *parse_local_label_declaration(void) entity_t *begin = NULL; entity_t *end = NULL; entity_t **anchor = &begin; + add_anchor_token(';'); + add_anchor_token(','); do { source_position_t pos; symbol_t *const symbol = expect_identifier("while parsing local label declaration", &pos); - if (!symbol) - goto end_error; - - entity_t *entity = get_entity(symbol, NAMESPACE_LABEL); - if (entity != NULL && entity->base.parent_scope == current_scope) { - source_position_t const *const ppos = &entity->base.source_position; - errorf(&pos, "multiple definitions of '%N' (previous definition %P)", entity, ppos); - } else { - entity = allocate_entity_zero(ENTITY_LOCAL_LABEL, NAMESPACE_LABEL, symbol, &pos); - entity->base.parent_scope = current_scope; + if (symbol) { + entity_t *entity = get_entity(symbol, NAMESPACE_LABEL); + if (entity != NULL && entity->base.parent_scope == current_scope) { + source_position_t const *const ppos = &entity->base.source_position; + errorf(&pos, "multiple definitions of '%N' (previous definition %P)", entity, ppos); + } else { + entity = allocate_entity_zero(ENTITY_LOCAL_LABEL, NAMESPACE_LABEL, symbol, &pos); + entity->base.parent_scope = current_scope; - *anchor = entity; - anchor = &entity->base.next; - end = entity; + *anchor = entity; + anchor = &entity->base.next; + end = entity; - environment_push(entity); + environment_push(entity); + } } - } while (next_if(',')); + } while (accept(',')); + rem_anchor_token(','); + rem_anchor_token(';'); expect(';'); -end_error: statement->declaration.declarations_begin = begin; statement->declaration.declarations_end = end; return statement; @@ -9735,19 +9655,15 @@ static void parse_namespace_definition(void) symbol_t *symbol = NULL; if (token.kind == T_IDENTIFIER) { - symbol = token.identifier.symbol; - next_token(); - + symbol = token.base.symbol; entity = get_entity(symbol, NAMESPACE_NORMAL); - if (entity != NULL - && entity->kind != ENTITY_NAMESPACE - && entity->base.parent_scope == current_scope) { - if (is_entity_valid(entity)) { - error_redefined_as_different_kind(&token.base.source_position, - entity, ENTITY_NAMESPACE); - } + if (entity && entity->kind != ENTITY_NAMESPACE) { entity = NULL; + if (entity->base.parent_scope == current_scope && is_entity_valid(entity)) { + error_redefined_as_different_kind(HERE, entity, ENTITY_NAMESPACE); + } } + eat(T_IDENTIFIER); } if (entity == NULL) { @@ -9790,7 +9706,7 @@ static statement_t *intern_parse_statement(void) token_kind_t la1_type = (token_kind_t)look_ahead(1)->kind; if (la1_type == ':') { statement = parse_label_statement(); - } else if (is_typedef_symbol(token.identifier.symbol)) { + } else if (is_typedef_symbol(token.base.symbol)) { statement = parse_declaration_statement(); } else { /* it's an identifier, the grammar says this must be an @@ -9800,7 +9716,7 @@ static statement_t *intern_parse_statement(void) switch (la1_type) { case '&': case '*': - if (get_entity(token.identifier.symbol, NAMESPACE_NORMAL) != NULL) { + if (get_entity(token.base.symbol, NAMESPACE_NORMAL) != NULL) { default: statement = parse_expression_statement(); } else { @@ -9907,20 +9823,17 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) add_anchor_token('~'); add_anchor_token(T_CHARACTER_CONSTANT); add_anchor_token(T_COLONCOLON); - add_anchor_token(T_FLOATINGPOINT); add_anchor_token(T_IDENTIFIER); - add_anchor_token(T_INTEGER); add_anchor_token(T_MINUSMINUS); + add_anchor_token(T_NUMBER); add_anchor_token(T_PLUSPLUS); add_anchor_token(T_STRING_LITERAL); - add_anchor_token(T_WIDE_CHARACTER_CONSTANT); - add_anchor_token(T_WIDE_STRING_LITERAL); + add_anchor_token(T__Alignof); add_anchor_token(T__Bool); add_anchor_token(T__Complex); add_anchor_token(T__Imaginary); - add_anchor_token(T___FUNCTION__); + add_anchor_token(T__Thread_local); add_anchor_token(T___PRETTY_FUNCTION__); - add_anchor_token(T___alignof__); add_anchor_token(T___attribute__); add_anchor_token(T___builtin_va_start); add_anchor_token(T___extension__); @@ -9928,7 +9841,6 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) add_anchor_token(T___imag__); add_anchor_token(T___label__); add_anchor_token(T___real__); - add_anchor_token(T___thread); add_anchor_token(T_asm); add_anchor_token(T_auto); add_anchor_token(T_bool); @@ -10076,7 +9988,6 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) rem_anchor_token(T_bool); rem_anchor_token(T_auto); rem_anchor_token(T_asm); - rem_anchor_token(T___thread); rem_anchor_token(T___real__); rem_anchor_token(T___label__); rem_anchor_token(T___imag__); @@ -10084,20 +9995,17 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) rem_anchor_token(T___extension__); rem_anchor_token(T___builtin_va_start); rem_anchor_token(T___attribute__); - rem_anchor_token(T___alignof__); rem_anchor_token(T___PRETTY_FUNCTION__); - rem_anchor_token(T___FUNCTION__); + rem_anchor_token(T__Thread_local); rem_anchor_token(T__Imaginary); rem_anchor_token(T__Complex); rem_anchor_token(T__Bool); - rem_anchor_token(T_WIDE_STRING_LITERAL); - rem_anchor_token(T_WIDE_CHARACTER_CONSTANT); + rem_anchor_token(T__Alignof); rem_anchor_token(T_STRING_LITERAL); rem_anchor_token(T_PLUSPLUS); + rem_anchor_token(T_NUMBER); rem_anchor_token(T_MINUSMINUS); - rem_anchor_token(T_INTEGER); rem_anchor_token(T_IDENTIFIER); - rem_anchor_token(T_FLOATINGPOINT); rem_anchor_token(T_COLONCOLON); rem_anchor_token(T_CHARACTER_CONSTANT); rem_anchor_token('~'); @@ -10144,7 +10052,7 @@ static void check_unused_globals(void) continue; why = WARN_UNUSED_FUNCTION; - s = entity->function.statement != NULL ? "defined" : "declared"; + s = entity->function.body != NULL ? "defined" : "declared"; } else { why = WARN_UNUSED_VARIABLE; s = "defined"; @@ -10165,7 +10073,7 @@ static void parse_global_asm(void) expect('('); rem_anchor_token(T_STRING_LITERAL); - statement->asms.asm_text = parse_string_literals(); + statement->asms.asm_text = parse_string_literals("global asm"); statement->base.next = unit->global_asm; unit->global_asm = statement; @@ -10180,7 +10088,7 @@ static void parse_linkage_specification(void) eat(T_extern); source_position_t const pos = *HERE; - char const *const linkage = parse_string_literals().begin; + char const *const linkage = parse_string_literals(NULL).begin; linkage_kind_t old_linkage = current_linkage; linkage_kind_t new_linkage; @@ -10194,7 +10102,7 @@ static void parse_linkage_specification(void) } current_linkage = new_linkage; - if (next_if('{')) { + if (accept('{')) { parse_externals(); expect('}'); } else { @@ -10237,7 +10145,7 @@ static void parse_external(void) case ';': if (!strict_mode) { warningf(WARN_STRAY_SEMICOLON, HERE, "stray ';' outside of function"); - next_token(); + eat(';'); return; } /* FALLTHROUGH */ @@ -10318,9 +10226,6 @@ void start_parsing(void) { environment_stack = NEW_ARR_F(stack_entry_t, 0); label_stack = NEW_ARR_F(stack_entry_t, 0); - diagnostic_count = 0; - error_count = 0; - warning_count = 0; print_to_file(stderr); @@ -10383,7 +10288,7 @@ static void complete_incomplete_arrays(void) static void prepare_main_collect2(entity_t *const entity) { - PUSH_SCOPE(&entity->function.statement->compound.scope); + PUSH_SCOPE(&entity->function.body->compound.scope); // create call to __main symbol_t *symbol = symbol_table_insert("__main"); @@ -10405,9 +10310,9 @@ static void prepare_main_collect2(entity_t *const entity) expr_statement->base.source_position = builtin_source_position; expr_statement->expression.expression = call; - statement_t *statement = entity->function.statement; - assert(statement->kind == STATEMENT_COMPOUND); - compound_statement_t *compounds = &statement->compound; + statement_t *const body = entity->function.body; + assert(body->kind == STATEMENT_COMPOUND); + compound_statement_t *compounds = &body->compound; expr_statement->base.next = compounds->statements; compounds->statements = expr_statement; @@ -10434,8 +10339,6 @@ void parse(void) */ void init_parser(void) { - sym_anonymous = symbol_table_insert(""); - memset(token_anchor_set, 0, sizeof(token_anchor_set)); init_expression_parsers();