#include "adt/error.h"
#include "adt/array.h"
-/** if wchar_t is equal to unsigned short. */
-bool opt_short_wchar_t =
-#ifdef _WIN32
- true;
-#else
- false;
-#endif
-
//#define PRINT_TOKENS
#define MAX_LOOKAHEAD 2
typedef struct {
- entity_t *old_entity;
- symbol_t *symbol;
- namespace_t namespc;
+ entity_t *old_entity;
+ symbol_t *symbol;
+ entity_namespace_t namespc;
} stack_entry_t;
typedef struct argument_list_t argument_list_t;
typedef entity_t* (*parsed_declaration_func) (entity_t *declaration, bool is_definition);
/** The current token. */
-static token_t token;
+static token_t token;
/** The lookahead ring-buffer. */
-static token_t lookahead_buffer[MAX_LOOKAHEAD];
+static token_t lookahead_buffer[MAX_LOOKAHEAD];
/** Position of the next token in the lookahead buffer. */
-static int lookahead_bufpos;
-static stack_entry_t *environment_stack = NULL;
-static stack_entry_t *label_stack = NULL;
-static stack_entry_t *local_label_stack = NULL;
-/** The global file scope. */
-static scope_t *file_scope = NULL;
-/** The current scope. */
-static scope_t *scope = NULL;
+static int lookahead_bufpos;
+static stack_entry_t *environment_stack = NULL;
+static stack_entry_t *label_stack = NULL;
+static scope_t *file_scope = NULL;
+static scope_t *current_scope = NULL;
/** Point to the current function declaration if inside a function. */
-static function_t *current_function = NULL;
-static entity_t *current_init_decl = NULL;
-static switch_statement_t *current_switch = NULL;
-static statement_t *current_loop = NULL;
-static statement_t *current_parent = NULL;
-static ms_try_statement_t *current_try = NULL;
-static goto_statement_t *goto_first = NULL;
-static goto_statement_t *goto_last = NULL;
-static label_statement_t *label_first = NULL;
-static label_statement_t *label_last = NULL;
+static function_t *current_function = NULL;
+static entity_t *current_init_decl = NULL;
+static switch_statement_t *current_switch = NULL;
+static statement_t *current_loop = NULL;
+static statement_t *current_parent = NULL;
+static ms_try_statement_t *current_try = NULL;
+static linkage_kind_t current_linkage = LINKAGE_INVALID;
+static goto_statement_t *goto_first = NULL;
+static goto_statement_t **goto_anchor = NULL;
+static label_statement_t *label_first = NULL;
+static label_statement_t **label_anchor = NULL;
/** current translation unit. */
-static translation_unit_t *unit = NULL;
+static translation_unit_t *unit = NULL;
/** true if we are in a type property context (evaluation only for type. */
-static bool in_type_prop = false;
+static bool in_type_prop = false;
/** true in we are in a __extension__ context. */
-static bool in_gcc_extension = false;
-static struct obstack temp_obst;
+static bool in_gcc_extension = false;
+static struct obstack temp_obst;
#define PUSH_PARENT(stmt) \
static expression_t *parse_sub_expression(precedence_t);
static expression_t *parse_expression(void);
static type_t *parse_typename(void);
+static void parse_externals(void);
+static void parse_external(void);
static void parse_compound_type_entries(compound_t *compound_declaration);
static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
case T_register: \
case T___thread:
+#define STORAGE_CLASSES_NO_EXTERN \
+ case T_typedef: \
+ case T_static: \
+ case T_auto: \
+ case T_register: \
+ case T___thread:
+
#define TYPE_QUALIFIERS \
case T_const: \
case T_restrict: \
case T__forceinline: \
case T___attribute__:
-#ifdef PROVIDE_COMPLEX
#define COMPLEX_SPECIFIERS \
case T__Complex:
#define IMAGINARY_SPECIFIERS \
case T__Imaginary:
-#else
-#define COMPLEX_SPECIFIERS
-#define IMAGINARY_SPECIFIERS
-#endif
#define TYPE_SPECIFIERS \
- case T_void: \
+ case T__Bool: \
+ case T___builtin_va_list: \
+ case T___typeof__: \
+ case T__declspec: \
+ case T_bool: \
case T_char: \
- case T_short: \
+ case T_double: \
+ case T_enum: \
+ case T_float: \
case T_int: \
case T_long: \
- case T_float: \
- case T_double: \
+ case T_short: \
case T_signed: \
- case T_unsigned: \
- case T__Bool: \
case T_struct: \
case T_union: \
- case T_enum: \
- case T___typeof__: \
- case T___builtin_va_list: \
- case T__declspec: \
+ case T_unsigned: \
+ case T_void: \
COMPLEX_SPECIFIERS \
IMAGINARY_SPECIFIERS
TYPE_QUALIFIERS \
TYPE_SPECIFIERS
+#define DECLARATION_START_NO_EXTERN \
+ STORAGE_CLASSES_NO_EXTERN \
+ TYPE_QUALIFIERS \
+ TYPE_SPECIFIERS
+
#define TYPENAME_START \
TYPE_QUALIFIERS \
TYPE_SPECIFIERS
case T___func__: \
case T___noop: \
case T__assume: \
- case T_sizeof: \
case T_delete: \
- case T_throw:
+ case T_false: \
+ case T_sizeof: \
+ case T_throw: \
+ case T_true:
/**
* Allocate an AST node with given size and
[ENTITY_ENUM] = sizeof(enum_t),
[ENTITY_ENUM_VALUE] = sizeof(enum_value_t),
[ENTITY_LABEL] = sizeof(label_t),
- [ENTITY_LOCAL_LABEL] = sizeof(label_t)
+ [ENTITY_LOCAL_LABEL] = sizeof(label_t),
+ [ENTITY_NAMESPACE] = sizeof(namespace_t)
};
- assert(kind <= sizeof(sizes) / sizeof(sizes[0]));
+ assert(kind < sizeof(sizes) / sizeof(sizes[0]));
assert(sizes[kind] != 0);
return sizes[kind];
}
[STATEMENT_MS_TRY] = sizeof(ms_try_statement_t),
[STATEMENT_LEAVE] = sizeof(leave_statement_t)
};
- assert(kind <= sizeof(sizes) / sizeof(sizes[0]));
+ assert(kind < sizeof(sizes) / sizeof(sizes[0]));
assert(sizes[kind] != 0);
return sizes[kind];
}
if (kind >= EXPR_BINARY_FIRST && kind <= EXPR_BINARY_LAST) {
return sizes[EXPR_BINARY_FIRST];
}
- assert(kind <= sizeof(sizes) / sizeof(sizes[0]));
+ assert(kind < sizeof(sizes) / sizeof(sizes[0]));
assert(sizes[kind] != 0);
return sizes[kind];
}
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.kind = kind;
+ res->base.type = type_error_type;
+ res->base.source_position = token.source_position;
return res;
}
*/
static expression_t *create_invalid_expression(void)
{
- expression_t *expression = allocate_expression_zero(EXPR_INVALID);
- expression->base.source_position = token.source_position;
- return expression;
+ return allocate_expression_zero(EXPR_INVALID);
}
/**
return ARR_LEN(label_stack);
}
-/**
- * Returns the index of the top element of the local label stack.
- */
-static size_t local_label_top(void)
-{
- return ARR_LEN(local_label_stack);
-}
-
/**
* Return the next token.
*/
next_token();
}
-#define eat(token_type) do { assert(token.type == token_type); next_token(); } while (0)
+#define eat(token_type) do { assert(token.type == (token_type)); next_token(); } while (0)
/**
* Report a parse error because an expected token was not found.
static void scope_push(scope_t *new_scope)
{
- if (scope != NULL) {
- new_scope->depth = scope->depth + 1;
+ if (current_scope != NULL) {
+ new_scope->depth = current_scope->depth + 1;
}
- new_scope->parent = scope;
- scope = new_scope;
+ new_scope->parent = current_scope;
+ current_scope = new_scope;
}
static void scope_pop(void)
{
- scope = scope->parent;
+ current_scope = current_scope->parent;
}
/**
* Search an entity by its symbol in a given namespace.
*/
-static entity_t *get_entity(const symbol_t *const symbol, namespace_t namespc)
+static entity_t *get_entity(const symbol_t *const symbol,
+ namespace_tag_t namespc)
{
entity_t *entity = symbol->entity;
for( ; entity != NULL; entity = entity->base.symbol_next) {
*/
static void stack_push(stack_entry_t **stack_ptr, entity_t *entity)
{
- symbol_t *symbol = entity->base.symbol;
- namespace_t namespc = entity->base.namespc;
+ symbol_t *symbol = entity->base.symbol;
+ entity_namespace_t namespc = entity->base.namespc;
assert(namespc != NAMESPACE_INVALID);
/* replace/add entity into entity list of the symbol */
stack_push(&label_stack, label);
}
-/**
- * Push a declaration of the local label stack.
- *
- * @param declaration the declaration
- */
-static void local_label_push(entity_t *label)
-{
- assert(label->base.parent_scope != NULL);
- label->base.parent_scope = scope;
- stack_push(&local_label_stack, label);
-}
-
/**
* pops symbols from the environment stack until @p new_top is the top element
*/
for(i = top; i > new_top; --i) {
stack_entry_t *entry = &stack[i - 1];
- entity_t *old_entity = entry->old_entity;
- symbol_t *symbol = entry->symbol;
- namespace_t namespc = entry->namespc;
+ entity_t *old_entity = entry->old_entity;
+ symbol_t *symbol = entry->symbol;
+ entity_namespace_t namespc = entry->namespc;
/* replace with old_entity/remove */
entity_t **anchor;
stack_pop_to(&label_stack, new_top);
}
-/**
- * Pop all entries from the local label stack until the new_top
- * is reached.
- *
- * @param new_top the new stack top
- */
-static void local_label_pop_to(size_t new_top)
-{
- stack_pop_to(&local_label_stack, new_top);
-}
-
-
static int get_akind_rank(atomic_type_kind_t akind)
{
return (int) akind;
return parse_sub_expression(PREC_ASSIGNMENT);
}
-static type_t *make_global_typedef(const char *name, type_t *type)
-{
- symbol_t *const symbol = symbol_table_insert(name);
-
- entity_t *const entity = allocate_entity_zero(ENTITY_TYPEDEF);
- entity->base.symbol = symbol;
- entity->base.source_position = builtin_source_position;
- entity->base.namespc = NAMESPACE_NORMAL;
- entity->typedefe.type = type;
- entity->typedefe.builtin = true;
-
- record_entity(entity, false);
-
- type_t *typedef_type = allocate_type_zero(TYPE_TYPEDEF);
- typedef_type->typedeft.typedefe = &entity->typedefe;
-
- return typedef_type;
-}
-
static string_t parse_string_literals(void)
{
assert(token.type == T_STRING_LITERAL);
result = parse_scalar_initializer(type, env->must_be_constant);
}
- /* § 6.7.5 (22) array initializers for arrays with unknown size determine
+ /* § 6.7.8 (22) array initializers for arrays with unknown size determine
* the array type size */
if (is_type_array(type) && type->array.size_expression == NULL
&& result != NULL) {
type_t *new_type = duplicate_type(type);
- new_type->array.size_expression = cnst;
- new_type->array.size_constant = true;
- new_type->array.size = size;
+ new_type->array.size_expression = cnst;
+ new_type->array.size_constant = true;
+ new_type->array.has_implicit_size = true;
+ new_type->array.size = size;
env->type = new_type;
}
symbol = token.v.symbol;
next_token();
- namespace_t const namespc =
+ namespace_tag_t const namespc =
is_struct ? NAMESPACE_STRUCT : NAMESPACE_UNION;
entity_t *entity = get_entity(symbol, namespc);
if (entity != NULL) {
assert(entity->kind == (is_struct ? ENTITY_STRUCT : ENTITY_UNION));
compound = &entity->compound;
- if (compound->base.parent_scope != scope &&
+ if (compound->base.parent_scope != current_scope &&
(token.type == '{' || token.type == ';')) {
/* we're in an inner scope and have a definition. Override
existing definition in outer scope */
(is_struct ? NAMESPACE_STRUCT : NAMESPACE_UNION);
compound->base.source_position = token.source_position;
compound->base.symbol = symbol;
- compound->base.parent_scope = scope;
+ compound->base.parent_scope = current_scope;
if (symbol != NULL) {
environment_push(entity);
}
- append_entity(scope, entity);
+ append_entity(current_scope, entity);
}
if (token.type == '{') {
entity->base.namespc = NAMESPACE_ENUM;
entity->base.source_position = token.source_position;
entity->base.symbol = symbol;
- entity->base.parent_scope = scope;
+ entity->base.parent_scope = current_scope;
}
type_t *const type = allocate_type_zero(TYPE_ENUM);
if (symbol != NULL) {
environment_push(entity);
}
- append_entity(scope, entity);
+ append_entity(current_scope, entity);
entity->enume.complete = true;
parse_enum_entries(type);
entity->base.source_position = *HERE;
entity->base.symbol = symbol;
if (is_declaration(entity)) {
+ entity->declaration.type = type_error_type;
entity->declaration.implicit = true;
+ } else if (kind == ENTITY_TYPEDEF) {
+ entity->typedefe.type = type_error_type;
}
record_entity(entity, false);
return entity;
/* type specifiers */
#define MATCH_SPECIFIER(token, specifier, name) \
case token: \
- next_token(); \
if (type_specifiers & specifier) { \
errorf(HERE, "multiple " name " type specifiers given"); \
} else { \
type_specifiers |= specifier; \
} \
+ next_token(); \
break
- MATCH_SPECIFIER(T_void, SPECIFIER_VOID, "void");
- MATCH_SPECIFIER(T_char, SPECIFIER_CHAR, "char");
- MATCH_SPECIFIER(T_short, SPECIFIER_SHORT, "short");
- MATCH_SPECIFIER(T_int, SPECIFIER_INT, "int");
- MATCH_SPECIFIER(T_float, SPECIFIER_FLOAT, "float");
- MATCH_SPECIFIER(T_double, SPECIFIER_DOUBLE, "double");
- MATCH_SPECIFIER(T_signed, SPECIFIER_SIGNED, "signed");
- MATCH_SPECIFIER(T_unsigned, SPECIFIER_UNSIGNED, "unsigned");
MATCH_SPECIFIER(T__Bool, SPECIFIER_BOOL, "_Bool");
- MATCH_SPECIFIER(T__int8, SPECIFIER_INT8, "_int8");
+ MATCH_SPECIFIER(T__Complex, SPECIFIER_COMPLEX, "_Complex");
+ MATCH_SPECIFIER(T__Imaginary, SPECIFIER_IMAGINARY, "_Imaginary");
+ MATCH_SPECIFIER(T__int128, SPECIFIER_INT128, "_int128");
MATCH_SPECIFIER(T__int16, SPECIFIER_INT16, "_int16");
MATCH_SPECIFIER(T__int32, SPECIFIER_INT32, "_int32");
MATCH_SPECIFIER(T__int64, SPECIFIER_INT64, "_int64");
- MATCH_SPECIFIER(T__int128, SPECIFIER_INT128, "_int128");
- MATCH_SPECIFIER(T__Complex, SPECIFIER_COMPLEX, "_Complex");
- MATCH_SPECIFIER(T__Imaginary, SPECIFIER_IMAGINARY, "_Imaginary");
+ MATCH_SPECIFIER(T__int8, SPECIFIER_INT8, "_int8");
+ MATCH_SPECIFIER(T_bool, SPECIFIER_BOOL, "bool");
+ MATCH_SPECIFIER(T_char, SPECIFIER_CHAR, "char");
+ MATCH_SPECIFIER(T_double, SPECIFIER_DOUBLE, "double");
+ MATCH_SPECIFIER(T_float, SPECIFIER_FLOAT, "float");
+ MATCH_SPECIFIER(T_int, SPECIFIER_INT, "int");
+ MATCH_SPECIFIER(T_short, SPECIFIER_SHORT, "short");
+ MATCH_SPECIFIER(T_signed, SPECIFIER_SIGNED, "signed");
+ MATCH_SPECIFIER(T_unsigned, SPECIFIER_UNSIGNED, "unsigned");
+ MATCH_SPECIFIER(T_void, SPECIFIER_VOID, "void");
case T__forceinline:
/* only in microsoft mode */
break;
case T_long:
- next_token();
if (type_specifiers & SPECIFIER_LONG_LONG) {
errorf(HERE, "multiple type specifiers given");
} else if (type_specifiers & SPECIFIER_LONG) {
} else {
type_specifiers |= SPECIFIER_LONG;
}
+ next_token();
break;
case T_struct: {
{
type_t *type = allocate_type_zero(TYPE_FUNCTION);
+ type->function.linkage = current_linkage;
+
/* TODO: revive this... once we know exactly how to do it */
#if 0
decl_modifiers_t modifiers = entity->declaration.modifiers;
storage_class_t storage_class = specifiers->storage_class;
entity->declaration.declared_storage_class = storage_class;
- if (storage_class == STORAGE_CLASS_NONE && scope != file_scope) {
+ if (storage_class == STORAGE_CLASS_NONE
+ && current_scope != file_scope) {
storage_class = STORAGE_CLASS_AUTO;
}
entity->declaration.storage_class = storage_class;
return strcmp(sym->string, "main") == 0;
}
+static const char *get_entity_kind_name(entity_kind_t kind)
+{
+ switch ((entity_kind_tag_t) kind) {
+ case ENTITY_FUNCTION: return "function";
+ case ENTITY_VARIABLE: return "variable";
+ case ENTITY_COMPOUND_MEMBER: return "compound type member";
+ case ENTITY_STRUCT: return "struct";
+ case ENTITY_UNION: return "union";
+ case ENTITY_ENUM: return "enum";
+ case ENTITY_ENUM_VALUE: return "enum value";
+ case ENTITY_LABEL: return "label";
+ case ENTITY_LOCAL_LABEL: return "local label";
+ case ENTITY_TYPEDEF: return "typedef";
+ case ENTITY_NAMESPACE: return "namespace";
+ case ENTITY_INVALID: break;
+ }
+
+ panic("Invalid entity kind encountered in get_entity_kind_name");
+}
+
+static void error_redefined_as_different_kind(const source_position_t *pos,
+ const entity_t *old, entity_kind_t new_kind)
+{
+ errorf(pos, "redeclaration of %s '%Y' as %s (declared %P)",
+ get_entity_kind_name(old->kind), old->base.symbol,
+ get_entity_kind_name(new_kind), &old->base.source_position);
+}
+
/**
* record entities for the NAMESPACE_NORMAL, and produce error messages/warnings
* for various problems that occur for multiple definitions
static entity_t *record_entity(entity_t *entity, const bool is_definition)
{
const symbol_t *const symbol = entity->base.symbol;
- const namespace_t namespc = entity->base.namespc;
+ const namespace_tag_t namespc = (namespace_tag_t)entity->base.namespc;
const source_position_t *pos = &entity->base.source_position;
assert(symbol != NULL);
orig_type, symbol);
}
- if (warning.main && scope == file_scope && is_sym_main(symbol)) {
+ if (warning.main && current_scope == file_scope
+ && is_sym_main(symbol)) {
check_type_of_main(entity);
}
}
if (is_declaration(entity)) {
if (warning.nested_externs
&& entity->declaration.storage_class == STORAGE_CLASS_EXTERN
- && scope != file_scope) {
+ && current_scope != file_scope) {
warningf(pos, "nested extern declaration of '%#T'",
entity->declaration.type, symbol);
}
if (previous_entity != NULL
&& previous_entity->base.parent_scope == ¤t_function->parameters
- && scope->depth == previous_entity->base.parent_scope->depth + 1) {
+ && current_scope->depth == previous_entity->base.parent_scope->depth+1){
assert(previous_entity->kind == ENTITY_VARIABLE);
errorf(pos,
}
if (previous_entity != NULL
- && previous_entity->base.parent_scope == scope) {
+ && previous_entity->base.parent_scope == current_scope) {
if (previous_entity->kind != entity->kind) {
- errorf(pos,
- "redeclaration of '%Y' as different kind of symbol (declared %P)",
- symbol, &previous_entity->base.source_position);
+ error_redefined_as_different_kind(pos, previous_entity,
+ entity->kind);
goto finish;
}
if (previous_entity->kind == ENTITY_ENUM_VALUE) {
}
} else if (warning.missing_declarations
&& entity->kind == ENTITY_VARIABLE
- && scope == file_scope) {
+ && current_scope == file_scope) {
declaration_t *declaration = &entity->declaration;
if (declaration->storage_class == STORAGE_CLASS_NONE ||
declaration->storage_class == STORAGE_CLASS_THREAD) {
finish:
assert(entity->base.parent_scope == NULL);
- assert(scope != NULL);
+ assert(current_scope != NULL);
- entity->base.parent_scope = scope;
+ entity->base.parent_scope = current_scope;
entity->base.namespc = NAMESPACE_NORMAL;
environment_push(entity);
- append_entity(scope, entity);
+ append_entity(current_scope, entity);
return entity;
}
assert(entity->base.namespc == NAMESPACE_NORMAL);
entity_t *previous_entity = get_entity(symbol, NAMESPACE_NORMAL);
if (previous_entity == NULL
- || previous_entity->base.parent_scope != scope) {
+ || previous_entity->base.parent_scope != current_scope) {
errorf(HERE, "expected declaration of a function parameter, found '%Y'",
symbol);
return entity;
entity_t *parameter = entity->function.parameters.entities;
for ( ; parameter != NULL; parameter = parameter->base.next) {
assert(parameter->base.parent_scope == NULL);
- parameter->base.parent_scope = scope;
+ parameter->base.parent_scope = current_scope;
environment_push(parameter);
}
}
/* pop function parameters */
- assert(scope == &entity->function.parameters);
+ assert(current_scope == &entity->function.parameters);
scope_pop();
environment_pop_to(top);
"label '%Y' used but not defined", label->base.symbol);
}
}
- goto_first = NULL;
- goto_last = NULL;
+ goto_first = NULL;
+ goto_anchor = &goto_first;
if (warning.unused_label) {
for (const label_statement_t *label_statement = label_first;
}
}
}
- label_first = label_last = NULL;
+ label_first = NULL;
+ label_anchor = &label_first;
}
static void warn_unused_decl(entity_t *entity, entity_t *end,
case EXPR_BUILTIN_CONSTANT_P:
case EXPR_BUILTIN_PREFETCH:
case EXPR_OFFSETOF:
+ case EXPR_INVALID:
case EXPR_STATEMENT: // TODO implement
return true;
expression_returns(expr->binary.right);
case EXPR_UNKNOWN:
- case EXPR_INVALID:
break;
}
}
assert(is_declaration(ndeclaration));
- type_t *type = ndeclaration->declaration.type;
+ type_t *type = skip_typeref(ndeclaration->declaration.type);
- /* note that we don't skip typerefs: the standard doesn't allow them here
- * (so we can't use is_type_function here) */
- if (type->kind != TYPE_FUNCTION) {
+ if (!is_type_function(type)) {
if (is_type_valid(type)) {
errorf(HERE, "declarator '%#T' has a body but is not a function type",
type, ndeclaration->base.symbol);
entity_t *parameter = function->parameters.entities;
for( ; parameter != NULL; parameter = parameter->base.next) {
if (parameter->base.parent_scope == &ndeclaration->function.parameters) {
- parameter->base.parent_scope = scope;
+ parameter->base.parent_scope = current_scope;
}
assert(parameter->base.parent_scope == NULL
- || parameter->base.parent_scope == scope);
- parameter->base.parent_scope = scope;
+ || 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");
continue;
label_pop_to(label_stack_top);
}
- assert(scope == &function->parameters);
+ assert(current_scope == &function->parameters);
scope_pop();
environment_pop_to(top);
}
entity->declaration.type = type;
} else {
entity = parse_declarator(specifiers,/*may_be_abstract=*/true, true);
-
- assert(is_declaration(entity));
- type_t *orig_type = entity->declaration.type;
- type_t *type = skip_typeref(orig_type);
+ assert(entity->kind == ENTITY_COMPOUND_MEMBER);
if (token.type == ':') {
source_position_t source_position = *HERE;
next_token();
expression_t *size = parse_constant_expression();
- type_t *bitfield_type = make_bitfield_type(orig_type, size,
+ type_t *type = entity->declaration.type;
+ type_t *bitfield_type = make_bitfield_type(type, size,
&source_position, entity->base.symbol);
entity->declaration.type = bitfield_type;
- } else {
- /* TODO we ignore arrays for now... what is missing is a check
- * that they're at the end of the struct */
- if (is_type_incomplete(type) && !is_type_array(type)) {
- errorf(HERE,
- "compound member '%Y' has incomplete type '%T'",
- entity->base.symbol, orig_type);
- } else if (is_type_function(type)) {
- errorf(HERE, "compound member '%Y' must not have function type '%T'",
- entity->base.symbol, orig_type);
- }
}
}
;
}
+static void semantic_compound(compound_t *compound)
+{
+ entity_t *entity = compound->members.entities;
+ for ( ; entity != NULL; entity = entity->base.next) {
+ assert(entity->kind == ENTITY_COMPOUND_MEMBER);
+
+ type_t *orig_type = entity->declaration.type;
+ type_t *type = skip_typeref(orig_type);
+
+ if (is_type_function(type)) {
+ errorf(HERE,
+ "compound member '%Y' must not have function type '%T'",
+ entity->base.symbol, orig_type);
+ } else if (is_type_incomplete(type)) {
+ /* §6.7.2.1 (16) flexible array member */
+ if (is_type_array(type) && entity->base.next == NULL) {
+ compound->has_flexible_member = true;
+ } else {
+ errorf(HERE,
+ "compound member '%Y' has incomplete type '%T'",
+ entity->base.symbol, orig_type);
+ }
+ }
+ }
+}
+
static void parse_compound_type_entries(compound_t *compound)
{
eat('{');
parse_compound_declarators(compound, &specifiers);
}
+ semantic_compound(compound);
rem_anchor_token('}');
next_token();
}
}
}
+/**
+ * Parse a boolean constant.
+ */
+static expression_t *parse_bool_const(bool value)
+{
+ expression_t *cnst = allocate_expression_zero(EXPR_CONST);
+ cnst->base.type = type_bool;
+ cnst->conste.v.int_value = value;
+
+ next_token();
+
+ return cnst;
+}
+
/**
* Parse an integer constant.
*/
static expression_t *parse_int_const(void)
{
- expression_t *cnst = allocate_expression_zero(EXPR_CONST);
- cnst->base.source_position = *HERE;
- cnst->base.type = token.datatype;
- cnst->conste.v.int_value = token.v.intvalue;
+ expression_t *cnst = allocate_expression_zero(EXPR_CONST);
+ cnst->base.type = token.datatype;
+ cnst->conste.v.int_value = token.v.intvalue;
next_token();
static expression_t *parse_character_constant(void)
{
expression_t *cnst = allocate_expression_zero(EXPR_CHARACTER_CONSTANT);
-
- cnst->base.source_position = *HERE;
- cnst->base.type = token.datatype;
- cnst->conste.v.character = token.v.string;
+ cnst->base.type = token.datatype;
+ cnst->conste.v.character = token.v.string;
if (cnst->conste.v.character.size != 1) {
if (warning.multichar && GNU_MODE) {
static expression_t *parse_wide_character_constant(void)
{
expression_t *cnst = allocate_expression_zero(EXPR_WIDE_CHARACTER_CONSTANT);
-
- cnst->base.source_position = *HERE;
cnst->base.type = token.datatype;
cnst->conste.v.wide_character = token.v.wide_string;
orig_type = entity->declaration.type;
} else if (entity->kind == ENTITY_ENUM_VALUE) {
orig_type = entity->enum_value.enum_type;
+ } else if (entity->kind == ENTITY_TYPEDEF) {
+ errorf(HERE, "encountered typedef name '%Y' while parsing expression",
+ symbol);
+ next_token();
+ return create_invalid_expression();
} else {
panic("expected declaration or enum value in reference");
}
source_position_t source_position = token.source_position;
- type_t *type = parse_typename();
+ type_t *type = parse_typename();
rem_anchor_token(')');
expect(')');
expression_t *expression = allocate_expression_zero(EXPR_STATEMENT);
- statement_t *statement = parse_compound_statement(true);
- expression->statement.statement = statement;
- expression->base.source_position = statement->base.source_position;
+ statement_t *statement = parse_compound_statement(true);
+ expression->statement.statement = statement;
/* find last statement and use its type */
type_t *type = type_void;
static expression_t *parse_function_keyword(void)
{
- next_token();
/* TODO */
if (current_function == NULL) {
expression->base.type = type_char_ptr;
expression->funcname.kind = FUNCNAME_FUNCTION;
+ next_token();
+
return expression;
}
static expression_t *parse_pretty_function_keyword(void)
{
- eat(T___PRETTY_FUNCTION__);
-
if (current_function == NULL) {
errorf(HERE, "'__PRETTY_FUNCTION__' used outside of a function");
}
expression->base.type = type_char_ptr;
expression->funcname.kind = FUNCNAME_PRETTY_FUNCTION;
+ eat(T___PRETTY_FUNCTION__);
+
return expression;
}
static expression_t *parse_funcsig_keyword(void)
{
- eat(T___FUNCSIG__);
-
if (current_function == NULL) {
errorf(HERE, "'__FUNCSIG__' used outside of a function");
}
expression->base.type = type_char_ptr;
expression->funcname.kind = FUNCNAME_FUNCSIG;
+ eat(T___FUNCSIG__);
+
return expression;
}
static expression_t *parse_funcdname_keyword(void)
{
- eat(T___FUNCDNAME__);
-
if (current_function == NULL) {
errorf(HERE, "'__FUNCDNAME__' used outside of a function");
}
expression->base.type = type_char_ptr;
expression->funcname.kind = FUNCNAME_FUNCDNAME;
+ eat(T___FUNCDNAME__);
+
return expression;
}
*/
static expression_t *parse_offsetof(void)
{
- eat(T___builtin_offsetof);
-
expression_t *expression = allocate_expression_zero(EXPR_OFFSETOF);
expression->base.type = type_size_t;
+ eat(T___builtin_offsetof);
+
expect('(');
add_anchor_token(',');
type_t *type = parse_typename();
*/
static expression_t *parse_va_start(void)
{
- eat(T___builtin_va_start);
-
expression_t *expression = allocate_expression_zero(EXPR_VA_START);
+ eat(T___builtin_va_start);
+
expect('(');
add_anchor_token(',');
expression->va_starte.ap = parse_assignment_expression();
*/
static expression_t *parse_va_arg(void)
{
- eat(T___builtin_va_arg);
-
expression_t *expression = allocate_expression_zero(EXPR_VA_ARG);
+ eat(T___builtin_va_arg);
+
expect('(');
expression->va_arge.ap = parse_assignment_expression();
expect(',');
*/
static expression_t *parse_builtin_constant(void)
{
- eat(T___builtin_constant_p);
-
expression_t *expression = allocate_expression_zero(EXPR_BUILTIN_CONSTANT_P);
+ eat(T___builtin_constant_p);
+
expect('(');
add_anchor_token(')');
expression->builtin_constant.value = parse_assignment_expression();
*/
static expression_t *parse_builtin_prefetch(void)
{
- eat(T___builtin_prefetch);
-
expression_t *expression = allocate_expression_zero(EXPR_BUILTIN_PREFETCH);
+ eat(T___builtin_prefetch);
+
expect('(');
add_anchor_token(')');
expression->builtin_prefetch.adr = parse_assignment_expression();
*/
static expression_t *parse_builtin_expect(void)
{
- eat(T___builtin_expect);
-
expression_t *expression
= allocate_expression_zero(EXPR_BINARY_BUILTIN_EXPECT);
+ eat(T___builtin_expect);
+
expect('(');
expression->binary.left = parse_assignment_expression();
expect(',');
*/
static expression_t *parse_assume(void)
{
- eat(T__assume);
+ expression_t *expression = allocate_expression_zero(EXPR_UNARY_ASSUME);
- expression_t *expression
- = allocate_expression_zero(EXPR_UNARY_ASSUME);
+ eat(T__assume);
expect('(');
add_anchor_token(')');
entity_t *label;
assert(current_function != NULL);
- label = get_entity(symbol, NAMESPACE_LOCAL_LABEL);
+ label = get_entity(symbol, NAMESPACE_LABEL);
/* if we found a local label, we already created the declaration */
if (label != NULL && label->kind == ENTITY_LOCAL_LABEL) {
- if (label->base.parent_scope != scope) {
- assert(label->base.parent_scope->depth < scope->depth);
+ if (label->base.parent_scope != current_scope) {
+ assert(label->base.parent_scope->depth < current_scope->depth);
current_function->goto_to_outer = true;
}
return &label->label;
*/
static expression_t *parse_noop_expression(void)
{
- source_position_t source_position = *HERE;
+ /* the result is a (int)0 */
+ expression_t *cnst = allocate_expression_zero(EXPR_CONST);
+ cnst->base.type = type_int;
+ cnst->conste.v.int_value = 0;
+ cnst->conste.is_ms_noop = true;
+
eat(T___noop);
if (token.type == '(') {
rem_anchor_token(')');
expect(')');
- /* the result is a (int)0 */
- expression_t *cnst = allocate_expression_zero(EXPR_CONST);
- cnst->base.source_position = source_position;
- cnst->base.type = type_int;
- cnst->conste.v.int_value = 0;
- cnst->conste.is_ms_noop = true;
-
- return cnst;
-
end_error:
- return create_invalid_expression();
+ return cnst;
}
/**
static expression_t *parse_primary_expression(void)
{
switch (token.type) {
+ case T_false: return parse_bool_const(false);
+ case T_true: return parse_bool_const(true);
case T_INTEGER: return parse_int_const();
case T_CHARACTER_CONSTANT: return parse_character_constant();
case T_WIDE_CHARACTER_CONSTANT: return parse_wide_character_constant();
static expression_t *parse_array_expression(expression_t *left)
{
+ expression_t *expression = allocate_expression_zero(EXPR_ARRAY_ACCESS);
+
eat('[');
add_anchor_token(']');
expression_t *inside = parse_expression();
- expression_t *expression = allocate_expression_zero(EXPR_ARRAY_ACCESS);
-
- array_access_expression_t *array_access = &expression->array_access;
-
type_t *const orig_type_left = left->base.type;
type_t *const orig_type_inside = inside->base.type;
type_t *const type_left = skip_typeref(orig_type_left);
type_t *const type_inside = skip_typeref(orig_type_inside);
- type_t *return_type;
+ type_t *return_type;
+ array_access_expression_t *array_access = &expression->array_access;
if (is_type_pointer(type_left)) {
return_type = type_left->pointer.points_to;
array_access->array_ref = left;
expression->base.type = automatic_type_conversion(return_type);
rem_anchor_token(']');
- if (token.type == ']') {
- next_token();
- } else {
- parse_error_expected("Problem while parsing array access", ']', NULL);
- }
+ expect(']');
+end_error:
return expression;
}
-static expression_t *parse_typeprop(expression_kind_t const kind,
- source_position_t const pos)
+static expression_t *parse_typeprop(expression_kind_t const kind)
{
expression_t *tp_expression = allocate_expression_zero(kind);
- tp_expression->base.type = type_size_t;
- tp_expression->base.source_position = pos;
+ tp_expression->base.type = type_size_t;
+
+ eat(kind == EXPR_SIZEOF ? T_sizeof : T___alignof__);
char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
type->kind == TYPE_BITFIELD ? "bitfield" :
NULL;
if (wrong_type != NULL) {
- errorf(&pos, "operand of %s expression must not be of %s type '%T'",
+ errorf(&tp_expression->base.source_position,
+ "operand of %s expression must not be of %s type '%T'",
what, wrong_type, orig_type);
}
static expression_t *parse_sizeof(void)
{
- source_position_t pos = *HERE;
- eat(T_sizeof);
- return parse_typeprop(EXPR_SIZEOF, pos);
+ return parse_typeprop(EXPR_SIZEOF);
}
static expression_t *parse_alignof(void)
{
- source_position_t pos = *HERE;
- eat(T___alignof__);
- return parse_typeprop(EXPR_ALIGNOF, pos);
+ return parse_typeprop(EXPR_ALIGNOF);
}
static expression_t *parse_select_expression(expression_t *compound)
{
- assert(token.type == '.' || token.type == T_MINUSGREATER);
+ expression_t *select = allocate_expression_zero(EXPR_SELECT);
+ select->select.compound = compound;
+ assert(token.type == '.' || token.type == T_MINUSGREATER);
bool is_pointer = (token.type == T_MINUSGREATER);
next_token();
- expression_t *select = allocate_expression_zero(EXPR_SELECT);
- select->select.compound = compound;
-
if (token.type != T_IDENTIFIER) {
parse_error_expected("while parsing select", T_IDENTIFIER, NULL);
return select;
*/
static expression_t *parse_call_expression(expression_t *expression)
{
- expression_t *result = allocate_expression_zero(EXPR_CALL);
- result->base.source_position = expression->base.source_position;
-
- call_expression_t *call = &result->call;
- call->function = expression;
+ expression_t *result = allocate_expression_zero(EXPR_CALL);
+ call_expression_t *call = &result->call;
+ call->function = expression;
type_t *const orig_type = expression->base.type;
type_t *const type = skip_typeref(orig_type);
type1->compound.compound == type2->compound.compound;
}
+static expression_t const *get_reference_address(expression_t const *expr)
+{
+ bool regular_take_address = true;
+ for (;;) {
+ if (expr->kind == EXPR_UNARY_TAKE_ADDRESS) {
+ expr = expr->unary.value;
+ } else {
+ regular_take_address = false;
+ }
+
+ if (expr->kind != EXPR_UNARY_DEREFERENCE)
+ break;
+
+ expr = expr->unary.value;
+ }
+
+ if (expr->kind != EXPR_REFERENCE)
+ return NULL;
+
+ /* special case for functions which are automatically converted to a
+ * pointer to function without an extra TAKE_ADDRESS operation */
+ if (!regular_take_address &&
+ expr->reference.entity->kind != ENTITY_FUNCTION) {
+ return NULL;
+ }
+
+ return expr;
+}
+
+static void warn_reference_address_as_bool(expression_t const* expr)
+{
+ if (!warning.address)
+ return;
+
+ expr = get_reference_address(expr);
+ if (expr != NULL) {
+ warningf(&expr->base.source_position,
+ "the address of '%Y' will always evaluate as 'true'",
+ expr->reference.entity->base.symbol);
+ }
+}
+
/**
* Parse a conditional expression, ie. 'expression ? ... : ...'.
*
expression_t *result = allocate_expression_zero(EXPR_CONDITIONAL);
conditional_expression_t *conditional = &result->conditional;
- conditional->base.source_position = *HERE;
- conditional->condition = expression;
+ conditional->condition = expression;
+
+ warn_reference_address_as_bool(expression);
eat('?');
add_anchor_token(':');
*/
static expression_t *parse_builtin_classify_type(void)
{
- eat(T___builtin_classify_type);
-
expression_t *result = allocate_expression_zero(EXPR_CLASSIFY_TYPE);
result->base.type = type_int;
+ eat(T___builtin_classify_type);
+
expect('(');
add_anchor_token(')');
expression_t *expression = parse_expression();
static expression_t *parse_delete(void)
{
expression_t *const result = allocate_expression_zero(EXPR_UNARY_DELETE);
- result->base.source_position = *HERE;
- result->base.type = type_void;
+ result->base.type = type_void;
eat(T_delete);
static expression_t *parse_throw(void)
{
expression_t *const result = allocate_expression_zero(EXPR_UNARY_THROW);
- result->base.source_position = *HERE;
- result->base.type = type_void;
+ result->base.type = type_void;
eat(T_throw);
"traditional C rejects the unary plus operator");
}
-static expression_t const *get_reference_address(expression_t const *expr)
-{
- bool regular_take_address = true;
- for (;;) {
- if (expr->kind == EXPR_UNARY_TAKE_ADDRESS) {
- expr = expr->unary.value;
- } else {
- regular_take_address = false;
- }
-
- if (expr->kind != EXPR_UNARY_DEREFERENCE)
- break;
-
- expr = expr->unary.value;
- }
-
- /* special case for functions which are automatically converted to a
- * pointer to function without an extra TAKE_ADDRESS operation */
- if (!regular_take_address && expr->kind == EXPR_REFERENCE
- && expr->reference.entity->kind == ENTITY_FUNCTION) {
- return expr;
- }
-
- return NULL;
-}
-
-static void warn_function_address_as_bool(expression_t const* expr)
-{
- if (!warning.address)
- return;
-
- expr = get_reference_address(expr);
- if (expr != NULL) {
- warningf(&expr->base.source_position,
- "the address of '%Y' will always evaluate as 'true'",
- expr->reference.entity->base.symbol);
- }
-}
-
static void semantic_not(unary_expression_t *expression)
{
type_t *const orig_type = expression->value->base.type;
"operand of ! must be of scalar type");
}
- warn_function_address_as_bool(expression->value);
+ warn_reference_address_as_bool(expression->value);
- expression->base.type = type_int;
+ expression->base.type = c_mode & _CXX ? type_bool : type_int;
}
static void semantic_unexpr_integer(unary_expression_t *expression)
return;
/* §6.5.3.2 */
- if (value->kind != EXPR_ARRAY_ACCESS
- && value->kind != EXPR_UNARY_DEREFERENCE
- && !is_lvalue(value)) {
- errorf(&expression->base.source_position,
- "'&' requires an lvalue");
+ if (!is_lvalue(value)) {
+ errorf(&expression->base.source_position, "'&' requires an lvalue");
}
if (type->kind == TYPE_BITFIELD) {
errorf(&expression->base.source_position,
{ \
expression_t *unary_expression \
= allocate_expression_zero(unexpression_type); \
- unary_expression->base.source_position = *HERE; \
eat(token_type); \
unary_expression->unary.value = parse_sub_expression(PREC_UNARY); \
\
{ \
expression_t *unary_expression \
= allocate_expression_zero(unexpression_type); \
- unary_expression->base.source_position = *HERE; \
eat(token_type); \
- unary_expression->unary.value = left; \
+ unary_expression->unary.value = left; \
\
sfunc(&unary_expression->unary); \
\
&expression->base.source_position,
type_left, type_right);
}
- expression->base.type = type_int;
+ expression->base.type = c_mode & _CXX ? type_bool : type_int;
}
/**
type_t *const type_left = skip_typeref(orig_type_left);
type_t *const type_right = skip_typeref(orig_type_right);
- warn_function_address_as_bool(left);
- warn_function_address_as_bool(right);
+ warn_reference_address_as_bool(left);
+ warn_reference_address_as_bool(right);
if (!is_type_scalar(type_left) || !is_type_scalar(type_right)) {
/* TODO: improve error message */
return;
}
- expression->base.type = type_int;
+ expression->base.type = c_mode & _CXX ? type_bool : type_int;
}
/**
static expression_t *parse_##binexpression_type(expression_t *left) \
{ \
expression_t *binexpr = allocate_expression_zero(binexpression_type); \
- binexpr->base.source_position = *HERE; \
- binexpr->binary.left = left; \
+ binexpr->binary.left = left; \
eat(token_type); \
\
expression_t *right = parse_sub_expression(prec_r); \
*/
static asm_argument_t *parse_asm_arguments(bool is_out)
{
- asm_argument_t *result = NULL;
- asm_argument_t *last = NULL;
+ asm_argument_t *result = NULL;
+ asm_argument_t **anchor = &result;
while (token.type == T_STRING_LITERAL || token.type == '[') {
asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0]));
set_address_taken(expression, true);
- if (last != NULL) {
- last->next = argument;
- } else {
- result = argument;
- }
- last = argument;
+ *anchor = argument;
+ anchor = &argument->next;
if (token.type != ',')
break;
}
/* remember the labels in a list for later checking */
- if (label_last == NULL) {
- label_first = &statement->label;
- } else {
- label_last->next = &statement->label;
- }
- label_last = &statement->label;
+ *label_anchor = &statement->label;
+ label_anchor = &statement->label.next;
POP_PARENT;
return statement;
add_anchor_token(')');
expression_t *const expr = parse_expression();
statement->ifs.condition = expr;
+ warn_reference_address_as_bool(expr);
mark_vars_read(expr, NULL);
rem_anchor_token(')');
expect(')');
add_anchor_token(')');
expression_t *const cond = parse_expression();
statement->whiles.condition = cond;
+ warn_reference_address_as_bool(cond);
mark_vars_read(cond, NULL);
rem_anchor_token(')');
expect(')');
add_anchor_token(')');
expression_t *const cond = parse_expression();
statement->do_while.condition = cond;
+ warn_reference_address_as_bool(cond);
mark_vars_read(cond, NULL);
rem_anchor_token(')');
expect(')');
add_anchor_token(';');
expression_t *const cond = parse_expression();
statement->fors.condition = cond;
+ warn_reference_address_as_bool(cond);
mark_vars_read(cond, NULL);
rem_anchor_token(';');
}
rem_anchor_token(')');
statement->fors.body = parse_loop_body(statement);
- assert(scope == &statement->fors.scope);
+ assert(current_scope == &statement->fors.scope);
scope_pop();
environment_pop_to(top);
end_error:
POP_PARENT;
rem_anchor_token(')');
- assert(scope == &statement->fors.scope);
+ assert(current_scope == &statement->fors.scope);
scope_pop();
environment_pop_to(top);
expression_t *expression = parse_expression();
mark_vars_read(expression, NULL);
- /* Argh: although documentation say the expression must be of type void *,
- * gcc excepts anything that can be casted into void * without error */
+ /* Argh: although documentation says the expression must be of type void*,
+ * gcc accepts anything that can be casted into void* without error */
type_t *type = expression->base.type;
if (type != type_error_type) {
}
/* remember the goto's in a list for later checking */
- if (goto_last == NULL) {
- goto_first = &statement->gotos;
- } else {
- goto_last->next = &statement->gotos;
- }
- goto_last = &statement->gotos;
+ *goto_anchor = &statement->gotos;
+ goto_anchor = &statement->gotos.next;
expect(';');
mark_vars_read(return_value, NULL);
}
- const type_t *const func_type = current_function->base.type;
+ const type_t *const func_type = skip_typeref(current_function->base.type);
assert(is_type_function(func_type));
type_t *const return_type = skip_typeref(func_type->function.return_type);
{
statement_t *statement = allocate_statement_zero(STATEMENT_DECLARATION);
- entity_t *before = scope->last_entity;
+ entity_t *before = current_scope->last_entity;
if (GNU_MODE)
parse_external_declaration();
else
parse_declaration(record_entity);
if (before == NULL) {
- statement->declaration.declarations_begin = scope->entities;
+ statement->declaration.declarations_begin = current_scope->entities;
} else {
statement->declaration.declarations_begin = before->base.next;
}
- statement->declaration.declarations_end = scope->last_entity;
+ statement->declaration.declarations_end = current_scope->last_entity;
return statement;
}
goto end_error;
}
symbol_t *symbol = token.v.symbol;
- entity_t *entity = get_entity(symbol, NAMESPACE_LOCAL_LABEL);
- if (entity != NULL) {
+ entity_t *entity = get_entity(symbol, NAMESPACE_LABEL);
+ if (entity != NULL && entity->base.parent_scope == current_scope) {
errorf(HERE, "multiple definitions of '__label__ %Y' (previous definition %P)",
symbol, &entity->base.source_position);
} else {
entity = allocate_entity_zero(ENTITY_LOCAL_LABEL);
- entity->base.parent_scope = scope;
- entity->base.namespc = NAMESPACE_LOCAL_LABEL;
+ entity->base.parent_scope = current_scope;
+ entity->base.namespc = NAMESPACE_LABEL;
entity->base.source_position = token.source_position;
entity->base.symbol = symbol;
if (begin == NULL)
begin = entity;
- local_label_push(entity);
+ environment_push(entity);
}
next_token();
return statement;
}
+static void parse_namespace_definition(void)
+{
+ eat(T_namespace);
+
+ entity_t *entity = NULL;
+ symbol_t *symbol = NULL;
+
+ if (token.type == T_IDENTIFIER) {
+ symbol = token.v.symbol;
+ next_token();
+
+ entity = get_entity(symbol, NAMESPACE_NORMAL);
+ if (entity != NULL && entity->kind != ENTITY_NAMESPACE
+ && entity->base.parent_scope == current_scope) {
+ error_redefined_as_different_kind(&token.source_position,
+ entity, ENTITY_NAMESPACE);
+ entity = NULL;
+ }
+ }
+
+ if (entity == NULL) {
+ entity = allocate_entity_zero(ENTITY_NAMESPACE);
+ entity->base.symbol = symbol;
+ entity->base.source_position = token.source_position;
+ entity->base.namespc = NAMESPACE_NORMAL;
+ entity->base.parent_scope = current_scope;
+ }
+
+ if (token.type == '=') {
+ /* TODO: parse namespace alias */
+ panic("namespace alias definition not supported yet");
+ }
+
+ environment_push(entity);
+ append_entity(current_scope, entity);
+
+ size_t const top = environment_top();
+ scope_push(&entity->namespacee.members);
+
+ expect('{');
+ parse_externals();
+ expect('}');
+
+end_error:
+ assert(current_scope == &entity->namespacee.members);
+ scope_pop();
+ environment_pop_to(top);
+}
+
/**
* Parse a statement.
* There's also parse_statement() which additionally checks for
statement = parse_local_label_declaration();
break;
- case ';': statement = parse_empty_statement(); break;
- case '{': statement = parse_compound_statement(false); break;
- case T___leave: statement = parse_leave_statement(); break;
- case T___try: statement = parse_ms_try_statment(); break;
- case T_asm: statement = parse_asm_statement(); break;
- case T_break: statement = parse_break(); break;
- case T_case: statement = parse_case_statement(); break;
- case T_continue: statement = parse_continue(); break;
- case T_default: statement = parse_default_statement(); break;
- case T_do: statement = parse_do(); break;
- case T_for: statement = parse_for(); break;
- case T_goto: statement = parse_goto(); break;
- case T_if: statement = parse_if(); break;
- case T_return: statement = parse_return(); break;
- case T_switch: statement = parse_switch(); break;
- case T_while: statement = parse_while(); break;
+ case ';': statement = parse_empty_statement(); break;
+ case '{': statement = parse_compound_statement(false); break;
+ case T___leave: statement = parse_leave_statement(); break;
+ case T___try: statement = parse_ms_try_statment(); break;
+ case T_asm: statement = parse_asm_statement(); break;
+ case T_break: statement = parse_break(); break;
+ case T_case: statement = parse_case_statement(); break;
+ case T_continue: statement = parse_continue(); break;
+ case T_default: statement = parse_default_statement(); break;
+ case T_do: statement = parse_do(); break;
+ case T_for: statement = parse_for(); break;
+ case T_goto: statement = parse_goto(); break;
+ case T_if: statement = parse_if(); break;
+ case T_return: statement = parse_return(); break;
+ case T_switch: statement = parse_switch(); break;
+ case T_while: statement = parse_while(); break;
EXPRESSION_START
statement = parse_expression_statement();
eat('{');
add_anchor_token('}');
- size_t const top = environment_top();
- size_t const top_local = local_label_top();
+ size_t const top = environment_top();
scope_push(&statement->compound.scope);
statement_t **anchor = &statement->compound.statements;
end_error:
rem_anchor_token('}');
- assert(scope == &statement->compound.scope);
+ assert(current_scope == &statement->compound.scope);
scope_pop();
environment_pop_to(top);
- local_label_pop_to(top_local);
POP_PARENT;
return statement;
}
-/**
- * Initialize builtin types.
- */
-static void initialize_builtin_types(void)
-{
- type_intmax_t = make_global_typedef("__intmax_t__", type_long_long);
- type_size_t = make_global_typedef("__SIZE_TYPE__", type_unsigned_long);
- type_ssize_t = make_global_typedef("__SSIZE_TYPE__", type_long);
- type_ptrdiff_t = make_global_typedef("__PTRDIFF_TYPE__", type_long);
- type_uintmax_t = make_global_typedef("__uintmax_t__", type_unsigned_long_long);
- type_uptrdiff_t = make_global_typedef("__UPTRDIFF_TYPE__", type_unsigned_long);
- type_wchar_t = make_global_typedef("__WCHAR_TYPE__", opt_short_wchar_t ? type_unsigned_short : type_int);
- type_wint_t = make_global_typedef("__WINT_TYPE__", type_int);
-
- type_intmax_t_ptr = make_pointer_type(type_intmax_t, TYPE_QUALIFIER_NONE);
- type_ptrdiff_t_ptr = make_pointer_type(type_ptrdiff_t, TYPE_QUALIFIER_NONE);
- type_ssize_t_ptr = make_pointer_type(type_ssize_t, TYPE_QUALIFIER_NONE);
- type_wchar_t_ptr = make_pointer_type(type_wchar_t, TYPE_QUALIFIER_NONE);
-
- /* const version of wchar_t */
- type_const_wchar_t = allocate_type_zero(TYPE_TYPEDEF);
- type_const_wchar_t->typedeft.typedefe = type_wchar_t->typedeft.typedefe;
- type_const_wchar_t->base.qualifiers |= TYPE_QUALIFIER_CONST;
-
- type_const_wchar_t_ptr = make_pointer_type(type_const_wchar_t, TYPE_QUALIFIER_NONE);
-}
-
/**
* Check for unused global static functions and variables
*/
end_error:;
}
-/**
- * Parse a translation unit.
- */
-static void parse_translation_unit(void)
+static void parse_linkage_specification(void)
+{
+ eat(T_extern);
+ assert(token.type == T_STRING_LITERAL);
+
+ const char *linkage = parse_string_literals().begin;
+
+ linkage_kind_t old_linkage = current_linkage;
+ linkage_kind_t new_linkage;
+ if (strcmp(linkage, "C") == 0) {
+ new_linkage = LINKAGE_C;
+ } else if (strcmp(linkage, "C++") == 0) {
+ new_linkage = LINKAGE_CXX;
+ } else {
+ errorf(HERE, "linkage string \"%s\" not recognized", linkage);
+ new_linkage = LINKAGE_INVALID;
+ }
+ current_linkage = new_linkage;
+
+ if (token.type == '{') {
+ next_token();
+ parse_externals();
+ expect('}');
+ } else {
+ parse_external();
+ }
+
+end_error:
+ assert(current_linkage == new_linkage);
+ current_linkage = old_linkage;
+}
+
+static void parse_external(void)
+{
+ switch (token.type) {
+ DECLARATION_START_NO_EXTERN
+ case T_IDENTIFIER:
+ case T___extension__:
+ case '(': /* for function declarations with implicit return type and
+ * parenthesized declarator, i.e. (f)(void); */
+ parse_external_declaration();
+ return;
+
+ case T_extern:
+ if (look_ahead(1)->type == T_STRING_LITERAL) {
+ parse_linkage_specification();
+ } else {
+ parse_external_declaration();
+ }
+ return;
+
+ case T_asm:
+ parse_global_asm();
+ return;
+
+ case T_namespace:
+ parse_namespace_definition();
+ return;
+
+ case ';':
+ if (!strict_mode) {
+ if (warning.other)
+ warningf(HERE, "stray ';' outside of function");
+ next_token();
+ return;
+ }
+ /* FALLTHROUGH */
+
+ default:
+ errorf(HERE, "stray %K outside of function", &token);
+ if (token.type == '(' || token.type == '{' || token.type == '[')
+ eat_until_matching_token(token.type);
+ next_token();
+ return;
+ }
+}
+
+static void parse_externals(void)
{
+ add_anchor_token('}');
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 (;;) {
+
+ while (token.type != T_EOF && token.type != '}') {
#ifndef NDEBUG
bool anchor_leak = false;
for (int i = 0; i != T_LAST_TOKEN; ++i) {
abort();
#endif
- switch (token.type) {
- DECLARATION_START
- case T_IDENTIFIER:
- case T___extension__:
- parse_external_declaration();
- break;
+ parse_external();
+ }
- case T_asm:
- parse_global_asm();
- break;
+ rem_anchor_token(T_EOF);
+ rem_anchor_token('}');
+}
- case T_EOF:
- rem_anchor_token(T_EOF);
- return;
+/**
+ * Parse a translation unit.
+ */
+static void parse_translation_unit(void)
+{
+ add_anchor_token(T_EOF);
- case ';':
- if (!strict_mode) {
- if (warning.other)
- warningf(HERE, "stray ';' outside of function");
- next_token();
- break;
- }
- /* FALLTHROUGH */
+ while (true) {
+ parse_externals();
- default:
- errorf(HERE, "stray %K outside of function", &token);
- if (token.type == '(' || token.type == '{' || token.type == '[')
- eat_until_matching_token(token.type);
- next_token();
- break;
- }
+ if (token.type == T_EOF)
+ break;
+
+ errorf(HERE, "stray %K outside of function", &token);
+ if (token.type == '(' || token.type == '{' || token.type == '[')
+ eat_until_matching_token(token.type);
+ next_token();
}
}
{
environment_stack = NEW_ARR_F(stack_entry_t, 0);
label_stack = NEW_ARR_F(stack_entry_t, 0);
- local_label_stack = NEW_ARR_F(stack_entry_t, 0);
diagnostic_count = 0;
error_count = 0;
warning_count = 0;
assert(file_scope == NULL);
file_scope = &unit->scope;
- assert(scope == NULL);
+ assert(current_scope == NULL);
scope_push(&unit->scope);
-
- initialize_builtin_types();
}
translation_unit_t *finish_parsing(void)
{
/* do NOT use scope_pop() here, this will crash, will it by hand */
- assert(scope == &unit->scope);
- scope = NULL;
+ assert(current_scope == &unit->scope);
+ current_scope = NULL;
assert(file_scope == &unit->scope);
check_unused_globals();
DEL_ARR_F(environment_stack);
DEL_ARR_F(label_stack);
- DEL_ARR_F(local_label_stack);
translation_unit_t *result = unit;
unit = NULL;
for (int i = 0; i < MAX_LOOKAHEAD + 2; ++i) {
next_token();
}
+ current_linkage = c_mode & _CXX ? LINKAGE_CXX : LINKAGE_C;
parse_translation_unit();
}