static stack_entry_t *label_stack = NULL;
static stack_entry_t *local_label_stack = NULL;
/** The global file scope. */
-static scope_t *global_scope = NULL;
+static scope_t *file_scope = NULL;
/** The current scope. */
static scope_t *scope = NULL;
static declaration_t *last_declaration = NULL;
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.kind = kind;
+ res->base.parent = current_parent;
+ res->base.source_position = token.source_position;
return res;
}
*/
static statement_t *create_invalid_statement(void)
{
- statement_t *statement = allocate_statement_zero(STATEMENT_INVALID);
- statement->base.source_position = token.source_position;
- return statement;
+ return allocate_statement_zero(STATEMENT_INVALID);
}
/**
*/
static statement_t *create_empty_statement(void)
{
- statement_t *statement = allocate_statement_zero(STATEMENT_EMPTY);
- statement->base.source_position = token.source_position;
- return statement;
+ return allocate_statement_zero(STATEMENT_EMPTY);
}
/**
break;
}
- /* Because of scopes and appending other namespaces to the end of
- * the list, this must hold. */
- assert((old_declaration != NULL ? old_declaration->symbol_next : NULL) == iter->symbol_next);
- *anchor = old_declaration;
+ /* Not all declarations adhere scopes (e.g. jump labels), so this
+ * correction is necessary */
+ if (old_declaration != NULL) {
+ old_declaration->symbol_next = iter->symbol_next;
+ *anchor = old_declaration;
+ } else {
+ *anchor = iter->symbol_next;
+ }
}
ARR_SHRINKLEN(*stack_ptr, (int) new_top);
}
switch(kind) {
- case GNU_AK_CONST:
case GNU_AK_VOLATILE:
case GNU_AK_NAKED:
case GNU_AK_MALLOC:
case GNU_AK_UNUSED: modifiers |= DM_UNUSED; goto no_arg;
case GNU_AK_USED: modifiers |= DM_USED; goto no_arg;
case GNU_AK_PURE: modifiers |= DM_PURE; goto no_arg;
+ case GNU_AK_CONST: modifiers |= DM_CONST; goto no_arg;
case GNU_AK_ALWAYS_INLINE: modifiers |= DM_FORCEINLINE; goto no_arg;
case GNU_AK_DLLIMPORT: modifiers |= DM_DLLIMPORT; goto no_arg;
case GNU_AK_DLLEXPORT: modifiers |= DM_DLLEXPORT; goto no_arg;
&expression->base.source_position);
initializer_t *const result = allocate_initializer_zero(INITIALIZER_VALUE);
+#if 0
+ if (type->kind == TYPE_BITFIELD) {
+ type = type->bitfield.base_type;
+ }
+#endif
result->value.value = create_implicit_cast(expression, type);
return result;
"'.%Y' designator used for non-compound type '%T'",
symbol, orig_type);
}
- goto failed;
- }
- declaration_t *declaration = type->compound.declaration;
- declaration_t *iter = declaration->scope.declarations;
- for( ; iter != NULL; iter = iter->next) {
- if (iter->symbol == symbol) {
- break;
+ top->type = type_error_type;
+ top->v.compound_entry = NULL;
+ orig_type = type_error_type;
+ } else {
+ declaration_t *declaration = type->compound.declaration;
+ declaration_t *iter = declaration->scope.declarations;
+ for( ; iter != NULL; iter = iter->next) {
+ if (iter->symbol == symbol) {
+ break;
+ }
}
- }
- if (iter == NULL) {
- errorf(&designator->source_position,
- "'%T' has no member named '%Y'", orig_type, symbol);
- goto failed;
- }
- if (used_in_offsetof) {
- type_t *real_type = skip_typeref(iter->type);
- if (real_type->kind == TYPE_BITFIELD) {
+ if (iter == NULL) {
errorf(&designator->source_position,
- "offsetof designator '%Y' may not specify bitfield",
- symbol);
+ "'%T' has no member named '%Y'", orig_type, symbol);
goto failed;
}
- }
+ if (used_in_offsetof) {
+ type_t *real_type = skip_typeref(iter->type);
+ if (real_type->kind == TYPE_BITFIELD) {
+ errorf(&designator->source_position,
+ "offsetof designator '%Y' may not specify bitfield",
+ symbol);
+ goto failed;
+ }
+ }
- top->type = orig_type;
- top->v.compound_entry = iter;
- orig_type = iter->type;
+ top->type = orig_type;
+ top->v.compound_entry = iter;
+ orig_type = iter->type;
+ }
} else {
expression_t *array_index = designator->array_index;
assert(designator->array_index != NULL);
}
goto failed;
}
- if (!is_type_valid(array_index->base.type)) {
- goto failed;
- }
long index = fold_constant(array_index);
if (!used_in_offsetof) {
if (index < 0) {
errorf(&designator->source_position,
"array index [%E] must be positive", array_index);
- goto failed;
- }
- if (type->array.size_constant == true) {
+ } else if (type->array.size_constant) {
long array_size = type->array.size;
if (index >= array_size) {
errorf(&designator->source_position,
"designator [%E] (%d) exceeds array size %d",
array_index, index, array_size);
- goto failed;
}
}
}
path->top_type = entry->type;
return;
}
- } else {
+ } else if (is_type_array(type)) {
assert(is_type_array(type));
top->v.index++;
if (!type->array.size_constant || top->v.index < type->array.size) {
return;
}
+ } else {
+ assert(!is_type_valid(type));
+ return;
}
/* we're past the last member of the current sub-aggregate, try if we
/* We are initializing an empty compound. */
} else {
type = skip_typeref(orig_type);
-
- /* we can't do usefull stuff if we didn't even parse the type. Skip the
- * initializers in this case. */
- if (!is_type_valid(type)) {
- skip_initializers();
- return create_empty_initializer();
- }
}
initializer_t **initializers = NEW_ARR_F(initializer_t*, 0);
if (type == NULL) {
/* we are already outside, ... */
- if (is_type_compound(outer_type) &&
- !outer_type->compound.declaration->init.complete) {
+ type_t *const outer_type_skip = skip_typeref(outer_type);
+ if (is_type_compound(outer_type_skip) &&
+ !outer_type_skip->compound.declaration->init.complete) {
goto error_parse_next;
}
goto error_excess;
decl->source_position = *HERE;
decl->declared_storage_class = storage_class;
decl->storage_class =
- storage_class != STORAGE_CLASS_NONE || scope == global_scope ?
+ storage_class != STORAGE_CLASS_NONE || scope == file_scope ?
storage_class : STORAGE_CLASS_AUTO;
decl->symbol = symbol;
decl->implicit = true;
type->compound.declaration = parse_compound_type_specifier(false);
if (type->compound.declaration->modifiers & DM_TRANSPARENT_UNION)
modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION;
- break;
finish_union_type(&type->compound);
+ break;
}
case T_enum:
type = parse_enum_specifier();
declaration->is_inline = specifiers->is_inline;
declaration->storage_class = specifiers->declared_storage_class;
- if (declaration->storage_class == STORAGE_CLASS_NONE
- && scope != global_scope) {
+ if (declaration->storage_class == STORAGE_CLASS_NONE &&
+ scope != file_scope) {
declaration->storage_class = STORAGE_CLASS_AUTO;
}
if (warning.nested_externs &&
declaration->storage_class == STORAGE_CLASS_EXTERN &&
- scope != global_scope) {
+ scope != file_scope) {
warningf(&declaration->source_position,
"nested extern declaration of '%#T'", declaration->type, symbol);
}
}
} else {
if (warning.missing_declarations &&
- scope == global_scope && (
+ scope == file_scope && (
declaration->storage_class == STORAGE_CLASS_NONE ||
declaration->storage_class == STORAGE_CLASS_THREAD
)) {
}
bool must_be_constant = false;
- if (declaration->storage_class == STORAGE_CLASS_STATIC
- || declaration->storage_class == STORAGE_CLASS_THREAD_STATIC
- || declaration->parent_scope == global_scope) {
+ if (declaration->storage_class == STORAGE_CLASS_STATIC ||
+ declaration->storage_class == STORAGE_CLASS_THREAD_STATIC ||
+ declaration->parent_scope == file_scope) {
must_be_constant = true;
}
return make_function_1_type(type_void_ptr, type_size_t);
case T___builtin_huge_val:
return make_function_0_type(type_double);
+ case T___builtin_inf:
+ return make_function_0_type(type_double);
+ case T___builtin_inff:
+ return make_function_0_type(type_float);
+ case T___builtin_infl:
+ return make_function_0_type(type_long_double);
case T___builtin_nan:
return make_function_1_type(type_double, type_char_ptr);
case T___builtin_nanf:
return make_function_1_type(type_float, type_char_ptr);
- case T___builtin_nand:
+ case T___builtin_nanl:
return make_function_1_type(type_long_double, type_char_ptr);
case T___builtin_va_end:
return make_function_1_type(type_void, type_valist);
/* this declaration is used */
declaration->used = true;
- if (declaration->parent_scope != global_scope &&
+ if (declaration->parent_scope != file_scope &&
declaration->parent_scope->depth < current_function->scope.depth &&
is_type_valid(orig_type) && !is_type_function(orig_type)) {
/* access of a variable from an outer function */
break;
default:
internal_errorf(HERE, "invalid compare builtin found");
- break;
}
expression->base.source_position = *HERE;
next_token();
case T___builtin_va_arg: return parse_va_arg();
case T___builtin_expect:
case T___builtin_alloca:
+ case T___builtin_inf:
+ case T___builtin_inff:
+ case T___builtin_infl:
case T___builtin_nan:
- case T___builtin_nand:
case T___builtin_nanf:
+ case T___builtin_nanl:
case T___builtin_huge_val:
case T___builtin_va_end: return parse_builtin_symbol();
case T___builtin_isgreater:
return true;
default:
- return false;
+ /* Claim it is an lvalue, if the type is invalid. There was a parse
+ * error before, which maybe prevented properly recognizing it as
+ * lvalue. */
+ return !is_type_valid(skip_typeref(expression->base.type));
}
}
value->base.type = revert_automatic_type_conversion(value);
type_t *orig_type = value->base.type;
- if (!is_type_valid(orig_type))
+ if (!is_type_valid(skip_typeref(orig_type)))
return;
set_address_taken(value, false);
*/
static statement_t *parse_asm_statement(void)
{
- eat(T_asm);
-
- statement_t *statement = allocate_statement_zero(STATEMENT_ASM);
- statement->base.source_position = token.source_position;
-
+ statement_t *statement = allocate_statement_zero(STATEMENT_ASM);
asm_statement_t *asm_statement = &statement->asms;
+ eat(T_asm);
+
if (token.type == T_volatile) {
next_token();
asm_statement->is_volatile = true;
*/
static statement_t *parse_case_statement(void)
{
- eat(T_case);
-
statement_t *const statement = allocate_statement_zero(STATEMENT_CASE_LABEL);
source_position_t *const pos = &statement->base.source_position;
- *pos = token.source_position;
+ eat(T_case);
+
expression_t *const expression = parse_expression();
statement->case_label.expression = expression;
if (!is_constant_expression(expression)) {
/* This check does not prevent the error message in all cases of an
* prior error while parsing the expression. At least it catches the
* common case of a mistyped enum entry. */
- if (is_type_valid(expression->base.type)) {
+ if (is_type_valid(skip_typeref(expression->base.type))) {
errorf(pos, "case label does not reduce to an integer constant");
}
statement->case_label.is_bad = true;
/* This check does not prevent the error message in all cases of an
* prior error while parsing the expression. At least it catches the
* common case of a mistyped enum entry. */
- if (is_type_valid(end_range->base.type)) {
+ if (is_type_valid(skip_typeref(end_range->base.type))) {
errorf(pos, "case range does not reduce to an integer constant");
}
statement->case_label.is_bad = true;
*/
static statement_t *parse_default_statement(void)
{
- eat(T_default);
-
statement_t *statement = allocate_statement_zero(STATEMENT_CASE_LABEL);
- statement->base.source_position = token.source_position;
+
+ eat(T_default);
PUSH_PARENT(statement);
static statement_t *parse_label_statement(void)
{
assert(token.type == T_IDENTIFIER);
- symbol_t *symbol = token.v.symbol;
- next_token();
-
- declaration_t *label = get_label(symbol);
+ symbol_t *symbol = token.v.symbol;
+ declaration_t *label = get_label(symbol);
statement_t *const statement = allocate_statement_zero(STATEMENT_LABEL);
- statement->base.source_position = token.source_position;
- statement->label.label = label;
+ statement->label.label = label;
+
+ next_token();
PUSH_PARENT(statement);
*/
static statement_t *parse_if(void)
{
- eat(T_if);
+ statement_t *statement = allocate_statement_zero(STATEMENT_IF);
- statement_t *statement = allocate_statement_zero(STATEMENT_IF);
- statement->base.source_position = token.source_position;
+ eat(T_if);
PUSH_PARENT(statement);
+ add_anchor_token('{');
+
expect('(');
add_anchor_token(')');
statement->ifs.condition = parse_expression();
rem_anchor_token(')');
expect(')');
+end_error:
+ rem_anchor_token('{');
+
add_anchor_token(T_else);
statement->ifs.true_statement = parse_statement();
rem_anchor_token(T_else);
POP_PARENT;
return statement;
-end_error:
- POP_PARENT;
- return create_invalid_statement();
}
/**
*/
static statement_t *parse_switch(void)
{
- eat(T_switch);
+ statement_t *statement = allocate_statement_zero(STATEMENT_SWITCH);
- statement_t *statement = allocate_statement_zero(STATEMENT_SWITCH);
- statement->base.source_position = token.source_position;
+ eat(T_switch);
PUSH_PARENT(statement);
*/
static statement_t *parse_while(void)
{
- eat(T_while);
+ statement_t *statement = allocate_statement_zero(STATEMENT_WHILE);
- statement_t *statement = allocate_statement_zero(STATEMENT_WHILE);
- statement->base.source_position = token.source_position;
+ eat(T_while);
PUSH_PARENT(statement);
*/
static statement_t *parse_do(void)
{
- eat(T_do);
-
statement_t *statement = allocate_statement_zero(STATEMENT_DO_WHILE);
- statement->base.source_position = token.source_position;
+
+ eat(T_do);
PUSH_PARENT(statement)
*/
static statement_t *parse_for(void)
{
- eat(T_for);
+ statement_t *statement = allocate_statement_zero(STATEMENT_FOR);
- statement_t *statement = allocate_statement_zero(STATEMENT_FOR);
- statement->base.source_position = token.source_position;
+ eat(T_for);
PUSH_PARENT(statement);
*/
static statement_t *parse_goto(void)
{
- source_position_t source_position = token.source_position;
+ statement_t *statement = allocate_statement_zero(STATEMENT_GOTO);
eat(T_goto);
- statement_t *statement;
if (GNU_MODE && token.type == '*') {
next_token();
expression_t *expression = parse_expression();
if (type != type_error_type) {
if (!is_type_pointer(type) && !is_type_integer(type)) {
- errorf(&source_position, "cannot convert to a pointer type");
+ errorf(&expression->base.source_position,
+ "cannot convert to a pointer type");
} else if (type != type_void_ptr) {
- warningf(&source_position,
+ warningf(&expression->base.source_position,
"type of computed goto expression should be 'void*' not '%T'", type);
}
expression = create_implicit_cast(expression, type_void_ptr);
}
- statement = allocate_statement_zero(STATEMENT_GOTO);
- statement->base.source_position = source_position;
- statement->gotos.expression = expression;
+ statement->gotos.expression = expression;
} else {
if (token.type != T_IDENTIFIER) {
if (GNU_MODE)
symbol_t *symbol = token.v.symbol;
next_token();
- statement = allocate_statement_zero(STATEMENT_GOTO);
- statement->base.source_position = source_position;
- statement->gotos.label = get_label(symbol);
+ statement->gotos.label = get_label(symbol);
if (statement->gotos.label->parent_scope->depth < current_function->scope.depth) {
statement->gotos.outer_fkt_jmp = true;
}
statement_t *statement = allocate_statement_zero(STATEMENT_CONTINUE);
- statement->base.source_position = token.source_position;
eat(T_continue);
expect(';');
}
statement_t *statement = allocate_statement_zero(STATEMENT_BREAK);
- statement->base.source_position = token.source_position;
eat(T_break);
expect(';');
}
statement_t *statement = allocate_statement_zero(STATEMENT_LEAVE);
- statement->base.source_position = token.source_position;
eat(T___leave);
expect(';');
*/
static statement_t *parse_return(void)
{
- statement_t *statement = allocate_statement_zero(STATEMENT_RETURN);
- statement->base.source_position = token.source_position;
-
eat(T_return);
+ statement_t *statement = allocate_statement_zero(STATEMENT_RETURN);
+
expression_t *return_value = NULL;
if (token.type != ';') {
return_value = parse_expression();
{
statement_t *statement = allocate_statement_zero(STATEMENT_DECLARATION);
- statement->base.source_position = token.source_position;
-
declaration_t *before = last_declaration;
if (GNU_MODE)
parse_external_declaration();
{
statement_t *statement = allocate_statement_zero(STATEMENT_EXPRESSION);
- statement->base.source_position = token.source_position;
expression_t *const expr = parse_expression();
statement->expression.expression = expr;
static statement_t *parse_ms_try_statment(void)
{
statement_t *statement = allocate_statement_zero(STATEMENT_MS_TRY);
- statement->base.source_position = token.source_position;
eat(T___try);
PUSH_PARENT(statement);
static statement_t *parse_local_label_declaration(void) {
statement_t *statement = allocate_statement_zero(STATEMENT_DECLARATION);
- statement->base.source_position = token.source_position;
eat(T___label__);
case T___builtin_islessequal:
case T___builtin_islessgreater:
case T___builtin_isunordered:
+ case T___builtin_inf:
+ case T___builtin_inff:
+ case T___builtin_infl:
case T___builtin_nan:
- case T___builtin_nand:
case T___builtin_nanf:
+ case T___builtin_nanl:
case T___builtin_offsetof:
case T___builtin_prefetch:
case T___builtin_va_arg:
static statement_t *parse_compound_statement(bool inside_expression_statement)
{
statement_t *statement = allocate_statement_zero(STATEMENT_COMPOUND);
- statement->base.source_position = token.source_position;
PUSH_PARENT(statement);
if (!warning.unused_function && !warning.unused_variable)
return;
- for (const declaration_t *decl = global_scope->declarations; decl != NULL; decl = decl->next) {
+ for (const declaration_t *decl = file_scope->declarations; decl != NULL; decl = decl->next) {
if (decl->used ||
decl->modifiers & DM_UNUSED ||
decl->modifiers & DM_USED ||
static void parse_global_asm(void)
{
+ statement_t *statement = allocate_statement_zero(STATEMENT_ASM);
+
eat(T_asm);
expect('(');
- statement_t *statement = allocate_statement_zero(STATEMENT_ASM);
- statement->base.source_position = token.source_position;
- statement->asms.asm_text = parse_string_literals();
- statement->base.next = unit->global_asm;
- unit->global_asm = statement;
+ statement->asms.asm_text = parse_string_literals();
+ statement->base.next = unit->global_asm;
+ unit->global_asm = statement;
expect(')');
expect(';');
break;
case T_EOF:
+ rem_anchor_token(T_EOF);
return;
case ';':
- /* TODO error in strict mode */
- warningf(HERE, "stray ';' outside of function");
- next_token();
- break;
+ if (!strict_mode) {
+ warningf(HERE, "stray ';' outside of function");
+ next_token();
+ break;
+ }
+ /* FALLTHROUGH */
default:
errorf(HERE, "stray %K outside of function", &token);
break;
}
}
-
- rem_anchor_token(T_EOF);
}
/**
assert(unit == NULL);
unit = allocate_ast_zero(sizeof(unit[0]));
- assert(global_scope == NULL);
- global_scope = &unit->scope;
+ assert(file_scope == NULL);
+ file_scope = &unit->scope;
assert(scope == NULL);
scope_push(&unit->scope);
scope = NULL;
last_declaration = NULL;
- assert(global_scope == &unit->scope);
+ assert(file_scope == &unit->scope);
check_unused_globals();
- global_scope = NULL;
+ file_scope = NULL;
DEL_ARR_F(environment_stack);
DEL_ARR_F(label_stack);