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;
#define PUSH_PARENT(stmt) \
statement_t *const prev_parent = current_parent; \
- current_parent = (stmt);
+ ((void)(current_parent = (stmt)))
#define POP_PARENT ((void)(current_parent = prev_parent))
static source_position_t null_position = { NULL, 0 };
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);
}
/**
*/
static void eat_until_anchor(void)
{
- if (token.type == T_EOF)
- return;
while (token_anchor_set[token.type] == 0) {
if (token.type == '(' || token.type == '{' || token.type == '[')
eat_until_matching_token(token.type);
- if (token.type == T_EOF)
- break;
next_token();
}
}
namespace_t namespc = (namespace_t) declaration->namespc;
/* replace/add declaration into declaration list of the symbol */
- declaration_t *iter = symbol->declaration;
- if (iter == NULL) {
- symbol->declaration = declaration;
- } else {
- declaration_t *iter_last = NULL;
- for( ; iter != NULL; iter_last = iter, iter = iter->symbol_next) {
- /* replace an entry? */
- if (iter->namespc == namespc) {
- if (iter_last == NULL) {
- symbol->declaration = declaration;
- } else {
- iter_last->symbol_next = declaration;
- }
- declaration->symbol_next = iter->symbol_next;
- break;
- }
- }
- if (iter == NULL) {
- assert(iter_last->symbol_next == NULL);
- iter_last->symbol_next = declaration;
+ declaration_t **anchor;
+ declaration_t *iter;
+ for (anchor = &symbol->declaration;; anchor = &iter->symbol_next) {
+ iter = *anchor;
+ if (iter == NULL)
+ break;
+
+ /* replace an entry? */
+ if (iter->namespc == namespc) {
+ declaration->symbol_next = iter->symbol_next;
+ break;
}
}
+ *anchor = declaration;
/* remember old declaration */
stack_entry_t entry;
namespace_t namespc = (namespace_t)entry->namespc;
/* replace/remove declaration */
- declaration_t *declaration = symbol->declaration;
- assert(declaration != NULL);
- if (declaration->namespc == namespc) {
- if (old_declaration == NULL) {
- symbol->declaration = declaration->symbol_next;
- } else {
- symbol->declaration = old_declaration;
- }
- } else {
- declaration_t *iter_last = declaration;
- declaration_t *iter = declaration->symbol_next;
- for( ; iter != NULL; iter_last = iter, iter = iter->symbol_next) {
- /* replace an entry? */
- if (iter->namespc == namespc) {
- assert(iter_last != NULL);
- iter_last->symbol_next = old_declaration;
- if (old_declaration != NULL) {
- old_declaration->symbol_next = iter->symbol_next;
- }
- break;
- }
- }
+ declaration_t **anchor;
+ declaration_t *iter;
+ for (anchor = &symbol->declaration;; anchor = &iter->symbol_next) {
+ iter = *anchor;
assert(iter != NULL);
+ /* replace an entry? */
+ if (iter->namespc == namespc)
+ break;
+ }
+
+ /* 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;
}
}
}
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);
}
assert(declaration != previous_declaration);
if (previous_declaration != NULL &&
- previous_declaration->parent_scope->is_parameter) {
+ previous_declaration->parent_scope->is_parameter &&
+ scope->depth == previous_declaration->parent_scope->depth + 1) {
errorf(&declaration->source_position,
"declaration '%#T' redeclares the parameter '%#T' (declared %P)",
orig_type, symbol, previous_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;
}
add_anchor_token('{');
/* push function parameters */
- int top = environment_top();
+ size_t const top = environment_top();
scope_push(&declaration->scope);
declaration_t *parameter = declaration->scope.declarations;
type = skip_typeref(declaration->type);
/* push function parameters and switch scope */
- int top = environment_top();
+ size_t const top = environment_top();
scope_push(&declaration->scope);
declaration_t *parameter = declaration->scope.declarations;
eat('{');
add_anchor_token('}');
- while (token.type != '}' && token.type != T_EOF) {
+ while (token.type != '}') {
+ if (token.type == T_EOF) {
+ errorf(HERE, "EOF while parsing struct");
+ break;
+ }
declaration_specifiers_t specifiers;
memset(&specifiers, 0, sizeof(specifiers));
parse_declaration_specifiers(&specifiers);
parse_compound_declarators(compound_declaration, &specifiers);
}
rem_anchor_token('}');
-
- if (token.type == T_EOF) {
- errorf(HERE, "EOF while parsing struct");
- }
next_token();
}
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;
- PUSH_PARENT(statement)
+ eat(T_do);
+
+ PUSH_PARENT(statement);
add_anchor_token(T_while);
statement->do_while.body = parse_loop_body(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);
- int top = environment_top();
+ size_t const top = environment_top();
scope_push(&statement->fors.scope);
expect('(');
*/
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);
eat('{');
add_anchor_token('}');
- int top = environment_top();
- int top_local = local_label_top();
+ size_t const top = environment_top();
+ size_t const top_local = local_label_top();
scope_push(&statement->compound.scope);
statement_t **anchor = &statement->compound.statements;
bool only_decls_so_far = true;
- while (token.type != '}' && token.type != T_EOF) {
+ while (token.type != '}') {
+ if (token.type == T_EOF) {
+ errorf(&statement->base.source_position,
+ "EOF while parsing compound statement");
+ break;
+ }
statement_t *sub_statement = intern_parse_statement();
if (is_invalid_statement(sub_statement)) {
/* an error occurred. if we are at an anchor, return */
anchor = &sub_statement->base.next;
}
-
- if (token.type == '}') {
- next_token();
- } else {
- errorf(&statement->base.source_position,
- "end of file while looking for closing '}'");
- }
+ next_token();
/* look over all statements again to produce no effect warnings */
if (warning.unused_value) {
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(';');
*/
static void parse_translation_unit(void)
{
+ add_anchor_token(T_EOF);
+
+#ifndef NDEBUG
+ unsigned char token_anchor_copy[T_LAST_TOKEN];
+ memcpy(token_anchor_copy, token_anchor_set, sizeof(token_anchor_copy));
+#endif
for (;;) {
#ifndef NDEBUG
bool anchor_leak = false;
for (int i = 0; i != T_LAST_TOKEN; ++i) {
- unsigned char count = token_anchor_set[i];
+ unsigned char count = token_anchor_set[i] - token_anchor_copy[i];
if (count != 0) {
errorf(HERE, "Leaked anchor token %k %d times", i, count);
anchor_leak = true;
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);
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);