#include <config.h>
#include <assert.h>
+#include <ctype.h>
#include <stdarg.h>
#include <stdbool.h>
#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"
#include "walk.h"
#include "warning.h"
#include "printer.h"
+#include "ast2firm.h"
#include "adt/bitfiddle.h"
#include "adt/error.h"
#include "adt/array.h"
typedef struct declaration_specifiers_t declaration_specifiers_t;
struct declaration_specifiers_t {
- source_position_t source_position;
- storage_class_t storage_class;
- unsigned char alignment; /**< Alignment, 0 if not set. */
- bool is_inline : 1;
- bool thread_local : 1; /**< GCC __thread */
- attribute_t *attributes; /**< list of attributes */
- type_t *type;
+ position_t pos;
+ storage_class_t storage_class;
+ unsigned char alignment; /**< Alignment, 0 if not set. */
+ bool is_inline : 1;
+ bool thread_local : 1;
+ attribute_t *attributes; /**< list of attributes */
+ type_t *type;
};
/**
#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];
/** The current source position. */
-#define HERE (&token.base.source_position)
+#define HERE (&token.base.pos)
/** true if we are in GCC mode. */
#define GNU_MODE ((c_mode & _GNUC) || in_gcc_extension)
case T_static: \
case T_auto: \
case T_register: \
- case T___thread:
+ case T__Thread_local:
#define TYPE_QUALIFIERS \
case T_const: \
case '~': \
case T_ANDAND: \
case T_CHARACTER_CONSTANT: \
- case T_FLOATINGPOINT: \
- case T_INTEGER: \
+ case T_NUMBER: \
case T_MINUSMINUS: \
case T_PLUSPLUS: \
case T_STRING_LITERAL: \
+ case T__Alignof: \
case T___FUNCDNAME__: \
case T___FUNCSIG__: \
case T___PRETTY_FUNCTION__: \
- case T___alignof__: \
case T___builtin_classify_type: \
case T___builtin_constant_p: \
case T___builtin_isgreater: \
[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),
[EXPR_LITERAL_INTEGER] = sizeof(literal_expression_t),
[EXPR_LITERAL_FLOATINGPOINT] = 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_COMPOUND_LITERAL] = sizeof(compound_literal_expression_t),
[EXPR_CALL] = sizeof(call_expression_t),
size_t size = get_statement_struct_size(kind);
statement_t *res = allocate_ast_zero(size);
- res->base.kind = kind;
- res->base.parent = current_parent;
- res->base.source_position = *HERE;
+ res->base.kind = kind;
+ res->base.parent = current_parent;
+ res->base.pos = *HERE;
return res;
}
size_t size = get_expression_struct_size(kind);
expression_t *res = allocate_ast_zero(size);
- res->base.kind = kind;
- res->base.type = type_error_type;
- res->base.source_position = *HERE;
+ res->base.kind = kind;
+ res->base.type = type_error_type;
+ res->base.pos = *HERE;
return res;
}
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;
#endif
}
-#define eat(token_kind) (assert(token.kind == (token_kind)), next_token())
+static inline void eat(token_kind_t const kind)
+{
+ assert(token.kind == kind);
+ (void)kind;
+ next_token();
+}
-static inline bool next_if(token_kind_t const type)
+/**
+ * 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 == type) {
- eat(type);
+ if (token.kind == kind) {
+ eat(kind);
return true;
} else {
return false;
static void eat_block(void)
{
eat_until_matching_token('{');
- next_if('}');
+ accept('}');
}
/**
* Report an incompatible type.
*/
static void type_error_incompatible(const char *msg,
- const source_position_t *source_position, type_t *type1, type_t *type2)
+ const position_t *pos, type_t *type1, type_t *type2)
{
- errorf(source_position, "%s, incompatible types: '%T' - '%T'",
- msg, type1, type2);
+ errorf(pos, "%s, incompatible types: '%T' - '%T'", msg, type1, type2);
}
static bool skip_till(token_kind_t const expected, char const *const context)
eat(expected);
}
-static symbol_t *expect_identifier(char const *const context, source_position_t *const pos)
+static symbol_t *expect_identifier(char const *const context,
+ position_t *const pos)
{
if (!skip_till(T_IDENTIFIER, context))
return NULL;
if (entity != NULL && (entity_kind_tag_t)entity->kind != kind) {
errorf(HERE,
"'%Y' defined as wrong kind of tag (previous definition %P)",
- symbol, &entity->base.source_position);
+ symbol, &entity->base.pos);
entity = NULL;
}
return entity;
*/
static void environment_push(entity_t *entity)
{
- assert(entity->base.source_position.input_name != NULL);
+ assert(entity->base.pos.input_name != NULL);
assert(entity->base.parent_scope != NULL);
stack_push(&environment_stack, entity);
}
ASSIGN_WARNING_INT_FROM_POINTER
} assign_error_t;
-static void report_assign_error(assign_error_t error, type_t *orig_type_left, expression_t const *const right, char const *const context, source_position_t const *const pos)
+static void report_assign_error(assign_error_t error, type_t *orig_type_left, expression_t const *const right, char const *const context, position_t const *const pos)
{
type_t *const orig_type_right = right->base.type;
type_t *const type_left = skip_typeref(orig_type_left);
expression_t *result = parse_subexpression(PREC_CONDITIONAL);
if (is_constant_expression(result) == EXPR_CLASS_VARIABLE) {
- errorf(&result->base.source_position,
- "expression '%E' is not constant", result);
+ errorf(&result->base.pos, "expression '%E' is not constant", result);
}
return result;
string_t result;
if (look_ahead(1)->kind == T_STRING_LITERAL) {
- append_string(&token.string.string);
+ append_string(&token.literal.string);
eat(T_STRING_LITERAL);
warningf(WARN_TRADITIONAL, HERE, "traditional C rejects string constant concatenation");
- string_encoding_t enc = token.string.string.encoding;
+ string_encoding_t enc = token.literal.string.encoding;
do {
- if (token.string.string.encoding != STRING_ENCODING_CHAR) {
- enc = token.string.string.encoding;
+ 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.string.string);
+ append_string(&token.literal.string);
eat(T_STRING_LITERAL);
} while (token.kind == T_STRING_LITERAL);
result = finish_string(enc);
} else {
- result = token.string.string;
+ result = token.literal.string;
eat(T_STRING_LITERAL);
}
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();
+ 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 wide string literal");
+ 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));
- attribute->kind = kind;
- attribute->source_position = *HERE;
+ attribute->kind = kind;
+ attribute->pos = *HERE;
return attribute;
}
/* append argument */
*anchor = argument;
anchor = &argument->next;
- } while (next_if(','));
+ } while (accept(','));
expect(')');
return first;
}
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;
next_token();
/* parse arguments */
- if (next_if('('))
+ if (accept('('))
attribute->a.arguments = parse_attribute_arguments();
return attribute;
*anchor = attribute;
anchor = &attribute->next;
}
- } while (next_if(','));
+ } while (accept(','));
rem_anchor_token(',');
rem_anchor_token(')');
designator_t *designator;
switch (token.kind) {
case '[':
- designator = allocate_ast_zero(sizeof(designator[0]));
- designator->source_position = *HERE;
+ designator = allocate_ast_zero(sizeof(designator[0]));
+ designator->pos = *HERE;
eat('[');
add_anchor_token(']');
designator->array_index = parse_constant_expression();
expect(']');
break;
case '.':
- designator = allocate_ast_zero(sizeof(designator[0]));
- designator->source_position = *HERE;
+ designator = allocate_ast_zero(sizeof(designator[0]));
+ designator->pos = *HERE;
eat('.');
designator->symbol = expect_identifier("while parsing designator", NULL);
if (!designator->symbol)
array_type_t *const array_type = &type->array;
type_t *const element_type = skip_typeref(array_type->element_type);
switch (expression->string_literal.value.encoding) {
- case STRING_ENCODING_CHAR: {
+ 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)) {
break;
}
+ case STRING_ENCODING_CHAR16:
+ case STRING_ENCODING_CHAR32:
case STRING_ENCODING_WIDE: {
- type_t *bare_wchar_type = skip_typeref(type_wchar_t);
- if (get_unqualified_type(element_type) == bare_wchar_type) {
+ 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;
if (error == ASSIGN_ERROR_INCOMPATIBLE)
return NULL;
report_assign_error(error, type, expression, "initializer",
- &expression->base.source_position);
+ &expression->base.pos);
initializer_t *const result = allocate_initializer_zero(INITIALIZER_VALUE);
result->value.value = create_implicit_cast(expression, type);
expression_t *expression = parse_assignment_expression();
mark_vars_read(expression, NULL);
if (must_be_constant && !is_linker_constant(expression)) {
- errorf(&expression->base.source_position,
+ errorf(&expression->base.pos,
"initialisation expression '%E' is not constant",
expression);
}
initializer_t *initializer = initializer_from_expression(type, expression);
if (initializer == NULL) {
- errorf(&expression->base.source_position,
+ errorf(&expression->base.pos,
"expression '%E' (type '%T') doesn't match expected type '%T'",
expression, expression->base.type, type);
/* TODO */
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");
symbol_t *symbol = designator->symbol;
if (!is_type_compound(type)) {
if (is_type_valid(type)) {
- errorf(&designator->source_position,
+ errorf(&designator->pos,
"'.%Y' designator used for non-compound type '%T'",
symbol, orig_type);
}
}
}
if (iter == NULL) {
- errorf(&designator->source_position,
+ errorf(&designator->pos,
"'%T' has no member named '%Y'", orig_type, symbol);
return false;
}
assert(iter->kind == ENTITY_COMPOUND_MEMBER);
if (used_in_offsetof && iter->compound_member.bitfield) {
- errorf(&designator->source_position,
+ errorf(&designator->pos,
"offsetof designator '%Y' must not specify bitfield",
symbol);
return false;
if (!is_type_array(type)) {
if (is_type_valid(type)) {
- errorf(&designator->source_position,
+ errorf(&designator->pos,
"[%E] designator used for non-array type '%T'",
array_index, orig_type);
}
long index = fold_constant_to_int(array_index);
if (!used_in_offsetof) {
if (index < 0) {
- errorf(&designator->source_position,
+ errorf(&designator->pos,
"array index [%E] must be positive", array_index);
} else if (type->array.size_constant) {
long array_size = type->array.size;
if (index >= array_size) {
- errorf(&designator->source_position,
+ errorf(&designator->pos,
"designator [%E] (%d) exceeds array size %d",
array_index, index, array_size);
}
*/
static void skip_initializers(void)
{
- next_if('{');
+ accept('{');
while (token.kind != '}') {
if (token.kind == T_EOF)
return create_empty_initializer();
}
+ initializer_t *result = NULL;
+
type_t *orig_type = path->top_type;
type_t *type = NULL;
goto finish_designator;
} 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 = *HERE;
- designator->symbol = token.base.symbol;
+ designator = allocate_ast_zero(sizeof(designator[0]));
+ designator->pos = *HERE;
+ designator->symbol = token.base.symbol;
eat(T_IDENTIFIER);
eat(':');
mark_vars_read(expression, NULL);
if (env->must_be_constant && !is_linker_constant(expression)) {
- errorf(&expression->base.source_position,
+ errorf(&expression->base.pos,
"Initialisation expression '%E' is not constant",
expression);
}
goto error_parse_next;
}
- source_position_t const* const pos = &expression->base.source_position;
+ position_t const* const pos = &expression->base.pos;
if (env->entity != NULL) {
warningf(WARN_OTHER, pos, "excess elements in initializer for '%N'", env->entity);
} else {
/* handle { "string" } special case */
if (expression->kind == EXPR_STRING_LITERAL && outer_type != NULL) {
- sub = initializer_from_expression(outer_type, expression);
- if (sub != NULL) {
- next_if(',');
+ 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;
}
}
goto end_error;
}
if (is_type_scalar(type)) {
- errorf(&expression->base.source_position,
+ errorf(&expression->base.pos,
"expression '%E' doesn't match expected type '%T'",
expression, orig_type);
goto end_error;
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;
}
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)
static compound_t *parse_compound_type_specifier(bool is_struct)
{
- source_position_t const pos = *HERE;
+ position_t const pos = *HERE;
eat(is_struct ? T_struct : T_union);
symbol_t *symbol = NULL;
* existing definition in outer scope */
entity = NULL;
} else if (entity->compound.complete && token.kind == '{') {
- source_position_t const *const ppos = &entity->base.source_position;
+ position_t const *const ppos = &entity->base.pos;
errorf(&pos, "multiple definitions of '%N' (previous definition %P)", entity, ppos);
/* clear members in the hope to avoid further errors */
entity->compound.members.entities = NULL;
}
if (attributes != NULL) {
+ entity->compound.attributes = attributes;
handle_entity_attributes(attributes, entity);
}
add_anchor_token(',');
do {
add_anchor_token('=');
- source_position_t pos;
+ position_t pos;
symbol_t *const symbol = expect_identifier("while parsing enum entry", &pos);
entity_t *const entity = allocate_entity_zero(ENTITY_ENUM_VALUE, NAMESPACE_NORMAL, symbol, &pos);
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);
}
record_entity(entity, false);
- } while (next_if(',') && token.kind != '}');
+ } while (accept(',') && token.kind != '}');
rem_anchor_token(',');
rem_anchor_token('}');
static type_t *parse_enum_specifier(void)
{
- source_position_t const pos = *HERE;
- entity_t *entity;
- symbol_t *symbol;
+ position_t const pos = *HERE;
+ entity_t *entity;
+ symbol_t *symbol;
eat(T_enum);
switch (token.kind) {
* existing definition in outer scope */
entity = NULL;
} else if (entity->enume.complete && token.kind == '{') {
- source_position_t const *const ppos = &entity->base.source_position;
+ position_t const *const ppos = &entity->base.pos;
errorf(&pos, "multiple definitions of '%N' (previous definition %P)", entity, ppos);
}
}
}
typedef enum specifiers_t {
+ SPECIFIER_NONE = 0,
SPECIFIER_SIGNED = 1 << 0,
SPECIFIER_UNSIGNED = 1 << 1,
SPECIFIER_LONG = 1 << 2,
do {
add_anchor_token('=');
- source_position_t pos;
+ position_t pos;
symbol_t *const prop_sym = expect_identifier("while parsing property declspec", &pos);
rem_anchor_token('=');
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(')');
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) {
char const *const name = token.base.symbol->string;
}
/* parse arguments */
- if (next_if('('))
+ if (accept('('))
attribute->a.arguments = parse_attribute_arguments();
return attribute;
*anchor = attribute;
anchor = &attribute->next;
- } while (next_if(','));
+ } while (accept(','));
}
rem_anchor_token(')');
expect(')');
bool saw_error = false;
memset(specifiers, 0, sizeof(*specifiers));
- specifiers->source_position = *HERE;
+ specifiers->pos = *HERE;
while (true) {
specifiers->attributes = parse_attributes(specifiers->attributes);
= 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:
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;
}
}
| SPECIFIER_INT:
atomic_type = ATOMIC_TYPE_ULONGLONG;
warn_about_long_long:
- warningf(WARN_LONG_LONG, &specifiers->source_position, "ISO C90 does not support 'long long'");
+ warningf(WARN_LONG_LONG, &specifiers->pos, "ISO C90 does not support 'long long'");
break;
case SPECIFIER_UNSIGNED | SPECIFIER_INT8:
break;
default: {
/* invalid specifier combination, give an error message */
- source_position_t const* const pos = &specifiers->source_position;
+ position_t const* const pos = &specifiers->pos;
if (type_specifiers == 0) {
if (!saw_error) {
/* ISO/IEC 14882:1998(E) ยงC.1.5:4 */
type->atomic.akind = atomic_type;
newtype = true;
} else if (type_specifiers != 0) {
- errorf(&specifiers->source_position, "multiple datatypes in declaration");
+ errorf(&specifiers->pos, "multiple datatypes in declaration");
}
/* FIXME: check type qualifiers here */
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)
* incomplete type. */
type_t *type = skip_typeref(entity->declaration.type);
if (is_type_incomplete(type)) {
- errorf(&entity->base.source_position, "'%N' has incomplete type", entity);
+ errorf(&entity->base.pos, "'%N' has incomplete type", entity);
}
}
{
entity_t *entity = parse_parameter();
if (entity->kind == ENTITY_TYPEDEF) {
- errorf(&entity->base.source_position,
+ errorf(&entity->base.pos,
"typedef not allowed as function parameter");
break;
}
default:
goto parameters_finished;
}
- } while (next_if(','));
+ } while (accept(','));
parameters_finished:
rem_anchor_token(',');
}
typedef union construct_type_t construct_type_t;
typedef struct construct_type_base_t {
- construct_type_kind_t kind;
- source_position_t pos;
- construct_type_t *next;
+ construct_type_kind_t kind;
+ position_t pos;
+ construct_type_t *next;
} construct_type_base_t;
typedef struct parsed_pointer_t {
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;
type_t *const orig_type = size->base.type;
type_t *const type = skip_typeref(orig_type);
if (!is_type_integer(type) && is_type_valid(type)) {
- errorf(&size->base.source_position,
+ errorf(&size->base.pos,
"array size '%E' must have integer type but has type '%T'",
size, orig_type);
}
}
typedef struct parse_declarator_env_t {
- bool may_be_abstract : 1;
- bool must_be_abstract : 1;
- decl_modifiers_t modifiers;
- symbol_t *symbol;
- source_position_t source_position;
- scope_t parameters;
- attribute_t *attributes;
+ bool may_be_abstract : 1;
+ bool must_be_abstract : 1;
+ decl_modifiers_t modifiers;
+ symbol_t *symbol;
+ position_t pos;
+ scope_t parameters;
+ attribute_t *attributes;
} parse_declarator_env_t;
/* ยง6.7.5 */
if (env->must_be_abstract) {
errorf(HERE, "no identifier expected in typename");
} else {
- env->symbol = token.base.symbol;
- env->source_position = *HERE;
+ env->symbol = token.base.symbol;
+ env->pos = *HERE;
}
eat(T_IDENTIFIER);
break;
{
construct_type_t *iter = construct_list;
for (; iter != NULL; iter = iter->base.next) {
- source_position_t const* const pos = &iter->base.pos;
+ position_t const* const pos = &iter->base.pos;
switch (iter->kind) {
case CONSTRUCT_FUNCTION: {
construct_function_type_t *function = &iter->function;
/* ยง6.7.5.2:1 If the expression is a constant expression,
* it shall have a value greater than zero. */
if (size < 0) {
- errorf(&size_expression->base.source_position,
+ errorf(&size_expression->base.pos,
"size of array must be greater than zero");
} else if (size == 0 && !GNU_MODE) {
- errorf(&size_expression->base.source_position,
+ errorf(&size_expression->base.pos,
"size of array must be greater than zero (zero length arrays are a GCC extension)");
}
break;
static type_t *automatic_type_conversion(type_t *orig_type);
-static type_t *semantic_parameter(const source_position_t *pos,
- type_t *type,
+static type_t *semantic_parameter(const position_t *pos, type_t *type,
const declaration_specifiers_t *specifiers,
entity_t const *const param)
{
entity_t *entity;
if (specifiers->storage_class == STORAGE_CLASS_TYPEDEF) {
- entity = allocate_entity_zero(ENTITY_TYPEDEF, NAMESPACE_NORMAL, env.symbol, &env.source_position);
+ entity = allocate_entity_zero(ENTITY_TYPEDEF, NAMESPACE_NORMAL, env.symbol, &env.pos);
entity->typedefe.type = orig_type;
if (anonymous_entity != NULL) {
}
} else {
/* create a declaration type entity */
- source_position_t const *const pos = env.symbol ? &env.source_position : &specifiers->source_position;
+ position_t const *const pos = env.symbol ? &env.pos : &specifiers->pos;
if (flags & DECL_CREATE_COMPOUND_MEMBER) {
entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER, NAMESPACE_NORMAL, env.symbol, pos);
if (env.symbol != NULL) {
if (specifiers->is_inline && is_type_valid(type)) {
- errorf(&env.source_position, "'%N' declared 'inline'", entity);
+ errorf(&env.pos, "'%N' declared 'inline'", entity);
}
if (specifiers->thread_local ||
specifiers->storage_class != STORAGE_CLASS_NONE) {
- errorf(&env.source_position, "'%N' must have no storage class", entity);
+ errorf(&env.pos, "'%N' must have no storage class", entity);
}
}
} else if (flags & DECL_IS_PARAMETER) {
entity = allocate_entity_zero(ENTITY_PARAMETER, NAMESPACE_NORMAL, env.symbol, pos);
- orig_type = semantic_parameter(&env.source_position, orig_type, specifiers, entity);
+ orig_type = semantic_parameter(&env.pos, orig_type, specifiers, entity);
} else if (is_type_function(type)) {
entity = allocate_entity_zero(ENTITY_FUNCTION, NAMESPACE_NORMAL, env.symbol, pos);
entity->function.is_inline = specifiers->is_inline;
specifiers->storage_class != STORAGE_CLASS_NONE &&
(in_function_scope || specifiers->storage_class != STORAGE_CLASS_STATIC)
)) {
- errorf(&env.source_position, "invalid storage class for '%N'", entity);
+ errorf(&env.pos, "invalid storage class for '%N'", entity);
}
}
} else {
if (env.symbol != NULL) {
if (specifiers->is_inline && is_type_valid(type)) {
- errorf(&env.source_position, "'%N' declared 'inline'", entity);
+ errorf(&env.pos, "'%N' declared 'inline'", entity);
}
bool invalid_storage_class = false;
}
}
if (invalid_storage_class) {
- errorf(&env.source_position, "invalid storage class for '%N'", entity);
+ errorf(&env.pos, "invalid storage class for '%N'", entity);
}
}
}
*/
static void check_main(const entity_t *entity)
{
- const source_position_t *pos = &entity->base.source_position;
+ const position_t *pos = &entity->base.pos;
if (entity->kind != ENTITY_FUNCTION) {
warningf(WARN_MAIN, pos, "'main' is not a function");
return;
}
}
-static void error_redefined_as_different_kind(const source_position_t *pos,
+static void error_redefined_as_different_kind(const position_t *pos,
const entity_t *old, entity_kind_t new_kind)
{
- char const *const what = get_entity_kind_name(new_kind);
- source_position_t const *const ppos = &old->base.source_position;
+ char const *const what = get_entity_kind_name(new_kind);
+ position_t const *const ppos = &old->base.pos;
errorf(pos, "redeclaration of '%N' as %s (declared %P)", old, what, ppos);
}
*/
entity_t *record_entity(entity_t *entity, const bool is_definition)
{
- const symbol_t *const symbol = entity->base.symbol;
- const namespace_tag_t namespc = (namespace_tag_t)entity->base.namespc;
- const source_position_t *pos = &entity->base.source_position;
+ const symbol_t *const symbol = entity->base.symbol;
+ const namespace_tag_t namespc = (namespace_tag_t)entity->base.namespc;
+ const position_t *pos = &entity->base.pos;
/* can happen in error cases */
if (symbol == NULL)
}
if (previous_entity != NULL) {
- source_position_t const *const ppos = &previous_entity->base.source_position;
+ position_t const *const ppos = &previous_entity->base.pos;
if (previous_entity->base.parent_scope == ¤t_function->parameters &&
previous_entity->base.parent_scope->depth + 1 == current_scope->depth) {
}
static void parser_error_multiple_definition(entity_t *entity,
- const source_position_t *source_position)
+ const position_t *pos)
{
- errorf(source_position, "redefinition of '%N' (declared %P)", entity, &entity->base.source_position);
+ errorf(pos, "redefinition of '%N' (declared %P)", entity, &entity->base.pos);
}
static bool is_declaration_specifier(const token_t *token)
type_t *orig_type = type_error_type;
if (entity->base.kind == ENTITY_TYPEDEF) {
- source_position_t const *const pos = &entity->base.source_position;
+ position_t const *const pos = &entity->base.pos;
errorf(pos, "'%N' is initialized (use __typeof__ instead)", entity);
} else {
assert(is_declaration(entity));
}
if (is_type_function(type)) {
- source_position_t const *const pos = &entity->base.source_position;
+ position_t const *const pos = &entity->base.pos;
errorf(pos, "'%N' is initialized like a variable", entity);
orig_type = type_error_type;
}
eat(';');
anonymous_entity = NULL;
- source_position_t const *const pos = &specifiers->source_position;
+ position_t const *const pos = &specifiers->pos;
if (specifiers->storage_class != STORAGE_CLASS_NONE ||
specifiers->thread_local) {
warningf(WARN_OTHER, pos, "useless storage class in empty declaration");
return;
}
- errorf(&ent->base.source_position, "variable '%#N' has incomplete type", ent);
+ errorf(&ent->base.pos, "variable '%#N' has incomplete type", ent);
}
declaration_t *decl = &entity->declaration;
if (decl->storage_class != STORAGE_CLASS_EXTERN &&
is_type_reference(skip_typeref(decl->type))) {
- source_position_t const *const pos = &entity->base.source_position;
+ position_t const *const pos = &entity->base.pos;
errorf(pos, "reference '%#N' must be initialized", entity);
}
}
check_variable_type_complete(entity);
- if (!next_if(','))
+ if (!accept(','))
break;
add_anchor_token('=');
entity_t *previous_entity = get_entity(symbol, NAMESPACE_NORMAL);
if (previous_entity == NULL
|| previous_entity->base.parent_scope != current_scope) {
- errorf(&entity->base.source_position, "expected declaration of a function parameter, found '%Y'",
+ errorf(&entity->base.pos, "expected declaration of a function parameter, found '%Y'",
symbol);
return entity;
}
type_t *parameter_type = parameter->declaration.type;
if (parameter_type == NULL) {
- source_position_t const* const pos = ¶meter->base.source_position;
+ position_t const* const pos = ¶meter->base.pos;
if (strict_mode) {
errorf(pos, "no type specified for function '%N'", parameter);
parameter_type = type_error_type;
new_type = identify_new_type(new_type);
if (need_incompatible_warning) {
- symbol_t const *const sym = entity->base.symbol;
- source_position_t const *const pos = &entity->base.source_position;
- source_position_t const *const ppos = &proto_type->base.source_position;
+ symbol_t const *const sym = entity->base.symbol;
+ position_t const *const pos = &entity->base.pos;
+ position_t const *const ppos = &proto_type->base.pos;
warningf(WARN_OTHER, pos, "declaration '%#N' is incompatible with '%#T' (declared %P)", proto_type, new_type, sym, ppos);
}
entity->declaration.type = new_type;
{
if (first_err) {
first_err = false;
- char const *const file = current_function->base.base.source_position.input_name;
+ char const *const file = current_function->base.base.pos.input_name;
diagnosticf("%s: In '%N':\n", file, (entity_t const*)current_function);
}
}
goto_statement != NULL;
goto_statement = goto_statement->next) {
label_t *label = goto_statement->label;
- if (label->base.source_position.input_name == NULL) {
+ if (label->base.pos.input_name == NULL) {
print_in_function();
- source_position_t const *const pos = &goto_statement->base.source_position;
+ position_t const *const pos = &goto_statement->base.pos;
errorf(pos, "'%N' used but not defined", (entity_t const*)label);
}
}
if (! label->used) {
print_in_function();
- source_position_t const *const pos = &label_statement->base.source_position;
+ position_t const *const pos = &label_statement->base.pos;
warningf(WARN_UNUSED_LABEL, pos, "'%N' defined but not used", (entity_t const*)label);
}
}
if (!declaration->used) {
print_in_function();
- warningf(why, &entity->base.source_position, "'%N' is unused", entity);
+ warningf(why, &entity->base.pos, "'%N' is unused", entity);
} else if (entity->kind == ENTITY_VARIABLE && !entity->variable.read) {
print_in_function();
- warningf(why, &entity->base.source_position, "'%N' is never read", entity);
+ warningf(why, &entity->base.pos, "'%N' is never read", entity);
}
}
}
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);
}
}
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) {
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;
}
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;
switch (parent->kind) {
case STATEMENT_SWITCH:
- case STATEMENT_WHILE:
case STATEMENT_DO_WHILE:
case STATEMENT_FOR:
last = 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;
if (!is_type_void(ret) &&
is_type_valid(ret) &&
!is_main(current_entity)) {
- source_position_t const *const pos = &stmt->base.source_position;
+ position_t const *const pos = &stmt->base.pos;
warningf(WARN_RETURN_TYPE, pos, "control reaches end of non-void function");
}
return;
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)
if (!stmt->base.reachable) {
expression_t const *const cond = stmt->do_while.condition;
if (determine_truth(cond) >= 0) {
- source_position_t const *const pos = &cond->base.source_position;
+ position_t const *const pos = &cond->base.pos;
warningf(WARN_UNREACHABLE_CODE, pos, "condition of do-while-loop is unreachable");
}
}
goto warn_unreachable;
} else {
if (!stmt->base.reachable && fors->initialisation != NULL) {
- source_position_t const *const pos = &fors->initialisation->base.source_position;
+ position_t const *const pos = &fors->initialisation->base.pos;
warningf(WARN_UNREACHABLE_CODE, pos, "initialisation of for-statement is unreachable");
}
if (!fors->condition_reachable && fors->condition != NULL) {
- source_position_t const *const pos = &fors->condition->base.source_position;
+ position_t const *const pos = &fors->condition->base.pos;
warningf(WARN_UNREACHABLE_CODE, pos, "condition of for-statement is unreachable");
}
if (!fors->step_reachable && fors->step != NULL) {
- source_position_t const *const pos = &fors->step->base.source_position;
+ position_t const *const pos = &fors->step->base.pos;
warningf(WARN_UNREACHABLE_CODE, pos, "step of for-statement is unreachable");
}
}
default:
warn_unreachable:
if (!stmt->base.reachable) {
- source_position_t const *const pos = &stmt->base.source_position;
+ position_t const *const pos = &stmt->base.pos;
warningf(WARN_UNREACHABLE_CODE, pos, "statement is unreachable");
}
return;
return;
}
- source_position_t const *const pos = &ndeclaration->base.source_position;
+ position_t const *const pos = &ndeclaration->base.pos;
if (is_typeref(orig_type)) {
/* ยง6.9.1:2 */
errorf(pos, "type of function definition '%#N' is a typedef", ndeclaration);
|| parameter->base.parent_scope == current_scope);
parameter->base.parent_scope = current_scope;
if (parameter->base.symbol == NULL) {
- errorf(¶meter->base.source_position, "parameter name omitted");
+ errorf(¶meter->base.pos, "parameter name omitted");
continue;
}
environment_push(parameter);
}
- if (function->statement != NULL) {
+ if (function->body != NULL) {
parser_error_multiple_definition(entity, HERE);
eat_block();
} else {
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();
walk_statements(body, check_unreachable, NULL);
if (noreturn_candidate &&
!(function->base.modifiers & DM_NORETURN)) {
- source_position_t const *const pos = &body->base.source_position;
+ position_t const *const pos = &body->base.pos;
warningf(WARN_MISSING_NORETURN, pos, "function '%#N' is candidate for attribute 'noreturn'", entity);
}
}
return NULL;
}
-static void check_deprecated(const source_position_t *source_position,
- const entity_t *entity)
+static void check_deprecated(const position_t *pos, const entity_t *entity)
{
if (!is_declaration(entity))
return;
if ((entity->declaration.modifiers & DM_DEPRECATED) == 0)
return;
- source_position_t const *const epos = &entity->base.source_position;
- char const *const msg = get_deprecated_string(entity->declaration.attributes);
+ position_t const *const epos = &entity->base.pos;
+ char const *const msg = get_deprecated_string(entity->declaration.attributes);
if (msg != NULL) {
- warningf(WARN_DEPRECATED_DECLARATIONS, source_position, "'%N' is deprecated (declared %P): \"%s\"", entity, epos, msg);
+ warningf(WARN_DEPRECATED_DECLARATIONS, pos, "'%N' is deprecated (declared %P): \"%s\"", entity, epos, msg);
} else {
- warningf(WARN_DEPRECATED_DECLARATIONS, source_position, "'%N' is deprecated (declared %P)", entity, epos);
+ warningf(WARN_DEPRECATED_DECLARATIONS, pos, "'%N' is deprecated (declared %P)", entity, epos);
}
}
-static expression_t *create_select(const source_position_t *pos,
- expression_t *addr,
+static expression_t *create_select(const position_t *pos, expression_t *addr,
type_qualifiers_t qualifiers,
entity_t *entry)
{
* creates implicit select expressions for them.
* Returns the adress for the innermost compound.
*/
-static expression_t *find_create_select(const source_position_t *pos,
+static expression_t *find_create_select(const position_t *pos,
expression_t *addr,
type_qualifiers_t qualifiers,
compound_t *compound, symbol_t *symbol)
continue;
expression_t *sub_addr = create_select(pos, addr, qualifiers, iter);
- sub_addr->base.source_position = *pos;
- sub_addr->base.implicit = true;
+ sub_addr->base.pos = *pos;
+ sub_addr->base.implicit = true;
return find_create_select(pos, sub_addr, qualifiers, sub_compound,
symbol);
}
} else {
entity = parse_declarator(specifiers,
DECL_MAY_BE_ABSTRACT | DECL_CREATE_COMPOUND_MEMBER);
- source_position_t const *const pos = &entity->base.source_position;
+ position_t const *const pos = &entity->base.pos;
if (entity->kind == ENTITY_TYPEDEF) {
errorf(pos, "typedef not allowed as compound member");
} else {
if (symbol != NULL) {
entity_t *prev = find_compound_entry(compound, symbol);
if (prev != NULL) {
- source_position_t const *const ppos = &prev->base.source_position;
+ position_t const *const ppos = &prev->base.pos;
errorf(pos, "multiple declarations of '%N' (declared %P)", entity, ppos);
}
}
append_entity(&compound->members, entity);
}
}
- } while (next_if(','));
+ } while (accept(','));
rem_anchor_token(',');
rem_anchor_token(';');
expect(';');
/* TODO: improve error message, user does probably not know what a
* storage class is...
*/
- errorf(&specifiers.source_position, "typename must not have a storage class");
+ errorf(&specifiers.pos, "typename must not have a storage class");
}
type_t *result = parse_abstract_declarator(specifiers.type);
{
bool const warn = is_warn_on(WARN_WRITE_STRINGS);
switch (enc) {
- case STRING_ENCODING_CHAR: return warn ? type_const_char_ptr : type_char_ptr;
- case STRING_ENCODING_WIDE: return warn ? type_const_wchar_t_ptr : type_wchar_t_ptr;
+ 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");
}
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(HERE, "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(HERE, "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:
- kind = EXPR_LITERAL_FLOATINGPOINT;
- type = check_floatingpoint_suffix();
+ case 8:
+ case 10:
+ if (*i == 'E' || *i == 'e') {
+ base = 10;
+ goto parse_exponent;
+ }
+ break;
+
+ case 16:
+ if (*i == 'P' || *i == 'p') {
+parse_exponent:
+ ++i;
+ is_float = true;
+
+ if (*i == '-' || *i == '+')
+ ++i;
+
+ 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;
default:
- panic("unexpected token type in parse_number_literal");
+ panic("invalid base");
}
- 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();
+done:;
+ expression_t *const expr = allocate_expression_zero(is_float ? EXPR_LITERAL_FLOATINGPOINT : EXPR_LITERAL_INTEGER);
+ expr->literal.value = *str;
- /* 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 (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 {
+ expr->literal.suffix = i;
+ if (is_float) {
+ check_floatingpoint_suffix(expr, i);
+ } else {
+ check_integer_suffix(expr, i);
+ }
+ }
+ }
+
+ eat(T_NUMBER);
+ return expr;
}
/**
static expression_t *parse_character_constant(void)
{
expression_t *const literal = allocate_expression_zero(EXPR_LITERAL_CHARACTER);
- literal->string_literal.value = token.string.string;
+ literal->string_literal.value = token.literal.string;
- size_t const size = get_string_len(&token.string.string);
- switch (token.string.string.encoding) {
+ 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)) {
}
break;
- case STRING_ENCODING_WIDE:
- literal->base.type = type_int;
+ 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");
}
return literal;
}
-static entity_t *create_implicit_function(symbol_t *symbol, source_position_t const *const pos)
+static entity_t *create_implicit_function(symbol_t *symbol, position_t const *const pos)
{
type_t *ntype = allocate_type_zero(TYPE_FUNCTION);
ntype->function.return_type = type_int;
static entity_t *parse_qualified_identifier(void)
{
/* namespace containing the symbol */
- symbol_t *symbol;
- source_position_t pos;
- const scope_t *lookup_scope = NULL;
+ symbol_t *symbol;
+ 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;
/* lookup entity */
entity = lookup_entity(lookup_scope, symbol, NAMESPACE_NORMAL);
- if (!next_if(T_COLONCOLON))
+ if (!accept(T_COLONCOLON))
break;
switch (entity->kind) {
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);
}
static expression_t *parse_reference(void)
{
- source_position_t const pos = *HERE;
- entity_t *const entity = parse_qualified_identifier();
+ position_t const pos = *HERE;
+ entity_t *const entity = parse_qualified_identifier();
type_t *orig_type;
if (is_declaration(entity)) {
if (entity->kind == ENTITY_ENUM_VALUE)
kind = EXPR_ENUM_CONSTANT;
- expression_t *expression = allocate_expression_zero(kind);
- expression->base.source_position = pos;
- expression->base.type = type;
- expression->reference.entity = entity;
+ expression_t *expression = allocate_expression_zero(kind);
+ expression->base.pos = pos;
+ expression->base.type = type;
+ expression->reference.entity = entity;
/* this declaration is used */
if (is_declaration(entity)) {
static bool semantic_cast(expression_t *cast)
{
- expression_t *expression = cast->unary.value;
- type_t *orig_dest_type = cast->base.type;
- type_t *orig_type_right = expression->base.type;
- type_t const *dst_type = skip_typeref(orig_dest_type);
- type_t const *src_type = skip_typeref(orig_type_right);
- source_position_t const *pos = &cast->base.source_position;
+ expression_t *expression = cast->unary.value;
+ type_t *orig_dest_type = cast->base.type;
+ type_t *orig_type_right = expression->base.type;
+ type_t const *dst_type = skip_typeref(orig_dest_type);
+ type_t const *src_type = skip_typeref(orig_type_right);
+ position_t const *pos = &cast->base.pos;
/* ยง6.5.4 A (void) cast is explicitly permitted, more for documentation than for utility. */
if (is_type_void(dst_type))
return true;
}
-static expression_t *parse_compound_literal(source_position_t const *const pos, type_t *type)
+static expression_t *parse_compound_literal(position_t const *const pos,
+ type_t *type)
{
expression_t *expression = allocate_expression_zero(EXPR_COMPOUND_LITERAL);
- expression->base.source_position = *pos;
+ expression->base.pos = *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;
}
*/
static expression_t *parse_cast(void)
{
- source_position_t const pos = *HERE;
+ position_t const pos = *HERE;
eat('(');
add_anchor_token(')');
}
expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST);
- cast->base.source_position = pos;
+ cast->base.pos = pos;
expression_t *value = parse_subexpression(PREC_CAST);
cast->base.type = type;
type = stmt->expression.expression->base.type;
}
} else {
- source_position_t const *const pos = &expression->base.source_position;
+ position_t const *const pos = &expression->base.pos;
warningf(WARN_OTHER, pos, "empty statement expression ({})");
}
expression->base.type = type;
static expression_t *parse_function_keyword(funcname_kind_t const kind)
{
if (current_function == NULL) {
- errorf(HERE, "'%K' used outside of a function", &token);
+ errorf(HERE, "%K used outside of a function", &token);
}
expression_t *expression = allocate_expression_zero(EXPR_FUNCNAME);
static designator_t *parse_designator(void)
{
designator_t *const result = allocate_ast_zero(sizeof(result[0]));
- result->symbol = expect_identifier("while parsing member designator", &result->source_position);
+ result->symbol = expect_identifier("while parsing member designator", &result->pos);
if (!result->symbol)
return NULL;
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);
+ designator->symbol = expect_identifier("while parsing member designator", &designator->pos);
if (!designator->symbol)
return NULL;
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;
- designator->array_index = parse_expression();
+ designator_t *designator = allocate_ast_zero(sizeof(result[0]));
+ designator->pos = *HERE;
+ designator->array_index = parse_expression();
rem_anchor_token(']');
expect(']');
if (designator->array_index == NULL) {
expect(')');
if (!current_function) {
- errorf(&expression->base.source_position, "'va_start' used outside of function");
+ errorf(&expression->base.pos, "'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");
+ errorf(&expression->base.pos, "'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");
+ errorf(¶m->base.pos, "second argument of 'va_start' must be last parameter of the current function");
}
return expression;
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",
- &dst->base.source_position);
+ &dst->base.pos);
expression->va_copye.dst = dst;
rem_anchor_token(',');
if (!is_type_float(type_left) && !is_type_float(type_right)) {
if (is_type_valid(type_left) && is_type_valid(type_right)) {
type_error_incompatible("invalid operands in comparison",
- &expression->base.source_position, orig_type_left, orig_type_right);
+ &expression->base.pos, orig_type_left, orig_type_right);
}
} else {
semantic_comparison(&expression->binary);
}
} 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 };
+ position_t const nowhere = { NULL, 0, 0, false };
label = allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, sym, &nowhere);
label_push(label);
}
*/
static expression_t *parse_label_address(void)
{
- source_position_t const source_position = *HERE;
+ position_t const pos = *HERE;
eat(T_ANDAND);
label_t *const label = get_label("while parsing label address");
label->address_taken = true;
expression_t *expression = allocate_expression_zero(EXPR_LABEL_ADDRESS);
- expression->base.source_position = source_position;
+ expression->base.pos = pos;
/* label address is treated as a void pointer */
expression->base.type = type_void_ptr;
if (token.kind != ')') do {
(void)parse_assignment_expression();
- } while (next_if(','));
+ } while (accept(','));
rem_anchor_token(',');
rem_anchor_token(')');
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: return parse_number_literal();
+ case T_NUMBER: return parse_number_literal();
case T_CHARACTER_CONSTANT: return parse_character_constant();
case T_STRING_LITERAL: return parse_string_literal();
case T___func__: return parse_function_keyword(FUNCNAME_FUNCTION);
}
/* FALLTHROUGH */
DECLARATION_START {
- source_position_t const pos = *HERE;
+ position_t const pos = *HERE;
declaration_specifiers_t specifiers;
parse_declaration_specifiers(&specifiers);
type_t const *const type = parse_abstract_declarator(specifiers.type);
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.pos, "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;
+ position_t const *const pos = &idx->base.pos;
warningf(WARN_CHAR_SUBSCRIPTS, pos, "array subscript has char type");
}
} else {
if (is_type_valid(type_left) && is_type_valid(type_inside)) {
- errorf(&expr->base.source_position, "invalid types '%T[%T]' for array access", orig_type_left, orig_type_inside);
+ errorf(&expr->base.pos, "invalid types '%T[%T]' for array access", orig_type_left, orig_type_inside);
}
res_type = type_error_type;
ref = left;
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;
+ position_t const pos = *HERE;
eat('(');
add_anchor_token(')');
orig_type = parse_typename();
typeprop_expression:
if (is_bitfield(expression)) {
char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
- errorf(&tp_expression->base.source_position,
+ errorf(&tp_expression->base.pos,
"operand of %s expression must not be a bitfield", what);
}
} else if (type->kind == TYPE_FUNCTION) {
if (GNU_MODE) {
/* function types are allowed (and return 1) */
- source_position_t const *const pos = &tp_expression->base.source_position;
- char const *const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
+ position_t const *const pos = &tp_expression->base.pos;
+ char const *const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
warningf(WARN_OTHER, pos, "%s expression with function argument returns invalid result", what);
} else {
wrong_type = "function";
if (wrong_type != NULL) {
char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
- errorf(&tp_expression->base.source_position,
+ errorf(&tp_expression->base.pos,
"operand of %s expression must not be of %s type '%T'",
what, wrong_type, orig_type);
}
{
assert(token.kind == '.' || token.kind == T_MINUSGREATER);
bool select_left_arrow = (token.kind == T_MINUSGREATER);
- source_position_t const pos = *HERE;
+ position_t const pos = *HERE;
next_token();
symbol_t *const symbol = expect_identifier("while parsing select", NULL);
char buf[64];
snprintf(buf, sizeof(buf), "call argument %u", pos);
report_assign_error(error, expected_type, arg_expr, buf,
- &arg_expr->base.source_position);
+ &arg_expr->base.pos);
} else {
type_t *const promoted_type = get_default_promoted_type(arg_type);
if (!types_compatible(expected_type_skip, promoted_type) &&
!types_compatible(expected_type_skip, type_void_ptr) &&
!types_compatible(type_void_ptr, promoted_type)) {
/* Deliberately show the skipped types in this warning */
- source_position_t const *const apos = &arg_expr->base.source_position;
+ position_t const *const apos = &arg_expr->base.pos;
warningf(WARN_TRADITIONAL, apos, "passing call argument %u as '%T' rather than '%T' due to prototype", pos, expected_type_skip, promoted_type);
}
}
call_argument_t *argument = call->arguments;
if (is_constant_expression(argument->expression) == EXPR_CLASS_VARIABLE) {
- errorf(&call->base.source_position,
+ errorf(&call->base.pos,
"argument of '%Y' must be a constant expression",
call->function->reference.entity->base.symbol);
}
if (rw != NULL) {
if (is_constant_expression(rw->expression) == EXPR_CLASS_VARIABLE) {
- errorf(&call->base.source_position,
+ errorf(&call->base.pos,
"second argument of '%Y' must be a constant expression",
call->function->reference.entity->base.symbol);
}
}
if (locality != NULL) {
if (is_constant_expression(locality->expression) == EXPR_CLASS_VARIABLE) {
- errorf(&call->base.source_position,
+ errorf(&call->base.pos,
"third argument of '%Y' must be a constant expression",
call->function->reference.entity->base.symbol);
}
- locality = rw->next;
}
break;
default:
call_argument_t *arg = call->arguments->next;
if (arg != NULL && is_constant_expression(arg->expression) == EXPR_CLASS_VARIABLE) {
- errorf(&call->base.source_position,
+ errorf(&call->base.pos,
"second argument of '%Y' must be a constant expression",
call->function->reference.entity->base.symbol);
}
*anchor = argument;
anchor = &argument->next;
- } while (next_if(','));
+ } while (accept(','));
}
rem_anchor_token(',');
rem_anchor_token(')');
}
if (parameter != NULL) {
- errorf(&expression->base.source_position, "too few arguments to function '%E'", expression);
+ errorf(&expression->base.pos, "too few arguments to function '%E'",
+ expression);
} else if (argument != NULL && !function_type->variadic) {
- errorf(&argument->expression->base.source_position, "too many arguments to function '%E'", expression);
+ errorf(&argument->expression->base.pos,
+ "too many arguments to function '%E'", expression);
}
}
for (; argument != NULL; argument = argument->next) {
type_t *argument_type = argument->expression->base.type;
if (!is_type_object(skip_typeref(argument_type))) {
- errorf(&argument->expression->base.source_position,
+ errorf(&argument->expression->base.pos,
"call argument '%E' must not be void", argument->expression);
}
check_format(call);
if (is_type_compound(skip_typeref(function_type->return_type))) {
- source_position_t const *const pos = &expression->base.source_position;
+ position_t const *const pos = &expression->base.pos;
warningf(WARN_AGGREGATE_RETURN, pos, "function call has aggregate value");
}
{
expr = get_reference_address(expr);
if (expr != NULL) {
- source_position_t const *const pos = &expr->base.source_position;
- entity_t const *const ent = expr->reference.entity;
+ position_t const *const pos = &expr->base.pos;
+ entity_t const *const ent = expr->reference.entity;
warningf(WARN_ADDRESS, pos, "the address of '%N' will always evaluate as 'true'", ent);
}
}
return;
if (expr->base.parenthesized)
return;
- source_position_t const *const pos = &expr->base.source_position;
+ position_t const *const pos = &expr->base.pos;
warningf(WARN_PARENTHESES, pos, "suggest parentheses around assignment used as truth value");
}
warn_reference_address_as_bool(expr);
warn_assignment_in_condition(expr);
} else if (is_type_valid(type)) {
- errorf(&expr->base.source_position,
- "%s must have scalar type", context);
+ errorf(&expr->base.pos, "%s must have scalar type", context);
}
}
type_t *const false_type = skip_typeref(orig_false_type);
/* 6.5.15.3 */
- source_position_t const *const pos = &conditional->base.source_position;
- type_t *result_type;
+ position_t const *const pos = &conditional->base.pos;
+ type_t *result_type;
if (is_type_void(true_type) || is_type_void(false_type)) {
/* ISO/IEC 14882:1998(E) ยง5.16:2 */
if (true_expression->kind == EXPR_UNARY_THROW) {
eat(T_delete);
- if (next_if('[')) {
+ if (accept('[')) {
result->kind = EXPR_UNARY_DELETE_ARRAY;
expect(']');
}
type_t *const type = skip_typeref(value->base.type);
if (!is_type_pointer(type)) {
if (is_type_valid(type)) {
- errorf(&value->base.source_position,
+ errorf(&value->base.pos,
"operand of delete must have pointer type");
}
} else if (is_type_void(skip_typeref(type->pointer.points_to))) {
- source_position_t const *const pos = &value->base.source_position;
+ position_t const *const pos = &value->base.pos;
warningf(WARN_OTHER, pos, "deleting 'void*' is undefined");
}
type_t *const orig_type = value->base.type;
type_t *const type = skip_typeref(orig_type);
if (is_type_incomplete(type)) {
- errorf(&value->base.source_position,
+ errorf(&value->base.pos,
"cannot throw object of incomplete type '%T'", orig_type);
} else if (is_type_pointer(type)) {
type_t *const points_to = skip_typeref(type->pointer.points_to);
if (is_type_incomplete(points_to) && !is_type_void(points_to)) {
- errorf(&value->base.source_position,
+ errorf(&value->base.pos,
"cannot throw pointer to incomplete type '%T'", orig_type);
}
}
return result;
}
-static bool check_pointer_arithmetic(const source_position_t *source_position,
+static bool check_pointer_arithmetic(const position_t *pos,
type_t *pointer_type,
type_t *orig_pointer_type)
{
if (is_type_incomplete(points_to)) {
if (!GNU_MODE || !is_type_void(points_to)) {
- errorf(source_position,
+ errorf(pos,
"arithmetic with pointer to incomplete type '%T' not allowed",
orig_pointer_type);
return false;
} else {
- warningf(WARN_POINTER_ARITH, source_position, "pointer of type '%T' used in arithmetic", orig_pointer_type);
+ warningf(WARN_POINTER_ARITH, pos, "pointer of type '%T' used in arithmetic", orig_pointer_type);
}
} else if (is_type_function(points_to)) {
if (!GNU_MODE) {
- errorf(source_position,
+ errorf(pos,
"arithmetic with pointer to function type '%T' not allowed",
orig_pointer_type);
return false;
} else {
- warningf(WARN_POINTER_ARITH, source_position, "pointer to a function '%T' used in arithmetic", orig_pointer_type);
+ warningf(WARN_POINTER_ARITH, pos,
+ "pointer to a function '%T' used in arithmetic",
+ orig_pointer_type);
}
}
return true;
type_t *const orig_type = expression->value->base.type;
type_t *const type = skip_typeref(orig_type);
if (is_type_pointer(type)) {
- if (!check_pointer_arithmetic(&expression->base.source_position,
- type, orig_type)) {
+ if (!check_pointer_arithmetic(&expression->base.pos, type, orig_type)) {
return;
}
} else if (!is_type_real(type) && is_type_valid(type)) {
/* TODO: improve error message */
- errorf(&expression->base.source_position,
+ errorf(&expression->base.pos,
"operation needs an arithmetic or pointer type");
return;
}
if (!is_lvalue(expression->value)) {
/* TODO: improve error message */
- errorf(&expression->base.source_position, "lvalue required as operand");
+ errorf(&expression->base.pos, "lvalue required as operand");
}
expression->base.type = orig_type;
}
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");
+ position_t const *const pos = &expression->base.pos;
+ errorf(pos, "operand of unary expression must have arithmetic type, but is '%T'", orig_type);
}
return;
} else if (is_type_integer(type)) {
static void semantic_unexpr_plus(unary_expression_t *expression)
{
semantic_unexpr_arithmetic(expression);
- source_position_t const *const pos = &expression->base.source_position;
+ position_t const *const pos = &expression->base.pos;
warningf(WARN_TRADITIONAL, pos, "traditional C rejects the unary plus operator");
}
type_t *const type = skip_typeref(orig_type);
if (!is_type_integer(type)) {
if (is_type_valid(type)) {
- errorf(&expression->base.source_position,
- "operand of ~ must be of integer type");
+ errorf(&expression->base.pos, "operand of ~ must be of integer type");
}
return;
}
type_t *const type = skip_typeref(orig_type);
if (!is_type_pointer(type)) {
if (is_type_valid(type)) {
- errorf(&expression->base.source_position,
+ errorf(&expression->base.pos,
"Unary '*' needs pointer or array type, but type '%T' given", orig_type);
}
return;
if (entity->declaration.storage_class == STORAGE_CLASS_REGISTER
&& !may_be_register) {
- source_position_t const *const pos = &expression->base.source_position;
+ position_t const *const pos = &expression->base.pos;
errorf(pos, "address of register '%N' requested", entity);
}
/* ยง6.5.3.2 */
if (!is_lvalue(value)) {
- errorf(&expression->base.source_position, "'&' requires an lvalue");
+ errorf(&expression->base.pos, "'&' requires an lvalue");
}
if (is_bitfield(value)) {
- errorf(&expression->base.source_position,
- "'&' not allowed on bitfield");
+ errorf(&expression->base.pos, "'&' not allowed on bitfield");
}
set_address_taken(value, false);
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");
+ position_t const *const pos = &expression->base.pos;
+ errorf(pos, "operands of binary expression must have arithmetic types, but are '%T' and '%T'", orig_type_left, orig_type_right);
}
return;
}
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");
+ position_t const *const pos = &expression->base.pos;
+ errorf(pos, "operands of binary expression must have integer types, but are '%T' and '%T'", orig_type_left, orig_type_right);
}
return;
}
if (is_type_integer(right->base.type) &&
is_constant_expression(right) == EXPR_CLASS_CONSTANT &&
!fold_constant_to_bool(right)) {
- source_position_t const *const pos = &expression->base.source_position;
+ position_t const *const pos = &expression->base.pos;
warningf(WARN_DIV_BY_ZERO, pos, "division by zero");
}
}
/**
- * 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)
default: return;
}
- source_position_t const *const pos = &expr->base.source_position;
+ position_t const *const pos = &expr->base.pos;
warningf(WARN_PARENTHESES, pos, "suggest parentheses around '%c' inside shift", op);
}
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");
+ position_t const *const pos = &expression->base.pos;
+ errorf(pos, "operands of shift expression must have integer types, but are '%T' and '%T'", orig_type_left, orig_type_right);
}
return false;
}
type_left = promote_integer(type_left);
if (is_constant_expression(right) == EXPR_CLASS_CONSTANT) {
- source_position_t const *const pos = &right->base.source_position;
- long const count = fold_constant_to_int(right);
+ position_t const *const pos = &right->base.pos;
+ long const count = fold_constant_to_int(right);
if (count < 0) {
warningf(WARN_OTHER, pos, "shift count must be non-negative");
} else if ((unsigned long)count >=
expression->right = create_implicit_cast(right, arithmetic_type);
expression->base.type = arithmetic_type;
} else if (is_type_pointer(type_left) && is_type_integer(type_right)) {
- check_pointer_arithmetic(&expression->base.source_position,
- type_left, orig_type_left);
+ check_pointer_arithmetic(&expression->base.pos, type_left,
+ orig_type_left);
expression->base.type = type_left;
} else if (is_type_pointer(type_right) && is_type_integer(type_left)) {
- check_pointer_arithmetic(&expression->base.source_position,
- type_right, orig_type_right);
+ check_pointer_arithmetic(&expression->base.pos, type_right,
+ orig_type_right);
expression->base.type = type_right;
} else if (is_type_valid(type_left) && is_type_valid(type_right)) {
- errorf(&expression->base.source_position,
+ errorf(&expression->base.pos,
"invalid operands to binary + ('%T', '%T')",
orig_type_left, orig_type_right);
}
static void semantic_sub(binary_expression_t *expression)
{
- expression_t *const left = expression->left;
- expression_t *const right = expression->right;
- type_t *const orig_type_left = left->base.type;
- type_t *const orig_type_right = right->base.type;
- type_t *const type_left = skip_typeref(orig_type_left);
- type_t *const type_right = skip_typeref(orig_type_right);
- source_position_t const *const pos = &expression->base.source_position;
+ expression_t *const left = expression->left;
+ expression_t *const right = expression->right;
+ type_t *const orig_type_left = left->base.type;
+ type_t *const orig_type_right = right->base.type;
+ type_t *const type_left = skip_typeref(orig_type_left);
+ type_t *const type_right = skip_typeref(orig_type_right);
+ position_t const *const pos = &expression->base.pos;
/* ยง5.6.5 */
if (is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) {
expression->right = create_implicit_cast(right, arithmetic_type);
expression->base.type = arithmetic_type;
} else if (is_type_pointer(type_left) && is_type_integer(type_right)) {
- check_pointer_arithmetic(&expression->base.source_position,
- type_left, orig_type_left);
+ check_pointer_arithmetic(&expression->base.pos, type_left,
+ orig_type_left);
expression->base.type = type_left;
} else if (is_type_pointer(type_left) && is_type_pointer(type_right)) {
type_t *const unqual_left = get_unqualified_type(skip_typeref(type_left->pointer.points_to));
}
if (expr->kind == EXPR_STRING_LITERAL) {
- source_position_t const *const pos = &expr->base.source_position;
+ position_t const *const pos = &expr->base.pos;
warningf(WARN_ADDRESS, pos, "comparison with string literal results in unspecified behaviour");
}
}
}
}
-static void warn_comparison(source_position_t const *const pos, expression_t const *const expr, expression_t const *const other)
+static void warn_comparison(position_t const *const pos, expression_t const *const expr, expression_t const *const other)
{
warn_string_literal_address(expr);
*/
static void semantic_comparison(binary_expression_t *expression)
{
- source_position_t const *const pos = &expression->base.source_position;
- expression_t *const left = expression->left;
- expression_t *const right = expression->right;
+ position_t const *const pos = &expression->base.pos;
+ expression_t *const left = expression->left;
+ expression_t *const right = expression->right;
warn_comparison(pos, left, right);
warn_comparison(pos, right, left);
type_t *const type_left = skip_typeref(orig_type_left);
if (!is_lvalue(left)) {
- errorf(&left->base.source_position, "left hand side '%E' of assignment is not an lvalue",
- left);
+ errorf(&left->base.pos,
+ "left hand side '%E' of assignment is not an lvalue", left);
return false;
}
if (left->kind == EXPR_REFERENCE
&& left->reference.entity->kind == ENTITY_FUNCTION) {
- errorf(&left->base.source_position, "cannot assign to function '%E'", left);
+ errorf(&left->base.pos, "cannot assign to function '%E'", left);
return false;
}
if (is_type_array(type_left)) {
- errorf(&left->base.source_position, "cannot assign to array '%E'", left);
+ errorf(&left->base.pos, "cannot assign to array '%E'", left);
return false;
}
if (type_left->base.qualifiers & TYPE_QUALIFIER_CONST) {
- errorf(&left->base.source_position, "assignment to read-only location '%E' (type '%T')", left,
+ errorf(&left->base.pos,
+ "assignment to read-only location '%E' (type '%T')", left,
orig_type_left);
return false;
}
if (is_type_incomplete(type_left)) {
- errorf(&left->base.source_position, "left-hand side '%E' of assignment has incomplete type '%T'",
+ errorf(&left->base.pos, "left-hand side '%E' of assignment has incomplete type '%T'",
left, orig_type_left);
return false;
}
if (is_type_compound(type_left) && has_const_fields(&type_left->compound)) {
- errorf(&left->base.source_position, "cannot assign to '%E' because compound type '%T' has read-only fields",
+ errorf(&left->base.pos, "cannot assign to '%E' because compound type '%T' has read-only fields",
left, orig_type_left);
return false;
}
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");
+ errorf(&expression->base.pos, "operation needs arithmetic types");
}
return;
}
expression->right = create_implicit_cast(right, arithmetic_type);
expression->base.type = type_left;
} else if (is_type_pointer(type_left) && is_type_integer(type_right)) {
- check_pointer_arithmetic(&expression->base.source_position,
- type_left, orig_type_left);
+ check_pointer_arithmetic(&expression->base.pos, type_left,
+ orig_type_left);
expression->base.type = type_left;
} else if (is_type_valid(type_left) && is_type_valid(type_right)) {
- errorf(&expression->base.source_position,
+ errorf(&expression->base.pos,
"incompatible types '%T' and '%T' in assignment",
orig_type_left, 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");
+ errorf(&expression->base.pos, "operation needs integer types");
}
return;
}
return;
if (expr->base.parenthesized)
return;
- source_position_t const *const pos = &expr->base.source_position;
+ position_t const *const pos = &expr->base.pos;
warningf(WARN_PARENTHESES, pos, "suggest parentheses around && within ||");
}
assign_error_t error = semantic_assign(orig_type_left, expression->right);
report_assign_error(error, orig_type_left, expression->right,
- "assignment", &left->base.source_position);
+ "assignment", &left->base.pos);
expression->right = create_implicit_cast(expression->right, orig_type_left);
expression->base.type = orig_type_left;
}
{
const expression_t *const left = expression->left;
if (!expression_has_effect(left)) {
- source_position_t const *const pos = &left->base.source_position;
+ position_t const *const pos = &left->base.pos;
warningf(WARN_UNUSED_VALUE, pos, "left-hand operand of comma expression has no effect");
}
expression->base.type = expression->right->base.type;
}
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)
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);
/**
* 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;
+ if (token.kind == T_STRING_LITERAL || token.kind == '[') {
+ add_anchor_token(',');
+ do {
+ asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0]));
- while (token.kind == T_STRING_LITERAL || token.kind == '[') {
- asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0]));
+ add_anchor_token(')');
+ add_anchor_token('(');
+ add_anchor_token(T_STRING_LITERAL);
- if (next_if('[')) {
- add_anchor_token(']');
- argument->symbol = expect_identifier("while parsing asm argument", NULL);
- rem_anchor_token(']');
- expect(']');
- if (!argument->symbol)
- return NULL;
- }
-
- argument->constraints = parse_string_literals("asm argument");
- add_anchor_token(')');
- expect('(');
- 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;
+ }
+
+ if (value_flags != flags || value_size != size)
+ break;
- expression = value;
- } while (expression->kind == EXPR_UNARY_CAST);
+ 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.pos,
+ "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(')');
-
- set_address_taken(expression, true);
+ }
+ argument->expression = expression;
+ rem_anchor_token(')');
+ expect(')');
- *anchor = argument;
- anchor = &argument->next;
+ set_address_taken(expression, true);
- 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(NULL);
+ *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;
}
/**
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('(');
rem_anchor_token(T_STRING_LITERAL);
asm_statement->asm_text = parse_string_literals("asm statement");
- if (next_if(':'))
- asm_statement->outputs = parse_asm_arguments(true);
-
- if (next_if(':'))
- asm_statement->inputs = parse_asm_arguments(false);
+ 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);
rem_anchor_token(':');
- if (next_if(':'))
- asm_statement->clobbers = parse_asm_clobbers();
+ if (accept(':')) {
+ if (!asm_goto)
+ warningf(WARN_OTHER, &statement->base.pos, "assembler statement with labels should be 'asm goto'");
+ parse_asm_labels(&asm_statement->labels);
+ if (asm_statement->labels)
+ errorf(&statement->base.pos, "'asm goto' not supported");
+ } else {
+ if (asm_goto)
+ warningf(WARN_OTHER, &statement->base.pos, "'asm goto' without labels");
+ }
rem_anchor_token(')');
expect(')');
statement_t *inner_stmt;
switch (token.kind) {
case '}':
- errorf(&label->base.source_position, "%s at end of compound statement", label_kind);
+ errorf(&label->base.pos, "%s at end of compound statement", label_kind);
inner_stmt = create_error_statement();
break;
/* ISO/IEC 9899:1999(E) ยง6.8:1/6.8.2:1 Declarations are no statements */
/* ISO/IEC 14882:1998(E) ยง6:1/ยง6.7 Declarations are statements */
if (inner_stmt->kind == STATEMENT_DECLARATION && !(c_mode & _CXX)) {
- errorf(&inner_stmt->base.source_position, "declaration after %s", label_kind);
+ errorf(&inner_stmt->base.pos, "declaration after %s", label_kind);
}
break;
}
*/
static statement_t *parse_case_statement(void)
{
- statement_t *const statement = allocate_statement_zero(STATEMENT_CASE_LABEL);
- source_position_t *const pos = &statement->base.source_position;
+ statement_t *const statement = allocate_statement_zero(STATEMENT_CASE_LABEL);
+ position_t *const pos = &statement->base.pos;
eat(T_case);
add_anchor_token(':');
}
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);
}
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");
}
continue;
errorf(pos, "duplicate case value (previously used %P)",
- &l->base.source_position);
+ &l->base.pos);
break;
}
}
if (current_switch != NULL) {
const case_label_statement_t *def_label = current_switch->default_label;
if (def_label != NULL) {
- errorf(&statement->base.source_position, "multiple default labels in one switch (previous declared %P)", &def_label->base.source_position);
+ errorf(&statement->base.pos, "multiple default labels in one switch (previous declared %P)", &def_label->base.pos);
} else {
current_switch->default_label = &statement->case_label;
current_switch->last_case = &statement->case_label;
}
} else {
- errorf(&statement->base.source_position,
- "'default' label not within a switch statement");
+ errorf(&statement->base.pos,
+ "'default' label not within a switch statement");
}
statement->case_label.statement = parse_label_inner_statement(statement, "default label");
/* if statement is already set then the label is defined twice,
* otherwise it was just mentioned in a goto/local label declaration so far
*/
- source_position_t const* const pos = &statement->base.source_position;
+ position_t const* const pos = &statement->base.pos;
if (label->statement != NULL) {
- errorf(pos, "duplicate '%N' (declared %P)", (entity_t const*)label, &label->base.source_position);
+ errorf(pos, "duplicate '%N' (declared %P)", (entity_t const*)label, &label->base.pos);
} else {
- label->base.source_position = *pos;
- label->statement = statement;
+ label->base.pos = *pos;
+ label->statement = statement;
+ label->n_users += 1;
}
eat(':');
/* ISO/IEC 9899:1999(E) ยง6.8:1/6.8.2:1 Declarations are no statements */
/* ISO/IEC 14882:1998(E) ยง6:1/ยง6.7 Declarations are statements */
if (stmt->kind == STATEMENT_DECLARATION && !(c_mode & _CXX)) {
- errorf(&stmt->base.source_position, "declaration as inner statement, use {}");
+ errorf(&stmt->base.pos, "declaration as inner statement, use {}");
}
return stmt;
}
"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) {
}
} else if (true_stmt->kind == STATEMENT_IF &&
true_stmt->ifs.false_statement != NULL) {
- source_position_t const *const pos = &true_stmt->base.source_position;
+ position_t const *const pos = &true_stmt->base.pos;
warningf(WARN_PARENTHESES, pos, "suggest explicit braces to avoid ambiguous 'else'");
}
{
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;
}
}
if (!found) {
- source_position_t const *const pos = &statement->base.source_position;
+ position_t const *const pos = &statement->base.pos;
warningf(WARN_SWITCH_ENUM, pos, "'%N' not handled in switch", entry);
}
- last_value = value;
}
}
if (is_type_integer(type)) {
type = promote_integer(type);
if (get_akind_rank(get_akind(type)) >= get_akind_rank(ATOMIC_TYPE_LONG)) {
- warningf(WARN_TRADITIONAL, &expr->base.source_position, "'%T' switch expression not converted to '%T' in ISO C", type, type_int);
+ warningf(WARN_TRADITIONAL, &expr->base.pos,
+ "'%T' switch expression not converted to '%T' in ISO C",
+ type, type_int);
}
} else if (is_type_valid(type)) {
- errorf(&expr->base.source_position,
- "switch quantity is not an integer, but '%T'", type);
+ errorf(&expr->base.pos, "switch quantity is not an integer, but '%T'",
+ type);
type = type_error_type;
}
statement->switchs.expression = create_implicit_cast(expr, type);
current_switch = rem;
if (statement->switchs.default_label == NULL) {
- warningf(WARN_SWITCH_DEFAULT, &statement->base.source_position, "switch has no default case");
+ warningf(WARN_SWITCH_DEFAULT, &statement->base.pos, "switch has no default case");
}
check_enum_cases(&statement->switchs);
*/
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();
PUSH_EXTENSION();
- if (next_if(';')) {
+ if (accept(';')) {
} else if (is_declaration_specifier(&token)) {
parse_declaration(record_entity, DECL_FLAGS_NONE);
} else {
statement->fors.initialisation = init;
mark_vars_read(init, ENT_ANY);
if (!expression_has_effect(init)) {
- warningf(WARN_UNUSED_VALUE, &init->base.source_position, "initialisation of 'for'-statement has no effect");
+ warningf(WARN_UNUSED_VALUE, &init->base.pos, "initialisation of 'for'-statement has no effect");
}
rem_anchor_token(';');
expect(';');
statement->fors.step = step;
mark_vars_read(step, ENT_ANY);
if (!expression_has_effect(step)) {
- warningf(WARN_UNUSED_VALUE, &step->base.source_position, "step of 'for'-statement has no effect");
+ warningf(WARN_UNUSED_VALUE, &step->base.pos, "step of 'for'-statement has no effect");
}
}
rem_anchor_token(')');
if (type != type_error_type) {
if (!is_type_pointer(type) && !is_type_integer(type)) {
- errorf(&expression->base.source_position,
- "cannot convert to a pointer type");
+ errorf(&expression->base.pos, "cannot convert to a pointer type");
} else if (type != type_void_ptr) {
- warningf(WARN_OTHER, &expression->base.source_position, "type of computed goto expression should be 'void*' not '%T'", type);
+ warningf(WARN_OTHER, &expression->base.pos, "type of computed goto expression should be 'void*' not '%T'", type);
}
expression = create_implicit_cast(expression, type_void_ptr);
}
label_t *const label = get_label("while parsing goto");
if (label) {
+ label->n_users += 1;
label->used = true;
statement->gotos.label = label;
*goto_anchor = &statement->gotos;
goto_anchor = &statement->gotos.next;
} else {
- statement->gotos.label = &allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, sym_anonymous, &builtin_source_position)->label;
+ statement->gotos.label = &allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, sym_anonymous, &builtin_position)->label;
}
}
return is_local_variable(entity);
}
-static void err_or_warn(source_position_t const *const pos, char const *const msg)
+static void err_or_warn(position_t const *const pos, char const *const msg)
{
if (c_mode & _CXX || strict_mode) {
errorf(pos, msg);
assert(is_type_function(func_type));
type_t *const return_type = skip_typeref(func_type->function.return_type);
- source_position_t const *const pos = &statement->base.source_position;
+ position_t const *const pos = &statement->base.pos;
if (return_value != NULL) {
type_t *return_value_type = skip_typeref(return_value->base.type);
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)) {
type = promote_integer(type);
} else if (is_type_valid(type)) {
- errorf(&expr->base.source_position,
+ errorf(&expr->base.pos,
"__expect expression is not an integer, but '%T'", type);
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);
add_anchor_token(';');
add_anchor_token(',');
do {
- source_position_t pos;
+ position_t pos;
symbol_t *const symbol = expect_identifier("while parsing local label declaration", &pos);
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;
+ position_t const *const ppos = &entity->base.pos;
errorf(&pos, "multiple definitions of '%N' (previous definition %P)", entity, ppos);
} else {
entity = allocate_entity_zero(ENTITY_LOCAL_LABEL, NAMESPACE_LABEL, symbol, &pos);
environment_push(entity);
}
}
- } while (next_if(','));
+ } while (accept(','));
rem_anchor_token(',');
rem_anchor_token(';');
expect(';');
if (statement->kind == STATEMENT_EXPRESSION) {
expression_t *expression = statement->expression.expression;
if (!expression_has_effect(expression)) {
- warningf(WARN_UNUSED_VALUE, &expression->base.source_position, "statement has no effect");
+ warningf(WARN_UNUSED_VALUE, &expression->base.pos,
+ "statement has no effect");
}
}
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__Alignof);
add_anchor_token(T__Bool);
add_anchor_token(T__Complex);
add_anchor_token(T__Imaginary);
+ 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__);
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);
if (sub_statement->kind != STATEMENT_DECLARATION) {
only_decls_so_far = false;
} else if (!only_decls_so_far) {
- source_position_t const *const pos = &sub_statement->base.source_position;
+ position_t const *const pos = &sub_statement->base.pos;
warningf(WARN_DECLARATION_AFTER_STATEMENT, pos, "ISO C90 forbids mixed declarations and code");
}
expression_t *expression = sub_statement->expression.expression;
if (!expression_has_effect(expression)) {
- warningf(WARN_UNUSED_VALUE, &expression->base.source_position, "statement has no effect");
+ warningf(WARN_UNUSED_VALUE, &expression->base.pos,
+ "statement has no effect");
}
}
}
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__);
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__Thread_local);
rem_anchor_token(T__Imaginary);
rem_anchor_token(T__Complex);
rem_anchor_token(T__Bool);
+ 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('~');
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";
}
- warningf(why, &declaration->base.source_position, "'%#N' %s but not used", entity, s);
+ warningf(why, &declaration->base.pos, "'%#N' %s but not used", entity, s);
}
}
{
eat(T_extern);
- source_position_t const pos = *HERE;
- char const *const linkage = parse_string_literals(NULL).begin;
+ position_t const pos = *HERE;
+ char const *const linkage = parse_string_literals(NULL).begin;
linkage_kind_t old_linkage = current_linkage;
linkage_kind_t new_linkage;
}
current_linkage = new_linkage;
- if (next_if('{')) {
+ if (accept('{')) {
parse_externals();
expect('}');
} else {
{
environment_stack = NEW_ARR_F(stack_entry_t, 0);
label_stack = NEW_ARR_F(stack_entry_t, 0);
- error_count = 0;
- warning_count = 0;
print_to_file(stderr);
if (!is_type_incomplete(type))
continue;
- source_position_t const *const pos = &decl->base.source_position;
+ position_t const *const pos = &decl->base.pos;
warningf(WARN_OTHER, pos, "array '%#N' assumed to have one element", (entity_t const*)decl);
type_t *const new_type = duplicate_type(type);
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");
entity_t *subsubmain_ent
- = create_implicit_function(symbol, &builtin_source_position);
+ = create_implicit_function(symbol, &builtin_position);
- expression_t *ref = allocate_expression_zero(EXPR_REFERENCE);
- type_t *ftype = subsubmain_ent->declaration.type;
- ref->base.source_position = builtin_source_position;
- ref->base.type = make_pointer_type(ftype, TYPE_QUALIFIER_NONE);
- ref->reference.entity = subsubmain_ent;
+ expression_t *ref = allocate_expression_zero(EXPR_REFERENCE);
+ type_t *ftype = subsubmain_ent->declaration.type;
+ ref->base.pos = builtin_position;
+ ref->base.type = make_pointer_type(ftype, TYPE_QUALIFIER_NONE);
+ ref->reference.entity = subsubmain_ent;
- expression_t *call = allocate_expression_zero(EXPR_CALL);
- call->base.source_position = builtin_source_position;
- call->base.type = type_void;
- call->call.function = ref;
+ expression_t *call = allocate_expression_zero(EXPR_CALL);
+ call->base.pos = builtin_position;
+ call->base.type = type_void;
+ call->call.function = ref;
statement_t *expr_statement = allocate_statement_zero(STATEMENT_EXPRESSION);
- expr_statement->base.source_position = builtin_source_position;
+ expr_statement->base.pos = builtin_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;
*/
void init_parser(void)
{
- sym_anonymous = symbol_table_insert("<anonymous>");
-
memset(token_anchor_set, 0, sizeof(token_anchor_set));
init_expression_parsers();