#include <stdarg.h>
#include <stdbool.h>
+#include "adt/strutil.h"
#include "parser.h"
#include "diagnostic.h"
#include "format_check.h"
static elf_visibility_tag_t default_visibility = ELF_VISIBILITY_DEFAULT;
+#define PUSH_CURRENT_ENTITY(entity) \
+ entity_t *const new_current_entity = (entity); \
+ entity_t *const old_current_entity = current_entity; \
+ ((void)(current_entity = new_current_entity))
+#define POP_CURRENT_ENTITY() (assert(current_entity == new_current_entity), (void)(current_entity = old_current_entity))
+
#define PUSH_PARENT(stmt) \
statement_t *const new_parent = (stmt); \
statement_t *const old_parent = current_parent; \
#define PUSH_SCOPE(scope) \
size_t const top = environment_top(); \
scope_t *const new_scope = (scope); \
- scope_t *const old_scope = scope_push(new_scope)
-#define POP_SCOPE() (assert(current_scope == new_scope), scope_pop(old_scope), environment_pop_to(top))
+ scope_t *const old_scope = (new_scope ? scope_push(new_scope) : NULL)
+#define PUSH_SCOPE_STATEMENT(scope) PUSH_SCOPE(c_mode & (_C99 | _CXX) ? (scope) : NULL)
+#define POP_SCOPE() (new_scope ? assert(current_scope == new_scope), scope_pop(old_scope), environment_pop_to(top) : (void)0)
#define PUSH_EXTENSION() \
(void)0; \
case T_ANDAND: \
case T_CHARACTER_CONSTANT: \
case T_FLOATINGPOINT: \
- case T_FLOATINGPOINT_HEXADECIMAL: \
case T_INTEGER: \
- case T_INTEGER_HEXADECIMAL: \
- case T_INTEGER_OCTAL: \
case T_MINUSMINUS: \
case T_PLUSPLUS: \
case T_STRING_LITERAL: \
static size_t get_statement_struct_size(statement_kind_t kind)
{
static const size_t sizes[] = {
- [STATEMENT_ERROR] = sizeof(statement_base_t),
- [STATEMENT_EMPTY] = sizeof(statement_base_t),
- [STATEMENT_COMPOUND] = sizeof(compound_statement_t),
- [STATEMENT_RETURN] = sizeof(return_statement_t),
- [STATEMENT_DECLARATION] = sizeof(declaration_statement_t),
- [STATEMENT_IF] = sizeof(if_statement_t),
- [STATEMENT_SWITCH] = sizeof(switch_statement_t),
- [STATEMENT_EXPRESSION] = sizeof(expression_statement_t),
- [STATEMENT_CONTINUE] = sizeof(statement_base_t),
- [STATEMENT_BREAK] = sizeof(statement_base_t),
- [STATEMENT_GOTO] = sizeof(goto_statement_t),
- [STATEMENT_LABEL] = sizeof(label_statement_t),
- [STATEMENT_CASE_LABEL] = sizeof(case_label_statement_t),
- [STATEMENT_WHILE] = sizeof(while_statement_t),
- [STATEMENT_DO_WHILE] = sizeof(do_while_statement_t),
- [STATEMENT_FOR] = sizeof(for_statement_t),
- [STATEMENT_ASM] = sizeof(asm_statement_t),
- [STATEMENT_MS_TRY] = sizeof(ms_try_statement_t),
- [STATEMENT_LEAVE] = sizeof(leave_statement_t)
+ [STATEMENT_ERROR] = sizeof(statement_base_t),
+ [STATEMENT_EMPTY] = sizeof(statement_base_t),
+ [STATEMENT_COMPOUND] = sizeof(compound_statement_t),
+ [STATEMENT_RETURN] = sizeof(return_statement_t),
+ [STATEMENT_DECLARATION] = sizeof(declaration_statement_t),
+ [STATEMENT_IF] = sizeof(if_statement_t),
+ [STATEMENT_SWITCH] = sizeof(switch_statement_t),
+ [STATEMENT_EXPRESSION] = sizeof(expression_statement_t),
+ [STATEMENT_CONTINUE] = sizeof(statement_base_t),
+ [STATEMENT_BREAK] = sizeof(statement_base_t),
+ [STATEMENT_COMPUTED_GOTO] = sizeof(computed_goto_statement_t),
+ [STATEMENT_GOTO] = sizeof(goto_statement_t),
+ [STATEMENT_LABEL] = sizeof(label_statement_t),
+ [STATEMENT_CASE_LABEL] = sizeof(case_label_statement_t),
+ [STATEMENT_WHILE] = sizeof(while_statement_t),
+ [STATEMENT_DO_WHILE] = sizeof(do_while_statement_t),
+ [STATEMENT_FOR] = sizeof(for_statement_t),
+ [STATEMENT_ASM] = sizeof(asm_statement_t),
+ [STATEMENT_MS_TRY] = sizeof(ms_try_statement_t),
+ [STATEMENT_LEAVE] = sizeof(leave_statement_t)
};
assert((size_t)kind < lengthof(sizes));
assert(sizes[kind] != 0);
static const size_t sizes[] = {
[EXPR_ERROR] = sizeof(expression_base_t),
[EXPR_REFERENCE] = sizeof(reference_expression_t),
- [EXPR_REFERENCE_ENUM_VALUE] = sizeof(reference_expression_t),
+ [EXPR_ENUM_CONSTANT] = sizeof(reference_expression_t),
[EXPR_LITERAL_BOOLEAN] = sizeof(literal_expression_t),
[EXPR_LITERAL_INTEGER] = sizeof(literal_expression_t),
- [EXPR_LITERAL_INTEGER_OCTAL] = sizeof(literal_expression_t),
- [EXPR_LITERAL_INTEGER_HEXADECIMAL]= sizeof(literal_expression_t),
[EXPR_LITERAL_FLOATINGPOINT] = sizeof(literal_expression_t),
- [EXPR_LITERAL_FLOATINGPOINT_HEXADECIMAL] = sizeof(literal_expression_t),
[EXPR_LITERAL_CHARACTER] = sizeof(literal_expression_t),
[EXPR_LITERAL_WIDE_CHARACTER] = sizeof(literal_expression_t),
[EXPR_STRING_LITERAL] = sizeof(string_literal_expression_t),
#endif
}
-static inline bool next_if(int const type)
+static inline bool next_if(token_kind_t const type)
{
if (token.kind == type) {
next_token();
/**
* Adds a token type to the token type anchor set (a multi-set).
*/
-static void add_anchor_token(int token_kind)
+static void add_anchor_token(token_kind_t const token_kind)
{
- assert(0 <= token_kind && token_kind < T_LAST_TOKEN);
+ assert(token_kind < T_LAST_TOKEN);
++token_anchor_set[token_kind];
}
-/**
- * Set the number of tokens types of the given type
- * to zero and return the old count.
- */
-static int save_and_reset_anchor_state(int token_kind)
-{
- assert(0 <= token_kind && token_kind < T_LAST_TOKEN);
- int count = token_anchor_set[token_kind];
- token_anchor_set[token_kind] = 0;
- return count;
-}
-
-/**
- * Restore the number of token types to the given count.
- */
-static void restore_anchor_state(int token_kind, int count)
-{
- assert(0 <= token_kind && token_kind < T_LAST_TOKEN);
- token_anchor_set[token_kind] = count;
-}
-
/**
* Remove a token type from the token type anchor set (a multi-set).
*/
-static void rem_anchor_token(int token_kind)
+static void rem_anchor_token(token_kind_t const token_kind)
{
- assert(0 <= token_kind && token_kind < T_LAST_TOKEN);
+ assert(token_kind < T_LAST_TOKEN);
assert(token_anchor_set[token_kind] != 0);
--token_anchor_set[token_kind];
}
-/**
- * Return true if the token type of the current token is
- * in the anchor set.
- */
-static bool at_anchor(void)
-{
- if (token.kind < 0)
- return false;
- return token_anchor_set[token.kind];
-}
-
/**
* Eat tokens until a matching token type is found.
*/
-static void eat_until_matching_token(int type)
+static void eat_until_matching_token(token_kind_t const type)
{
- int end_token;
+ token_kind_t end_token;
switch (type) {
case '(': end_token = ')'; break;
case '{': end_token = '}'; break;
/**
* Expect the current token is the expected token.
- * If not, generate an error, eat the current statement,
- * and goto the error_label label.
- */
-#define expect(expected, error_label) \
- do { \
- if (UNLIKELY(token.kind != (expected))) { \
- parse_error_expected(NULL, (expected), NULL); \
- add_anchor_token(expected); \
- eat_until_anchor(); \
- rem_anchor_token(expected); \
- if (token.kind != (expected)) \
- goto error_label; \
- } \
- next_token(); \
- } while (0)
+ * If not, generate an error and skip until the next anchor.
+ */
+static void expect(token_kind_t const expected)
+{
+ if (UNLIKELY(token.kind != expected)) {
+ parse_error_expected(NULL, expected, NULL);
+ add_anchor_token(expected);
+ eat_until_anchor();
+ rem_anchor_token(expected);
+ if (token.kind != expected)
+ return;
+ }
+ eat(expected);
+}
+
+static symbol_t *expect_identifier(char const *const context, source_position_t *const pos)
+{
+ if (token.kind != T_IDENTIFIER) {
+ parse_error_expected(context, T_IDENTIFIER, NULL);
+ add_anchor_token(T_IDENTIFIER);
+ eat_until_anchor();
+ rem_anchor_token(T_IDENTIFIER);
+ if (token.kind != T_IDENTIFIER)
+ return NULL;
+ }
+ symbol_t *const sym = token.identifier.symbol;
+ if (pos)
+ *pos = *HERE;
+ eat(T_IDENTIFIER);
+ return sym;
+}
/**
* Push a given scope on the scope stack and make it the
points_to_left = get_unqualified_type(points_to_left);
points_to_right = get_unqualified_type(points_to_right);
- if (is_type_atomic(points_to_left, ATOMIC_TYPE_VOID))
+ if (is_type_void(points_to_left))
return res;
- if (is_type_atomic(points_to_right, ATOMIC_TYPE_VOID)) {
+ if (is_type_void(points_to_right)) {
/* ISO/IEC 14882:1998(E) §C.1.2:6 */
return c_mode & _CXX ? ASSIGN_ERROR_INCOMPATIBLE : res;
}
return result;
}
-/**
- * compare two string, ignoring double underscores on the second.
- */
-static int strcmp_underscore(const char *s1, const char *s2)
-{
- if (s2[0] == '_' && s2[1] == '_') {
- size_t len2 = strlen(s2);
- size_t len1 = strlen(s1);
- if (len1 == len2-4 && s2[len2-2] == '_' && s2[len2-1] == '_') {
- return strncmp(s1, s2+2, len2-4);
- }
- }
-
- return strcmp(s1, s2);
-}
-
static attribute_t *allocate_attribute_zero(attribute_kind_t kind)
{
attribute_t *attribute = allocate_ast_zero(sizeof(*attribute));
*anchor = argument;
anchor = &argument->next;
} while (next_if(','));
- expect(')', end_error);
-
- return first;
-
-end_error:
- /* TODO... */
+ expect(')');
return first;
}
{
attribute_t *attribute = allocate_attribute_zero(ATTRIBUTE_GNU_ASM);
eat(T_asm);
-
- expect('(', end_error);
+ expect('(');
attribute->a.arguments = parse_attribute_arguments();
return attribute;
-
-end_error:
- return NULL;
}
static symbol_t *get_symbol_from_token(void)
{
switch(token.kind) {
- case T_IDENTIFIER:
- return token.identifier.symbol;
- case T_auto:
- case T_char:
- case T_double:
- case T_enum:
- case T_extern:
- case T_float:
- case T_int:
- case T_long:
- case T_register:
- case T_short:
- case T_static:
- case T_struct:
- case T_union:
- case T_unsigned:
- case T_void:
- case T_bool:
- case T__Bool:
- case T_class:
- case T_explicit:
- case T_export:
- case T_wchar_t:
- case T_const:
- case T_signed:
- case T___real__:
- case T___imag__:
- case T_restrict:
- case T_volatile:
- case T_inline:
- /* maybe we need more tokens ... add them on demand */
- return get_token_kind_symbol(token.kind);
- default:
+ case T_CHARACTER_CONSTANT:
+ case T_EOF:
+ case T_FLOATINGPOINT:
+ case T_INTEGER:
+ case T_STRING_LITERAL:
+ case T_WIDE_CHARACTER_CONSTANT:
+ case T_WIDE_STRING_LITERAL:
return NULL;
+
+ default:
+ return token.identifier.symbol;
}
}
}
const char *attribute_name = get_attribute_name(kind);
- if (attribute_name != NULL
- && strcmp_underscore(attribute_name, name) == 0)
+ if (attribute_name != NULL && streq_underscore(attribute_name, name))
break;
}
attribute_t **anchor = &first;
eat(T___attribute__);
- expect('(', end_error);
- expect('(', end_error);
+ expect('(');
+ expect('(');
+ add_anchor_token(')');
+ add_anchor_token(',');
if (token.kind != ')') do {
attribute_t *attribute = parse_attribute_gnu_single();
- if (attribute == NULL)
- goto end_error;
-
- *anchor = attribute;
- anchor = &attribute->next;
+ if (attribute) {
+ *anchor = attribute;
+ anchor = &attribute->next;
+ }
} while (next_if(','));
- expect(')', end_error);
- expect(')', end_error);
+ rem_anchor_token(',');
+ rem_anchor_token(')');
-end_error:
+ expect(')');
+ expect(')');
return first;
}
case EXPR_UNARY_CAST:
/* Special case: Use void cast to mark a variable as "read" */
- if (is_type_atomic(skip_typeref(expr->base.type), ATOMIC_TYPE_VOID))
+ if (is_type_void(skip_typeref(expr->base.type)))
lhs_ent = NULL;
goto unary;
determine_lhs_ent(expr->va_starte.ap, lhs_ent);
return;
- EXPR_LITERAL_CASES
+ case EXPR_LITERAL_CASES:
case EXPR_ERROR:
case EXPR_STRING_LITERAL:
case EXPR_WIDE_STRING_LITERAL:
case EXPR_OFFSETOF:
case EXPR_STATEMENT: // TODO
case EXPR_LABEL_ADDRESS:
- case EXPR_REFERENCE_ENUM_VALUE:
+ case EXPR_ENUM_CONSTANT:
return;
}
add_anchor_token(']');
designator->array_index = parse_constant_expression();
rem_anchor_token(']');
- expect(']', end_error);
+ expect(']');
break;
case '.':
designator = allocate_ast_zero(sizeof(designator[0]));
designator->source_position = token.base.source_position;
next_token();
- if (token.kind != T_IDENTIFIER) {
- parse_error_expected("while parsing designator",
- T_IDENTIFIER, NULL);
+ designator->symbol = expect_identifier("while parsing designator", NULL);
+ if (!designator->symbol)
return NULL;
- }
- designator->symbol = token.identifier.symbol;
- next_token();
break;
default:
- expect('=', end_error);
+ expect('=');
return result;
}
*anchor = designator;
anchor = &designator->next;
}
-end_error:
- return NULL;
}
static initializer_t *initializer_from_string(array_type_t *const type,
return result;
}
-/**
- * Checks if a given expression can be used as a constant initializer.
- */
-static bool is_initializer_constant(const expression_t *expression)
-{
- return is_constant_expression(expression) != EXPR_CLASS_VARIABLE ||
- is_linker_constant(expression) != EXPR_CLASS_VARIABLE;
-}
-
/**
* Parses an scalar initializer.
*
expression_t *expression = parse_assignment_expression();
mark_vars_read(expression, NULL);
- if (must_be_constant && !is_initializer_constant(expression)) {
+ if (must_be_constant && !is_linker_constant(expression)) {
errorf(&expression->base.source_position,
"initialisation expression '%E' is not constant",
expression);
env);
rem_anchor_token('}');
- if (type != NULL) {
- ascend_from_subtype(path);
- expect('}', end_error);
- } else {
- expect('}', end_error);
+ expect('}');
+
+ if (!type)
goto error_parse_next;
- }
+
+ ascend_from_subtype(path);
}
} else {
/* must be an expression */
expression_t *expression = parse_assignment_expression();
mark_vars_read(expression, NULL);
- if (env->must_be_constant && !is_initializer_constant(expression)) {
+ if (env->must_be_constant && !is_linker_constant(expression)) {
errorf(&expression->base.source_position,
"Initialisation expression '%E' is not constant",
expression);
if (token.kind == '}') {
break;
}
- expect(',', end_error);
+ add_anchor_token('}');
+ expect(',');
+ rem_anchor_token('}');
if (token.kind == '}') {
break;
}
max_index = path.max_index;
DEL_ARR_F(path.path);
- expect('}', end_error);
-end_error:;
+ expect('}');
} else {
/* parse_scalar_initializer() also works in this case: we simply
* have an expression without {} around it */
}
if (entity == NULL) {
- entity = allocate_entity_zero(kind, NAMESPACE_TAG, symbol);
- entity->compound.alignment = 1;
- entity->base.source_position = pos;
- entity->base.parent_scope = current_scope;
+ entity = allocate_entity_zero(kind, NAMESPACE_TAG, symbol, &pos);
+ entity->compound.alignment = 1;
+ entity->base.parent_scope = current_scope;
if (symbol != NULL) {
environment_push(entity);
}
}
add_anchor_token('}');
+ add_anchor_token(',');
do {
- if (token.kind != T_IDENTIFIER) {
- parse_error_expected("while parsing enum entry", T_IDENTIFIER, NULL);
- eat_block();
- rem_anchor_token('}');
- return;
- }
-
- symbol_t *symbol = token.identifier.symbol;
- entity_t *const entity
- = allocate_entity_zero(ENTITY_ENUM_VALUE, NAMESPACE_NORMAL, symbol);
+ add_anchor_token('=');
+ source_position_t pos;
+ symbol_t *const symbol = expect_identifier("while parsing enum entry", &pos);
+ entity_t *const entity = allocate_entity_zero(ENTITY_ENUM_VALUE, NAMESPACE_NORMAL, symbol, &pos);
entity->enum_value.enum_type = enum_type;
- entity->base.source_position = token.base.source_position;
- next_token();
+ rem_anchor_token('=');
if (next_if('=')) {
expression_t *value = parse_constant_expression();
record_entity(entity, false);
} while (next_if(',') && token.kind != '}');
+ rem_anchor_token(',');
rem_anchor_token('}');
- expect('}', end_error);
-
-end_error:
- ;
+ expect('}');
}
static type_t *parse_enum_specifier(void)
}
if (entity == NULL) {
- entity = allocate_entity_zero(ENTITY_ENUM, NAMESPACE_TAG, symbol);
- entity->base.source_position = pos;
- entity->base.parent_scope = current_scope;
+ entity = allocate_entity_zero(ENTITY_ENUM, NAMESPACE_TAG, symbol, &pos);
+ entity->base.parent_scope = current_scope;
}
type_t *const type = allocate_type_zero(TYPE_ENUM);
type_t *type;
- expect('(', end_error);
+ expect('(');
add_anchor_token(')');
expression_t *expression = NULL;
}
rem_anchor_token(')');
- expect(')', end_error);
+ expect(')');
type_t *typeof_type = allocate_type_zero(TYPE_TYPEOF);
typeof_type->typeoft.expression = expression;
typeof_type->typeoft.typeof_type = type;
return typeof_type;
-end_error:
- return NULL;
}
typedef enum specifiers_t {
static attribute_t *parse_attribute_ms_property(attribute_t *attribute)
{
- expect('(', end_error);
+ attribute_property_argument_t *const property = allocate_ast_zero(sizeof(*property));
- attribute_property_argument_t *property
- = allocate_ast_zero(sizeof(*property));
+ expect('(');
+ add_anchor_token(')');
+ add_anchor_token(',');
do {
- if (token.kind != T_IDENTIFIER) {
- parse_error_expected("while parsing property declspec",
- T_IDENTIFIER, NULL);
- goto end_error;
- }
+ add_anchor_token('=');
+ source_position_t pos;
+ symbol_t *const prop_sym = expect_identifier("while parsing property declspec", &pos);
+ rem_anchor_token('=');
- symbol_t **prop;
- symbol_t *symbol = token.identifier.symbol;
- if (strcmp(symbol->string, "put") == 0) {
- prop = &property->put_symbol;
- } else if (strcmp(symbol->string, "get") == 0) {
- prop = &property->get_symbol;
- } else {
- errorf(HERE, "expected put or get in property declspec");
- prop = NULL;
- }
- eat(T_IDENTIFIER);
- expect('=', end_error);
- if (token.kind != T_IDENTIFIER) {
- parse_error_expected("while parsing property declspec",
- T_IDENTIFIER, NULL);
- goto end_error;
+ symbol_t **prop = NULL;
+ if (prop_sym) {
+ if (streq(prop_sym->string, "put")) {
+ prop = &property->put_symbol;
+ } else if (streq(prop_sym->string, "get")) {
+ prop = &property->get_symbol;
+ } else {
+ errorf(&pos, "expected put or get in property declspec, but got '%Y'", prop_sym);
+ }
}
+
+ add_anchor_token(T_IDENTIFIER);
+ expect('=');
+ rem_anchor_token(T_IDENTIFIER);
+
+ symbol_t *const sym = expect_identifier("while parsing property declspec", NULL);
if (prop != NULL)
- *prop = token.identifier.symbol;
- next_token();
+ *prop = sym ? sym : sym_anonymous;
} while (next_if(','));
+ rem_anchor_token(',');
+ rem_anchor_token(')');
attribute->a.property = property;
- expect(')', end_error);
-
-end_error:
+ expect(')');
return attribute;
}
for (attribute_kind_t k = ATTRIBUTE_MS_FIRST; k <= ATTRIBUTE_MS_LAST;
++k) {
const char *attribute_name = get_attribute_name(k);
- if (attribute_name != NULL && strcmp(attribute_name, name) == 0) {
+ if (attribute_name != NULL && streq(attribute_name, name)) {
kind = k;
break;
}
{
eat(T__declspec);
- expect('(', end_error);
-
- if (next_if(')'))
- return NULL;
-
- add_anchor_token(')');
-
- attribute_t **anchor = &first;
- do {
- while (*anchor != NULL)
- anchor = &(*anchor)->next;
+ expect('(');
+ if (token.kind != ')') {
+ add_anchor_token(')');
- attribute_t *attribute
- = parse_microsoft_extended_decl_modifier_single();
- if (attribute == NULL)
- goto end_error;
+ attribute_t **anchor = &first;
+ do {
+ while (*anchor != NULL)
+ anchor = &(*anchor)->next;
- *anchor = attribute;
- anchor = &attribute->next;
- } while (next_if(','));
+ attribute_t *attribute
+ = parse_microsoft_extended_decl_modifier_single();
+ if (attribute == NULL)
+ break;
- rem_anchor_token(')');
- expect(')', end_error);
- return first;
+ *anchor = attribute;
+ anchor = &attribute->next;
+ } while (next_if(','));
-end_error:
- rem_anchor_token(')');
+ rem_anchor_token(')');
+ }
+ expect(')');
return first;
}
static entity_t *create_error_entity(symbol_t *symbol, entity_kind_tag_t kind)
{
- entity_t *const entity = allocate_entity_zero(kind, NAMESPACE_NORMAL, symbol);
- entity->base.source_position = *HERE;
+ entity_t *const entity = allocate_entity_zero(kind, NAMESPACE_NORMAL, symbol, HERE);
if (is_declaration(entity)) {
entity->declaration.type = type_error_type;
entity->declaration.implicit = true;
{
assert(token.kind == T_IDENTIFIER);
do {
- entity_t *const entity = allocate_entity_zero(ENTITY_PARAMETER, NAMESPACE_NORMAL, token.identifier.symbol);
- entity->base.source_position = token.base.source_position;
+ entity_t *const entity = allocate_entity_zero(ENTITY_PARAMETER, NAMESPACE_NORMAL, token.identifier.symbol, HERE);
/* a K&R parameter has no type, yet */
next_token();
static bool has_parameters(void)
{
/* func(void) is not a parameter */
+ if (look_ahead(1)->kind != ')')
+ return true;
if (token.kind == T_IDENTIFIER) {
entity_t const *const entity
= get_entity(token.identifier.symbol, NAMESPACE_NORMAL);
return true;
if (entity->kind != ENTITY_TYPEDEF)
return true;
- if (skip_typeref(entity->typedefe.type) != type_void)
+ type_t const *const type = skip_typeref(entity->typedefe.type);
+ if (!is_type_void(type))
return true;
+ if (c_mode & _CXX) {
+ /* ISO/IEC 14882:1998(E) §8.3.5:2 It must be literally (void). A typedef
+ * is not allowed. */
+ errorf(HERE, "empty parameter list defined with a typedef of 'void' not allowed in C++");
+ } else if (type->base.qualifiers != TYPE_QUALIFIER_NONE) {
+ /* §6.7.5.3:10 Qualification is not allowed here. */
+ errorf(HERE, "'void' as parameter must not have type qualifiers");
+ }
} else if (token.kind != T_void) {
return true;
}
- if (look_ahead(1)->kind != ')')
- return true;
next_token();
return false;
}
{
eat('(');
add_anchor_token(')');
- int saved_comma_state = save_and_reset_anchor_state(',');
-
- if (token.kind == T_IDENTIFIER
- && !is_typedef_symbol(token.identifier.symbol)) {
- token_kind_t la1_type = (token_kind_t)look_ahead(1)->kind;
- if (la1_type == ',' || la1_type == ')') {
- type->kr_style_parameters = true;
- parse_identifier_list(scope);
- goto parameters_finished;
- }
- }
- if (token.kind == ')') {
+ if (token.kind == T_IDENTIFIER &&
+ !is_typedef_symbol(token.identifier.symbol) &&
+ (look_ahead(1)->kind == ',' || look_ahead(1)->kind == ')')) {
+ type->kr_style_parameters = true;
+ parse_identifier_list(scope);
+ } else if (token.kind == ')') {
/* ISO/IEC 14882:1998(E) §C.1.6:1 */
if (!(c_mode & _CXX))
type->unspecified_parameters = true;
} else if (has_parameters()) {
function_parameter_t **anchor = &type->parameters;
+ add_anchor_token(',');
do {
switch (token.kind) {
case T_DOTDOTDOT:
goto parameters_finished;
}
} while (next_if(','));
+parameters_finished:
+ rem_anchor_token(',');
}
-parameters_finished:
rem_anchor_token(')');
- expect(')', end_error);
-
-end_error:
- restore_anchor_state(',', saved_comma_state);
+ expect(')');
}
typedef enum construct_type_kind_t {
errorf(&array->base.pos, "static array parameters require a size");
rem_anchor_token(']');
- expect(']', end_error);
-
-end_error:
+ expect(']');
return cons;
}
env->must_be_abstract = true;
}
rem_anchor_token(')');
- expect(')', end_error);
+ expect(')');
}
break;
}
*anchor = inner_types;
return first;
-end_error:
- return NULL;
}
static type_t *construct_declarator_type(construct_type_t *construct_list,
entity_t *entity;
if (specifiers->storage_class == STORAGE_CLASS_TYPEDEF) {
- entity = allocate_entity_zero(ENTITY_TYPEDEF, NAMESPACE_NORMAL, env.symbol);
- entity->base.source_position = env.source_position;
- entity->typedefe.type = orig_type;
+ entity = allocate_entity_zero(ENTITY_TYPEDEF, NAMESPACE_NORMAL, env.symbol, &env.source_position);
+ entity->typedefe.type = orig_type;
if (anonymous_entity != NULL) {
if (is_type_compound(type)) {
}
} else {
/* create a declaration type entity */
+ source_position_t const *const pos = env.symbol ? &env.source_position : &specifiers->source_position;
if (flags & DECL_CREATE_COMPOUND_MEMBER) {
- entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER, NAMESPACE_NORMAL, env.symbol);
+ entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER, NAMESPACE_NORMAL, env.symbol, pos);
if (env.symbol != NULL) {
if (specifiers->is_inline && is_type_valid(type)) {
}
}
} else if (flags & DECL_IS_PARAMETER) {
- entity = allocate_entity_zero(ENTITY_PARAMETER, NAMESPACE_NORMAL, env.symbol);
+ entity = allocate_entity_zero(ENTITY_PARAMETER, NAMESPACE_NORMAL, env.symbol, pos);
orig_type = semantic_parameter(&env.source_position, orig_type, specifiers, entity);
} else if (is_type_function(type)) {
- entity = allocate_entity_zero(ENTITY_FUNCTION, NAMESPACE_NORMAL, env.symbol);
+ entity = allocate_entity_zero(ENTITY_FUNCTION, NAMESPACE_NORMAL, env.symbol, pos);
entity->function.is_inline = specifiers->is_inline;
entity->function.elf_visibility = default_visibility;
entity->function.parameters = env.parameters;
}
}
} else {
- entity = allocate_entity_zero(ENTITY_VARIABLE, NAMESPACE_NORMAL, env.symbol);
+ entity = allocate_entity_zero(ENTITY_VARIABLE, NAMESPACE_NORMAL, env.symbol, pos);
entity->variable.elf_visibility = default_visibility;
entity->variable.thread_local = specifiers->thread_local;
}
}
- entity->base.source_position = env.symbol != NULL ? env.source_position : specifiers->source_position;
entity->declaration.type = orig_type;
entity->declaration.alignment = get_type_alignment(orig_type);
entity->declaration.modifiers = env.modifiers;
handle_entity_attributes(attributes, entity);
}
+ if (entity->kind == ENTITY_FUNCTION && !freestanding) {
+ adapt_special_functions(&entity->function);
+ }
+
return entity;
}
}
}
-/**
- * Check if a symbol is the equal to "main".
- */
-static bool is_sym_main(const symbol_t *const sym)
-{
- return strcmp(sym->string, "main") == 0;
-}
-
static void error_redefined_as_different_kind(const source_position_t *pos,
const entity_t *old, entity_kind_t new_kind)
{
}
}
+static bool is_main(entity_t*);
+
/**
* record entities for the NAMESPACE_NORMAL, and produce error messages/warnings
* for various problems that occur for multiple definitions
if (symbol == NULL)
return entity;
+ assert(!entity->base.parent_scope);
+ assert(current_scope);
+ entity->base.parent_scope = current_scope;
+
entity_t *const previous_entity = get_entity(symbol, namespc);
/* pushing the same entity twice will break the stack structure */
assert(previous_entity != entity);
warningf(WARN_STRICT_PROTOTYPES, pos, "function declaration '%#N' is not a prototype", entity);
}
- if (current_scope == file_scope && is_sym_main(symbol)) {
+ if (is_main(entity)) {
check_main(entity);
}
}
type_t *const type = skip_typeref(entity->typedefe.type);
type_t *const prev_type
= skip_typeref(previous_entity->typedefe.type);
- /* gcc extension: redef in system headers is allowed */
- if ((pos->is_system_header || ppos->is_system_header)
- && types_compatible(type, prev_type))
- goto finish;
- /* c++ allows double typedef if they are identical
- * (after skipping typedefs) */
- if ((c_mode & _CXX) && type == prev_type)
- goto finish;
+ if (c_mode & _CXX) {
+ /* C++ allows double typedef if they are identical
+ * (after skipping typedefs) */
+ if (type == prev_type)
+ goto finish;
+ } else {
+ /* GCC extension: redef in system headers is allowed */
+ if ((pos->is_system_header || ppos->is_system_header) &&
+ types_compatible(type, prev_type))
+ goto finish;
+ }
errorf(pos, "redefinition of '%N' (declared %P)",
entity, ppos);
goto finish;
case STORAGE_CLASS_EXTERN:
if (is_definition) {
- if (prev_type->function.unspecified_parameters && !is_sym_main(symbol)) {
+ if (prev_type->function.unspecified_parameters && !is_main(entity)) {
warningf(WARN_MISSING_PROTOTYPES, pos, "no previous prototype for '%#N'", entity);
}
} else if (new_storage_class == STORAGE_CLASS_NONE) {
if (entity->kind == ENTITY_FUNCTION) {
if (is_definition &&
entity->declaration.storage_class != STORAGE_CLASS_STATIC &&
- !is_sym_main(symbol)) {
+ !is_main(entity)) {
if (is_warn_on(WARN_MISSING_PROTOTYPES)) {
warningf(WARN_MISSING_PROTOTYPES, pos, "no previous prototype for '%#N'", entity);
} else {
}
finish:
- assert(entity->base.parent_scope == NULL);
- assert(current_scope != NULL);
-
- entity->base.parent_scope = current_scope;
environment_push(entity);
append_entity(current_scope, entity);
/* ISO/IEC 14882:1998(E) §8.5.3:3 The initializer can be omitted
* [...] where the extern specifier is explicitly used. */
declaration_t *decl = &entity->declaration;
- if (decl->storage_class != STORAGE_CLASS_EXTERN) {
- type_t *type = decl->type;
- if (is_type_reference(skip_typeref(type))) {
- source_position_t const *const pos = &entity->base.source_position;
- errorf(pos, "reference '%#N' must be initialized", entity);
- }
+ if (decl->storage_class != STORAGE_CLASS_EXTERN &&
+ is_type_reference(skip_typeref(decl->type))) {
+ source_position_t const *const pos = &entity->base.source_position;
+ errorf(pos, "reference '%#N' must be initialized", entity);
}
}
ndeclaration = parse_declarator(specifiers, flags);
rem_anchor_token('=');
}
- expect(';', end_error);
+ rem_anchor_token(',');
+ rem_anchor_token(';');
+ expect(';');
-end_error:
anonymous_entity = NULL;
- rem_anchor_token(';');
- rem_anchor_token(',');
}
static entity_t *finished_kr_declaration(entity_t *entity, bool is_definition)
for (const goto_statement_t *goto_statement = goto_first;
goto_statement != NULL;
goto_statement = goto_statement->next) {
- /* skip computed gotos */
- if (goto_statement->expression != NULL)
- continue;
-
label_t *label = goto_statement->label;
if (label->base.source_position.input_name == NULL) {
print_in_function();
{
if (is_warn_on(WARN_UNUSED_PARAMETER)) {
const scope_t *scope = ¤t_function->parameters;
-
- /* do not issue unused warnings for main */
- if (!is_sym_main(current_function->base.base.symbol)) {
- warn_unused_entity(WARN_UNUSED_PARAMETER, scope->entities, NULL);
- }
+ warn_unused_entity(WARN_UNUSED_PARAMETER, scope->entities, NULL);
}
if (is_warn_on(WARN_UNUSED_VARIABLE)) {
walk_statements(current_function->statement, check_unused_variables,
switch (expr->kind) {
case EXPR_CALL: {
expression_t const *const func = expr->call.function;
- if (func->kind == EXPR_REFERENCE) {
- entity_t *entity = func->reference.entity;
- if (entity->kind == ENTITY_FUNCTION
- && entity->declaration.modifiers & DM_NORETURN)
+ type_t const *const type = skip_typeref(func->base.type);
+ if (type->kind == TYPE_POINTER) {
+ type_t const *const points_to
+ = skip_typeref(type->pointer.points_to);
+ if (points_to->kind == TYPE_FUNCTION
+ && points_to->function.modifiers & DM_NORETURN)
return false;
}
}
case EXPR_REFERENCE:
- case EXPR_REFERENCE_ENUM_VALUE:
- EXPR_LITERAL_CASES
+ case EXPR_ENUM_CONSTANT:
+ case EXPR_LITERAL_CASES:
case EXPR_STRING_LITERAL:
case EXPR_WIDE_STRING_LITERAL:
case EXPR_COMPOUND_LITERAL: // TODO descend into initialisers
case EXPR_VA_COPY:
return expression_returns(expr->va_copye.src);
- EXPR_UNARY_CASES_MANDATORY
+ case EXPR_UNARY_CASES_MANDATORY:
return expression_returns(expr->unary.value);
case EXPR_UNARY_THROW:
return false;
- EXPR_BINARY_CASES
+ case EXPR_BINARY_CASES:
// TODO handle constant lhs of && and ||
return
expression_returns(expr->binary.left) &&
found_break_parent:
break;
- case STATEMENT_GOTO:
- if (stmt->gotos.expression) {
- if (!expression_returns(stmt->gotos.expression))
- return;
+ case STATEMENT_COMPUTED_GOTO: {
+ if (!expression_returns(stmt->computed_goto.expression))
+ return;
- statement_t *parent = stmt->base.parent;
- if (parent == NULL) /* top level goto */
- return;
- next = parent;
- } else {
- next = stmt->gotos.label->statement;
- if (next == NULL) /* missing label */
- return;
- }
+ statement_t *parent = stmt->base.parent;
+ if (parent == NULL) /* top level goto */
+ return;
+ next = parent;
+ break;
+ }
+
+ case STATEMENT_GOTO:
+ next = stmt->gotos.label->statement;
+ if (next == NULL) /* missing label */
+ return;
break;
case STATEMENT_LABEL:
type_t *const type = skip_typeref(current_function->base.type);
assert(is_type_function(type));
type_t *const ret = skip_typeref(type->function.return_type);
- if (!is_type_atomic(ret, ATOMIC_TYPE_VOID) &&
- is_type_valid(ret) &&
- !is_sym_main(current_function->base.base.symbol)) {
+ if (!is_type_void(ret) &&
+ is_type_valid(ret) &&
+ !is_main(current_entity)) {
source_position_t const *const pos = &stmt->base.source_position;
warningf(WARN_RETURN_TYPE, pos, "control reaches end of non-void function");
}
case STATEMENT_RETURN:
case STATEMENT_CONTINUE:
case STATEMENT_BREAK:
+ case STATEMENT_COMPUTED_GOTO:
case STATEMENT_GOTO:
case STATEMENT_LEAVE:
panic("invalid control flow in function");
}
}
+static bool is_main(entity_t *entity)
+{
+ static symbol_t *sym_main = NULL;
+ if (sym_main == NULL) {
+ sym_main = symbol_table_insert("main");
+ }
+
+ if (entity->base.symbol != sym_main)
+ return false;
+ /* must be in outermost scope */
+ if (entity->base.parent_scope != file_scope)
+ return false;
+
+ return true;
+}
+
+static void prepare_main_collect2(entity_t*);
+
static void parse_external_declaration(void)
{
/* function-definitions and declarations both start with declaration
if (ndeclaration != entity) {
function->parameters = ndeclaration->function.parameters;
}
- assert(is_declaration(entity));
- type = skip_typeref(entity->declaration.type);
PUSH_SCOPE(&function->parameters);
/* parse function body */
int label_stack_top = label_top();
function_t *old_current_function = current_function;
- entity_t *old_current_entity = current_entity;
current_function = function;
- current_entity = entity;
+ PUSH_CURRENT_ENTITY(entity);
PUSH_PARENT(NULL);
goto_first = NULL;
}
}
+ if (is_main(entity)) {
+ /* Force main to C linkage. */
+ type_t *const type = entity->declaration.type;
+ assert(is_type_function(type));
+ if (type->function.linkage != LINKAGE_C) {
+ type_t *new_type = duplicate_type(type);
+ new_type->function.linkage = LINKAGE_C;
+ entity->declaration.type = identify_new_type(new_type);
+ }
+
+ if (enable_main_collect2_hack)
+ prepare_main_collect2(entity);
+ }
+
+ POP_CURRENT_ENTITY();
POP_PARENT();
assert(current_function == function);
- assert(current_entity == entity);
- current_entity = old_current_entity;
current_function = old_current_function;
label_pop_to(label_stack_top);
}
static void parse_compound_declarators(compound_t *compound,
const declaration_specifiers_t *specifiers)
{
+ add_anchor_token(';');
+ add_anchor_token(',');
do {
entity_t *entity;
if (token.kind == ':') {
/* anonymous bitfield */
type_t *type = specifiers->type;
- entity_t *entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER,
- NAMESPACE_NORMAL, NULL);
- entity->base.source_position = *HERE;
+ entity_t *const entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER, NAMESPACE_NORMAL, NULL, HERE);
entity->declaration.declared_storage_class = STORAGE_CLASS_NONE;
entity->declaration.storage_class = STORAGE_CLASS_NONE;
entity->declaration.type = type;
token.kind != ';' ||
look_ahead(1)->kind != '}') {
errorf(pos, "'%N' has incomplete type '%T'", entity, orig_type);
+ } else if (compound->members.entities == NULL) {
+ errorf(pos, "flexible array member in otherwise empty struct");
}
}
}
}
}
} while (next_if(','));
- expect(';', end_error);
+ rem_anchor_token(',');
+ rem_anchor_token(';');
+ expect(';');
-end_error:
anonymous_entity = NULL;
}
default:
rem_anchor_token('}');
- expect('}', end_error);
-end_error:
+ expect('}');
/* §6.7.2.1:7 */
compound->complete = true;
return;
static expression_parser_function_t expression_parsers[T_LAST_TOKEN];
-/**
- * Prints an error message if an expression was expected but not read
- */
-static expression_t *expected_expression_error(void)
-{
- /* skip the error message if the error token was read */
- if (token.kind != T_ERROR) {
- errorf(HERE, "expected expression, got token %K", &token);
- }
- next_token();
-
- return create_error_expression();
-}
-
static type_t *get_string_type(void)
{
return is_warn_on(WARN_WRITE_STRINGS) ? type_const_char_ptr : type_char_ptr;
check_integer_suffix();
type = type_int;
break;
- case T_INTEGER_OCTAL:
- kind = EXPR_LITERAL_INTEGER_OCTAL;
- check_integer_suffix();
- type = type_int;
- break;
- case T_INTEGER_HEXADECIMAL:
- kind = EXPR_LITERAL_INTEGER_HEXADECIMAL;
- check_integer_suffix();
- type = type_int;
- break;
+
case T_FLOATINGPOINT:
kind = EXPR_LITERAL_FLOATINGPOINT;
type = check_floatingpoint_suffix();
break;
- case T_FLOATINGPOINT_HEXADECIMAL:
- kind = EXPR_LITERAL_FLOATINGPOINT_HEXADECIMAL;
- type = check_floatingpoint_suffix();
- break;
+
default:
panic("unexpected token type in parse_number_literal");
}
return literal;
}
-static entity_t *create_implicit_function(symbol_t *symbol,
- const source_position_t *source_position)
+static entity_t *create_implicit_function(symbol_t *symbol, source_position_t const *const pos)
{
type_t *ntype = allocate_type_zero(TYPE_FUNCTION);
ntype->function.return_type = type_int;
ntype->function.linkage = LINKAGE_C;
type_t *type = identify_new_type(ntype);
- entity_t *const entity = allocate_entity_zero(ENTITY_FUNCTION, NAMESPACE_NORMAL, symbol);
+ entity_t *const entity = allocate_entity_zero(ENTITY_FUNCTION, NAMESPACE_NORMAL, symbol, pos);
entity->declaration.storage_class = STORAGE_CLASS_EXTERN;
entity->declaration.declared_storage_class = STORAGE_CLASS_EXTERN;
entity->declaration.type = type;
entity->declaration.implicit = true;
- entity->base.source_position = *source_position;
if (current_scope != NULL)
record_entity(entity, false);
entity_t *entity;
while (true) {
- if (token.kind != T_IDENTIFIER) {
- parse_error_expected("while parsing identifier", T_IDENTIFIER, NULL);
+ symbol = expect_identifier("while parsing identifier", &pos);
+ if (!symbol)
return create_error_entity(sym_anonymous, ENTITY_VARIABLE);
- }
- symbol = token.identifier.symbol;
- pos = *HERE;
- next_token();
/* lookup entity */
entity = lookup_entity(lookup_scope, symbol, NAMESPACE_NORMAL);
expression_kind_t kind = EXPR_REFERENCE;
if (entity->kind == ENTITY_ENUM_VALUE)
- kind = EXPR_REFERENCE_ENUM_VALUE;
+ kind = EXPR_ENUM_CONSTANT;
expression_t *expression = allocate_expression_zero(kind);
expression->base.source_position = pos;
source_position_t const *pos = &cast->base.source_position;
/* §6.5.4 A (void) cast is explicitly permitted, more for documentation than for utility. */
- if (dst_type == type_void)
+ if (is_type_void(dst_type))
return true;
/* only integer and pointer can be casted to pointer */
type_t *type = parse_typename();
rem_anchor_token(')');
- expect(')', end_error);
+ expect(')');
if (token.kind == '{') {
return parse_compound_literal(&pos, type);
}
return cast;
-end_error:
- return create_error_expression();
}
/**
expression->base.type = type;
rem_anchor_token(')');
- expect(')', end_error);
-
-end_error:
+ expect(')');
return expression;
}
expression_t *result = parse_expression();
result->base.parenthesized = true;
rem_anchor_token(')');
- expect(')', end_error);
+ expect(')');
-end_error:
return result;
}
static designator_t *parse_designator(void)
{
- designator_t *result = allocate_ast_zero(sizeof(result[0]));
- result->source_position = *HERE;
-
- if (token.kind != T_IDENTIFIER) {
- parse_error_expected("while parsing member designator",
- T_IDENTIFIER, NULL);
+ designator_t *const result = allocate_ast_zero(sizeof(result[0]));
+ result->symbol = expect_identifier("while parsing member designator", &result->source_position);
+ if (!result->symbol)
return NULL;
- }
- result->symbol = token.identifier.symbol;
- next_token();
designator_t *last_designator = result;
while (true) {
if (next_if('.')) {
- if (token.kind != T_IDENTIFIER) {
- parse_error_expected("while parsing member designator",
- T_IDENTIFIER, NULL);
+ designator_t *const designator = allocate_ast_zero(sizeof(result[0]));
+ designator->symbol = expect_identifier("while parsing member designator", &designator->source_position);
+ if (!designator->symbol)
return NULL;
- }
- designator_t *designator = allocate_ast_zero(sizeof(result[0]));
- designator->source_position = *HERE;
- designator->symbol = token.identifier.symbol;
- next_token();
last_designator->next = designator;
last_designator = designator;
designator->source_position = *HERE;
designator->array_index = parse_expression();
rem_anchor_token(']');
- expect(']', end_error);
+ expect(']');
if (designator->array_index == NULL) {
return NULL;
}
}
return result;
-end_error:
- return NULL;
}
/**
eat(T___builtin_offsetof);
- expect('(', end_error);
+ expect('(');
+ add_anchor_token(')');
add_anchor_token(',');
type_t *type = parse_typename();
rem_anchor_token(',');
- expect(',', end_error);
- add_anchor_token(')');
+ expect(',');
designator_t *designator = parse_designator();
rem_anchor_token(')');
- expect(')', end_error);
+ expect(')');
expression->offsetofe.type = type;
expression->offsetofe.designator = designator;
DEL_ARR_F(path.path);
return expression;
-end_error:
- return create_error_expression();
}
/**
eat(T___builtin_va_start);
- expect('(', end_error);
+ expect('(');
+ add_anchor_token(')');
add_anchor_token(',');
expression->va_starte.ap = parse_assignment_expression();
rem_anchor_token(',');
- expect(',', end_error);
+ expect(',');
expression_t *const expr = parse_assignment_expression();
if (expr->kind == EXPR_REFERENCE) {
entity_t *const entity = expr->reference.entity;
} else {
expression->va_starte.parameter = &entity->variable;
}
- expect(')', end_error);
- return expression;
+ } else {
+ expression = create_error_expression();
}
- expect(')', end_error);
-end_error:
- return create_error_expression();
+ rem_anchor_token(')');
+ expect(')');
+ return expression;
}
/**
eat(T___builtin_va_arg);
- expect('(', end_error);
+ expect('(');
+ add_anchor_token(')');
+ add_anchor_token(',');
call_argument_t ap;
ap.expression = parse_assignment_expression();
expression->va_arge.ap = ap.expression;
check_call_argument(type_valist, &ap, 1);
- expect(',', end_error);
+ rem_anchor_token(',');
+ expect(',');
expression->base.type = parse_typename();
- expect(')', end_error);
+ rem_anchor_token(')');
+ expect(')');
return expression;
-end_error:
- return create_error_expression();
}
/**
eat(T___builtin_va_copy);
- expect('(', end_error);
+ expect('(');
+ add_anchor_token(')');
+ add_anchor_token(',');
expression_t *dst = parse_assignment_expression();
assign_error_t error = semantic_assign(type_valist, dst);
report_assign_error(error, type_valist, dst, "call argument 1",
&dst->base.source_position);
expression->va_copye.dst = dst;
- expect(',', end_error);
+ rem_anchor_token(',');
+ expect(',');
call_argument_t src;
src.expression = parse_assignment_expression();
check_call_argument(type_valist, &src, 2);
expression->va_copye.src = src.expression;
- expect(')', end_error);
+ rem_anchor_token(')');
+ expect(')');
return expression;
-end_error:
- return create_error_expression();
}
/**
eat(T___builtin_constant_p);
- expect('(', end_error);
+ expect('(');
add_anchor_token(')');
expression->builtin_constant.value = parse_assignment_expression();
rem_anchor_token(')');
- expect(')', end_error);
+ expect(')');
expression->base.type = type_int;
return expression;
-end_error:
- return create_error_expression();
}
/**
eat(T___builtin_types_compatible_p);
- expect('(', end_error);
+ expect('(');
add_anchor_token(')');
add_anchor_token(',');
expression->builtin_types_compatible.left = parse_typename();
rem_anchor_token(',');
- expect(',', end_error);
+ expect(',');
expression->builtin_types_compatible.right = parse_typename();
rem_anchor_token(')');
- expect(')', end_error);
+ expect(')');
expression->base.type = type_int;
return expression;
-end_error:
- return create_error_expression();
}
/**
expression->base.source_position = *HERE;
next_token();
- expect('(', end_error);
+ expect('(');
+ add_anchor_token(')');
+ add_anchor_token(',');
expression->binary.left = parse_assignment_expression();
- expect(',', end_error);
+ rem_anchor_token(',');
+ expect(',');
expression->binary.right = parse_assignment_expression();
- expect(')', end_error);
+ rem_anchor_token(')');
+ expect(')');
type_t *const orig_type_left = expression->binary.left->base.type;
type_t *const orig_type_right = expression->binary.right->base.type;
}
return expression;
-end_error:
- return create_error_expression();
}
/**
eat(T__assume);
- expect('(', end_error);
+ expect('(');
add_anchor_token(')');
expression->unary.value = parse_assignment_expression();
rem_anchor_token(')');
- expect(')', end_error);
+ expect(')');
expression->base.type = type_void;
return expression;
-end_error:
- return create_error_expression();
}
/**
}
} else if (label == NULL || label->base.parent_scope != ¤t_function->parameters) {
/* There is no matching label in the same function, so create a new one. */
- label = allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, token.identifier.symbol);
+ source_position_t const nowhere = { NULL, 0, 0, false };
+ label = allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, token.identifier.symbol, &nowhere);
label_push(label);
}
if (token.kind != ')') do {
(void)parse_assignment_expression();
} while (next_if(','));
+
+ rem_anchor_token(',');
+ rem_anchor_token(')');
}
- rem_anchor_token(',');
- rem_anchor_token(')');
- expect(')', end_error);
+ expect(')');
-end_error:
return literal;
}
case T_false: return parse_boolean_literal(false);
case T_true: return parse_boolean_literal(true);
case T_INTEGER:
- case T_INTEGER_OCTAL:
- case T_INTEGER_HEXADECIMAL:
- case T_FLOATINGPOINT:
- case T_FLOATINGPOINT_HEXADECIMAL: return parse_number_literal();
+ case T_FLOATINGPOINT: return parse_number_literal();
case T_CHARACTER_CONSTANT: return parse_character_constant();
case T_WIDE_CHARACTER_CONSTANT: return parse_wide_character_constant();
case T_STRING_LITERAL:
arr->base.type = res_type;
rem_anchor_token(']');
- expect(']', end_error);
-end_error:
+ expect(']');
return expr;
}
add_anchor_token(')');
orig_type = parse_typename();
rem_anchor_token(')');
- expect(')', end_error);
+ expect(')');
if (token.kind == '{') {
/* It was not sizeof(type) after all. It is sizeof of an expression
type_t const* const type = skip_typeref(orig_type);
char const* wrong_type = NULL;
if (is_type_incomplete(type)) {
- if (!is_type_atomic(type, ATOMIC_TYPE_VOID) || !GNU_MODE)
+ if (!is_type_void(type) || !GNU_MODE)
wrong_type = "incomplete";
} else if (type->kind == TYPE_FUNCTION) {
if (GNU_MODE) {
what, wrong_type, orig_type);
}
-end_error:
return tp_expression;
}
source_position_t const pos = *HERE;
next_token();
- if (token.kind != T_IDENTIFIER) {
- parse_error_expected("while parsing select", T_IDENTIFIER, NULL);
+ symbol_t *const symbol = expect_identifier("while parsing select", NULL);
+ if (!symbol)
return create_error_expression();
- }
- symbol_t *symbol = token.identifier.symbol;
- next_token();
type_t *const orig_type = addr->base.type;
type_t *const type = skip_typeref(orig_type);
}
rem_anchor_token(',');
rem_anchor_token(')');
- expect(')', end_error);
+ expect(')');
if (function_type == NULL)
return result;
handle_builtin_argument_restrictions(call);
}
-end_error:
return result;
}
true_expression = parse_expression();
}
rem_anchor_token(':');
- expect(':', end_error);
-end_error:;
+ expect(':');
expression_t *false_expression =
parse_subexpression(c_mode & _CXX ? PREC_ASSIGNMENT : PREC_CONDITIONAL);
/* 6.5.15.3 */
source_position_t const *const pos = &conditional->base.source_position;
type_t *result_type;
- if (is_type_atomic(true_type, ATOMIC_TYPE_VOID) ||
- is_type_atomic(false_type, ATOMIC_TYPE_VOID)) {
+ if (is_type_void(true_type) || is_type_void(false_type)) {
/* ISO/IEC 14882:1998(E) §5.16:2 */
if (true_expression->kind == EXPR_UNARY_THROW) {
result_type = false_type;
} else if (false_expression->kind == EXPR_UNARY_THROW) {
result_type = true_type;
} else {
- if (!is_type_atomic(true_type, ATOMIC_TYPE_VOID) ||
- !is_type_atomic(false_type, ATOMIC_TYPE_VOID)) {
+ if (!is_type_void(true_type) || !is_type_void(false_type)) {
warningf(WARN_OTHER, pos, "ISO C forbids conditional expression with only one void side");
}
result_type = type_void;
type_t *to2 = skip_typeref(other_type->pointer.points_to);
type_t *to;
- if (is_type_atomic(to1, ATOMIC_TYPE_VOID) ||
- is_type_atomic(to2, ATOMIC_TYPE_VOID)) {
+ if (is_type_void(to1) || is_type_void(to2)) {
to = type_void;
} else if (types_compatible(get_unqualified_type(to1),
get_unqualified_type(to2))) {
eat(T___builtin_classify_type);
- expect('(', end_error);
+ expect('(');
add_anchor_token(')');
expression_t *expression = parse_expression();
rem_anchor_token(')');
- expect(')', end_error);
+ expect(')');
result->classify_type.type_expression = expression;
return result;
-end_error:
- return create_error_expression();
}
/**
if (next_if('[')) {
result->kind = EXPR_UNARY_DELETE_ARRAY;
- expect(']', end_error);
-end_error:;
+ expect(']');
}
expression_t *const value = parse_subexpression(PREC_CAST);
errorf(&value->base.source_position,
"operand of delete must have pointer type");
}
- } else if (is_type_atomic(skip_typeref(type->pointer.points_to), ATOMIC_TYPE_VOID)) {
+ } else if (is_type_void(skip_typeref(type->pointer.points_to))) {
source_position_t const *const pos = &value->base.source_position;
warningf(WARN_OTHER, pos, "deleting 'void*' is undefined");
}
"cannot throw object of incomplete type '%T'", orig_type);
} else if (is_type_pointer(type)) {
type_t *const points_to = skip_typeref(type->pointer.points_to);
- if (is_type_incomplete(points_to) &&
- !is_type_atomic(points_to, ATOMIC_TYPE_VOID)) {
+ if (is_type_incomplete(points_to) && !is_type_void(points_to)) {
errorf(&value->base.source_position,
"cannot throw pointer to incomplete type '%T'", orig_type);
}
points_to = skip_typeref(points_to);
if (is_type_incomplete(points_to)) {
- if (!GNU_MODE || !is_type_atomic(points_to, ATOMIC_TYPE_VOID)) {
+ if (!GNU_MODE || !is_type_void(points_to)) {
errorf(source_position,
"arithmetic with pointer to incomplete type '%T' not allowed",
orig_pointer_type);
"subtracting pointers to incompatible types '%T' and '%T'",
orig_type_left, orig_type_right);
} else if (!is_type_object(unqual_left)) {
- if (!is_type_atomic(unqual_left, ATOMIC_TYPE_VOID)) {
+ if (!is_type_void(unqual_left)) {
errorf(pos, "subtracting pointers to non-object types '%T'",
orig_type_left);
} else {
switch (expr->kind) {
case EXPR_ERROR: return true; /* do NOT warn */
case EXPR_REFERENCE: return false;
- case EXPR_REFERENCE_ENUM_VALUE: return false;
+ case EXPR_ENUM_CONSTANT: return false;
case EXPR_LABEL_ADDRESS: return false;
/* suppress the warning for microsoft __noop operations */
case EXPR_LITERAL_CHARACTER:
case EXPR_LITERAL_WIDE_CHARACTER:
case EXPR_LITERAL_INTEGER:
- case EXPR_LITERAL_INTEGER_OCTAL:
- case EXPR_LITERAL_INTEGER_HEXADECIMAL:
case EXPR_LITERAL_FLOATINGPOINT:
- case EXPR_LITERAL_FLOATINGPOINT_HEXADECIMAL: return false;
case EXPR_STRING_LITERAL: return false;
case EXPR_WIDE_STRING_LITERAL: return false;
* suppress the warning */
case EXPR_UNARY_CAST: {
type_t *const type = skip_typeref(expr->base.type);
- return is_type_atomic(type, ATOMIC_TYPE_VOID);
+ return is_type_void(type);
}
case EXPR_UNARY_ASSUME: return true;
static expression_t *parse_subexpression(precedence_t precedence)
{
- if (token.kind < 0) {
- return expected_expression_error();
- }
-
expression_parser_function_t *parser
= &expression_parsers[token.kind];
expression_t *left;
assert(left != NULL);
while (true) {
- if (token.kind < 0) {
- return expected_expression_error();
- }
-
parser = &expression_parsers[token.kind];
if (parser->infix_parser == NULL)
break;
while (token.kind == T_STRING_LITERAL || token.kind == '[') {
asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0]));
- memset(argument, 0, sizeof(argument[0]));
if (next_if('[')) {
- if (token.kind != T_IDENTIFIER) {
- parse_error_expected("while parsing asm argument",
- T_IDENTIFIER, NULL);
+ add_anchor_token(']');
+ argument->symbol = expect_identifier("while parsing asm argument", NULL);
+ rem_anchor_token(']');
+ expect(']');
+ if (!argument->symbol)
return NULL;
- }
- argument->symbol = token.identifier.symbol;
-
- expect(']', end_error);
}
argument->constraints = parse_string_literals();
- expect('(', end_error);
+ expect('(');
add_anchor_token(')');
expression_t *expression = parse_expression();
rem_anchor_token(')');
mark_vars_read(expression, NULL);
}
argument->expression = expression;
- expect(')', end_error);
+ expect(')');
set_address_taken(expression, true);
}
return result;
-end_error:
- return NULL;
}
/**
if (next_if(T_volatile))
asm_statement->is_volatile = true;
- expect('(', end_error);
+ expect('(');
add_anchor_token(')');
if (token.kind != T_STRING_LITERAL) {
parse_error_expected("after asm(", T_STRING_LITERAL, NULL);
end_of_asm:
rem_anchor_token(')');
- expect(')', end_error);
- expect(';', end_error);
+ expect(')');
+ expect(';');
if (asm_statement->outputs == NULL) {
/* GCC: An 'asm' instruction without any output operands will be treated
}
return statement;
-end_error:
- return create_error_statement();
}
static statement_t *parse_label_inner_statement(statement_t const *const label, char const *const label_kind)
source_position_t *const pos = &statement->base.source_position;
eat(T_case);
+ add_anchor_token(':');
+
+ expression_t *expression = parse_expression();
+ type_t *expression_type = expression->base.type;
+ type_t *skipped = skip_typeref(expression_type);
+ if (!is_type_integer(skipped) && is_type_valid(skipped)) {
+ errorf(pos, "case expression '%E' must have integer type but has type '%T'",
+ expression, expression_type);
+ }
+
+ type_t *type = expression_type;
+ if (current_switch != NULL) {
+ type_t *switch_type = current_switch->expression->base.type;
+ if (is_type_valid(switch_type)) {
+ expression = create_implicit_cast(expression, switch_type);
+ }
+ }
- expression_t *const expression = parse_expression();
statement->case_label.expression = expression;
expression_classification_t const expr_class = is_constant_expression(expression);
if (expr_class != EXPR_CLASS_CONSTANT) {
if (GNU_MODE) {
if (next_if(T_DOTDOTDOT)) {
- expression_t *const end_range = parse_expression();
+ expression_t *end_range = parse_expression();
+ expression_type = expression->base.type;
+ skipped = skip_typeref(expression_type);
+ if (!is_type_integer(skipped) && is_type_valid(skipped)) {
+ errorf(pos, "case expression '%E' must have integer type but has type '%T'",
+ expression, expression_type);
+ }
+
+ end_range = create_implicit_cast(end_range, type);
statement->case_label.end_range = end_range;
expression_classification_t const end_class = is_constant_expression(end_range);
if (end_class != EXPR_CLASS_CONSTANT) {
PUSH_PARENT(statement);
- expect(':', end_error);
-end_error:
+ rem_anchor_token(':');
+ expect(':');
if (current_switch != NULL) {
if (! statement->case_label.is_bad) {
PUSH_PARENT(statement);
- expect(':', end_error);
-end_error:
+ expect(':');
if (current_switch != NULL) {
const case_label_statement_t *def_label = current_switch->default_label;
return stmt;
}
+/**
+ * Parse an expression in parentheses and mark its variables as read.
+ */
+static expression_t *parse_condition(void)
+{
+ expect('(');
+ add_anchor_token(')');
+ expression_t *const expr = parse_expression();
+ mark_vars_read(expr, NULL);
+ rem_anchor_token(')');
+ expect(')');
+ return expr;
+}
+
/**
* Parse an if statement.
*/
eat(T_if);
PUSH_PARENT(statement);
+ PUSH_SCOPE_STATEMENT(&statement->ifs.scope);
- add_anchor_token('{');
+ add_anchor_token(T_else);
- expect('(', end_error);
- add_anchor_token(')');
- expression_t *const expr = parse_expression();
+ expression_t *const expr = parse_condition();
statement->ifs.condition = expr;
/* §6.8.4.1:1 The controlling expression of an if statement shall have
* scalar type. */
semantic_condition(expr, "condition of 'if'-statment");
- mark_vars_read(expr, NULL);
- rem_anchor_token(')');
- expect(')', end_error);
-end_error:
- rem_anchor_token('{');
-
- add_anchor_token(T_else);
statement_t *const true_stmt = parse_inner_statement();
statement->ifs.true_statement = true_stmt;
rem_anchor_token(T_else);
warningf(WARN_PARENTHESES, pos, "suggest explicit braces to avoid ambiguous 'else'");
}
+ POP_SCOPE();
POP_PARENT();
return statement;
}
eat(T_switch);
PUSH_PARENT(statement);
+ PUSH_SCOPE_STATEMENT(&statement->switchs.scope);
- expect('(', end_error);
- add_anchor_token(')');
- expression_t *const expr = parse_expression();
- mark_vars_read(expr, NULL);
+ expression_t *const expr = parse_condition();
type_t * type = skip_typeref(expr->base.type);
if (is_type_integer(type)) {
type = promote_integer(type);
type = type_error_type;
}
statement->switchs.expression = create_implicit_cast(expr, type);
- expect(')', end_error);
- rem_anchor_token(')');
switch_statement_t *rem = current_switch;
current_switch = &statement->switchs;
}
check_enum_cases(&statement->switchs);
+ POP_SCOPE();
POP_PARENT();
return statement;
-end_error:
- POP_PARENT();
- return create_error_statement();
}
static statement_t *parse_loop_body(statement_t *const loop)
eat(T_while);
PUSH_PARENT(statement);
+ PUSH_SCOPE_STATEMENT(&statement->whiles.scope);
- expect('(', end_error);
- add_anchor_token(')');
- expression_t *const cond = parse_expression();
+ expression_t *const cond = parse_condition();
statement->whiles.condition = cond;
/* §6.8.5:2 The controlling expression of an iteration statement shall
* have scalar type. */
semantic_condition(cond, "condition of 'while'-statement");
- mark_vars_read(cond, NULL);
- rem_anchor_token(')');
- expect(')', end_error);
statement->whiles.body = parse_loop_body(statement);
+ POP_SCOPE();
POP_PARENT();
return statement;
-end_error:
- POP_PARENT();
- return create_error_statement();
}
/**
eat(T_do);
PUSH_PARENT(statement);
+ PUSH_SCOPE_STATEMENT(&statement->do_while.scope);
add_anchor_token(T_while);
statement->do_while.body = parse_loop_body(statement);
rem_anchor_token(T_while);
- expect(T_while, end_error);
- expect('(', end_error);
- add_anchor_token(')');
- expression_t *const cond = parse_expression();
+ expect(T_while);
+ expression_t *const cond = parse_condition();
statement->do_while.condition = cond;
/* §6.8.5:2 The controlling expression of an iteration statement shall
* have scalar type. */
semantic_condition(cond, "condition of 'do-while'-statement");
- mark_vars_read(cond, NULL);
- rem_anchor_token(')');
- expect(')', end_error);
- expect(';', end_error);
+ expect(';');
+ POP_SCOPE();
POP_PARENT();
return statement;
-end_error:
- POP_PARENT();
- return create_error_statement();
}
/**
eat(T_for);
- expect('(', end_error1);
- add_anchor_token(')');
-
PUSH_PARENT(statement);
- PUSH_SCOPE(&statement->fors.scope);
+ PUSH_SCOPE_STATEMENT(&statement->fors.scope);
+
+ expect('(');
+ add_anchor_token(')');
PUSH_EXTENSION();
warningf(WARN_UNUSED_VALUE, &init->base.source_position, "initialisation of 'for'-statement has no effect");
}
rem_anchor_token(';');
- expect(';', end_error2);
+ expect(';');
}
POP_EXTENSION();
mark_vars_read(cond, NULL);
rem_anchor_token(';');
}
- expect(';', end_error2);
+ expect(';');
if (token.kind != ')') {
expression_t *const step = parse_expression();
statement->fors.step = step;
warningf(WARN_UNUSED_VALUE, &step->base.source_position, "step of 'for'-statement has no effect");
}
}
- expect(')', end_error2);
rem_anchor_token(')');
+ expect(')');
statement->fors.body = parse_loop_body(statement);
POP_SCOPE();
POP_PARENT();
return statement;
-
-end_error2:
- POP_PARENT();
- rem_anchor_token(')');
- POP_SCOPE();
- /* fallthrough */
-
-end_error1:
- return create_error_statement();
}
/**
*/
static statement_t *parse_goto(void)
{
- statement_t *statement = allocate_statement_zero(STATEMENT_GOTO);
- eat(T_goto);
+ statement_t *statement;
+ if (GNU_MODE && look_ahead(1)->kind == '*') {
+ statement = allocate_statement_zero(STATEMENT_COMPUTED_GOTO);
+ eat(T_goto);
+ eat('*');
- if (GNU_MODE && next_if('*')) {
expression_t *expression = parse_expression();
mark_vars_read(expression, NULL);
expression = create_implicit_cast(expression, type_void_ptr);
}
- statement->gotos.expression = expression;
- } else if (token.kind == T_IDENTIFIER) {
- label_t *const label = get_label();
- label->used = true;
- statement->gotos.label = label;
+ statement->computed_goto.expression = expression;
} else {
- if (GNU_MODE)
- parse_error_expected("while parsing goto", T_IDENTIFIER, '*', NULL);
- else
- parse_error_expected("while parsing goto", T_IDENTIFIER, NULL);
- eat_until_anchor();
- return create_error_statement();
+ statement = allocate_statement_zero(STATEMENT_GOTO);
+ eat(T_goto);
+ if (token.kind == T_IDENTIFIER) {
+ label_t *const label = get_label();
+ label->used = true;
+ statement->gotos.label = label;
+
+ /* remember the goto's in a list for later checking */
+ *goto_anchor = &statement->gotos;
+ goto_anchor = &statement->gotos.next;
+ } else {
+ if (GNU_MODE)
+ parse_error_expected("while parsing goto", T_IDENTIFIER, '*', NULL);
+ else
+ parse_error_expected("while parsing goto", T_IDENTIFIER, NULL);
+ eat_until_anchor();
+ statement->gotos.label = &allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, sym_anonymous, &builtin_source_position)->label;
+ }
}
- /* remember the goto's in a list for later checking */
- *goto_anchor = &statement->gotos;
- goto_anchor = &statement->gotos.next;
-
- expect(';', end_error);
-
-end_error:
+ expect(';');
return statement;
}
statement_t *statement = allocate_statement_zero(STATEMENT_CONTINUE);
eat(T_continue);
- expect(';', end_error);
-
-end_error:
+ expect(';');
return statement;
}
statement_t *statement = allocate_statement_zero(STATEMENT_BREAK);
eat(T_break);
- expect(';', end_error);
-
-end_error:
+ expect(';');
return statement;
}
statement_t *statement = allocate_statement_zero(STATEMENT_LEAVE);
eat(T___leave);
- expect(';', end_error);
-
-end_error:
+ expect(';');
return statement;
}
return entity;
}
+static void err_or_warn(source_position_t const *const pos, char const *const msg)
+{
+ if (c_mode & _CXX || strict_mode) {
+ errorf(pos, msg);
+ } else {
+ warningf(WARN_OTHER, pos, msg);
+ }
+}
+
/**
* Parse a return statement.
*/
if (return_value != NULL) {
type_t *return_value_type = skip_typeref(return_value->base.type);
- if (is_type_atomic(return_type, ATOMIC_TYPE_VOID)) {
- if (is_type_atomic(return_value_type, ATOMIC_TYPE_VOID)) {
+ if (is_type_void(return_type)) {
+ if (!is_type_void(return_value_type)) {
/* ISO/IEC 14882:1998(E) §6.6.3:2 */
/* Only warn in C mode, because GCC does the same */
- if (c_mode & _CXX || strict_mode) {
- errorf(pos,
- "'return' with a value, in function returning 'void'");
- } else {
- warningf(WARN_OTHER, pos, "'return' with a value, in function returning 'void'");
- }
+ err_or_warn(pos, "'return' with a value, in function returning 'void'");
} else if (!(c_mode & _CXX)) { /* ISO/IEC 14882:1998(E) §6.6.3:3 */
/* Only warn in C mode, because GCC does the same */
- if (strict_mode) {
- errorf(pos,
- "'return' with expression in function returning 'void'");
- } else {
- warningf(WARN_OTHER, pos, "'return' with expression in function returning 'void'");
- }
+ err_or_warn(pos, "'return' with expression in function returning 'void'");
}
} else {
assign_error_t error = semantic_assign(return_type, return_value);
warningf(WARN_OTHER, pos, "function returns address of local variable");
}
}
- } else if (!is_type_atomic(return_type, ATOMIC_TYPE_VOID)) {
+ } else if (!is_type_void(return_type)) {
/* ISO/IEC 14882:1998(E) §6.6.3:3 */
- if (c_mode & _CXX || strict_mode) {
- errorf(pos,
- "'return' without value, in function returning non-void");
- } else {
- warningf(WARN_OTHER, pos, "'return' without value, in function returning non-void");
- }
+ err_or_warn(pos, "'return' without value, in function returning non-void");
}
statement->returns.value = return_value;
- expect(';', end_error);
-
-end_error:
+ expect(';');
return statement;
}
statement->expression.expression = expr;
mark_vars_read(expr, ENT_ANY);
- expect(';', end_error);
-
-end_error:
+ expect(';');
return statement;
}
POP_PARENT();
if (next_if(T___except)) {
- expect('(', end_error);
- add_anchor_token(')');
- expression_t *const expr = parse_expression();
- mark_vars_read(expr, NULL);
+ expression_t *const expr = parse_condition();
type_t * type = skip_typeref(expr->base.type);
if (is_type_integer(type)) {
type = promote_integer(type);
type = type_error_type;
}
statement->ms_try.except_expression = create_implicit_cast(expr, type);
- rem_anchor_token(')');
- expect(')', end_error);
- statement->ms_try.final_statement = parse_compound_statement(false);
- } else if (next_if(T__finally)) {
- statement->ms_try.final_statement = parse_compound_statement(false);
- } else {
+ } else if (!next_if(T__finally)) {
parse_error_expected("while parsing __try statement", T___except, T___finally, NULL);
- return create_error_statement();
}
+ statement->ms_try.final_statement = parse_compound_statement(false);
return statement;
-end_error:
- return create_error_statement();
}
static statement_t *parse_empty_statement(void)
entity_t *end = NULL;
entity_t **anchor = &begin;
do {
- if (token.kind != T_IDENTIFIER) {
- parse_error_expected("while parsing local label declaration",
- T_IDENTIFIER, NULL);
+ source_position_t pos;
+ symbol_t *const symbol = expect_identifier("while parsing local label declaration", &pos);
+ if (!symbol)
goto end_error;
- }
- symbol_t *symbol = token.identifier.symbol;
+
entity_t *entity = get_entity(symbol, NAMESPACE_LABEL);
if (entity != NULL && entity->base.parent_scope == current_scope) {
source_position_t const *const ppos = &entity->base.source_position;
- errorf(HERE, "multiple definitions of '%N' (previous definition %P)", entity, ppos);
+ errorf(&pos, "multiple definitions of '%N' (previous definition %P)", entity, ppos);
} else {
- entity = allocate_entity_zero(ENTITY_LOCAL_LABEL, NAMESPACE_LABEL, symbol);
- entity->base.parent_scope = current_scope;
- entity->base.source_position = token.base.source_position;
+ entity = allocate_entity_zero(ENTITY_LOCAL_LABEL, NAMESPACE_LABEL, symbol, &pos);
+ entity->base.parent_scope = current_scope;
*anchor = entity;
anchor = &entity->base.next;
environment_push(entity);
}
- next_token();
} while (next_if(','));
- expect(';', end_error);
+ expect(';');
end_error:
statement->declaration.declarations_begin = begin;
statement->declaration.declarations_end = end;
}
if (entity == NULL) {
- entity = allocate_entity_zero(ENTITY_NAMESPACE, NAMESPACE_NORMAL, symbol);
- entity->base.source_position = token.base.source_position;
- entity->base.parent_scope = current_scope;
+ entity = allocate_entity_zero(ENTITY_NAMESPACE, NAMESPACE_NORMAL, symbol, HERE);
+ entity->base.parent_scope = current_scope;
}
if (token.kind == '=') {
append_entity(current_scope, entity);
PUSH_SCOPE(&entity->namespacee.members);
+ PUSH_CURRENT_ENTITY(entity);
- entity_t *old_current_entity = current_entity;
- current_entity = entity;
-
- expect('{', end_error);
+ add_anchor_token('}');
+ expect('{');
parse_externals();
- expect('}', end_error);
+ rem_anchor_token('}');
+ expect('}');
-end_error:
- assert(current_entity == entity);
- current_entity = old_current_entity;
+ POP_CURRENT_ENTITY();
POP_SCOPE();
}
*/
static statement_t *intern_parse_statement(void)
{
- statement_t *statement = NULL;
-
/* declaration or statement */
- add_anchor_token(';');
+ statement_t *statement;
switch (token.kind) {
case T_IDENTIFIER: {
token_kind_t la1_type = (token_kind_t)look_ahead(1)->kind;
default:
errorf(HERE, "unexpected token %K while parsing statement", &token);
statement = create_error_statement();
- if (!at_anchor())
- next_token();
+ eat_until_anchor();
break;
}
- rem_anchor_token(';');
-
- assert(statement != NULL
- && statement->base.source_position.input_name != NULL);
return statement;
}
add_anchor_token('*');
add_anchor_token('+');
add_anchor_token('-');
+ add_anchor_token(';');
add_anchor_token('{');
add_anchor_token('~');
add_anchor_token(T_CHARACTER_CONSTANT);
statement_t **anchor = &statement->compound.statements;
bool only_decls_so_far = true;
- while (token.kind != '}') {
- if (token.kind == T_EOF) {
- errorf(&statement->base.source_position,
- "EOF while parsing compound statement");
- break;
- }
+ while (token.kind != '}' && token.kind != T_EOF) {
statement_t *sub_statement = intern_parse_statement();
if (sub_statement->kind == STATEMENT_ERROR) {
- /* an error occurred. if we are at an anchor, return */
- if (at_anchor())
- goto end_error;
- continue;
+ break;
}
if (sub_statement->kind != STATEMENT_DECLARATION) {
}
*anchor = sub_statement;
-
- while (sub_statement->base.next != NULL)
- sub_statement = sub_statement->base.next;
-
- anchor = &sub_statement->base.next;
+ anchor = &sub_statement->base.next;
}
- next_token();
+ expect('}');
/* look over all statements again to produce no effect warnings */
if (is_warn_on(WARN_UNUSED_VALUE)) {
}
}
-end_error:
rem_anchor_token(T_while);
rem_anchor_token(T_wchar_t);
rem_anchor_token(T_volatile);
rem_anchor_token(T_CHARACTER_CONSTANT);
rem_anchor_token('~');
rem_anchor_token('{');
+ rem_anchor_token(';');
rem_anchor_token('-');
rem_anchor_token('+');
rem_anchor_token('*');
statement_t *statement = allocate_statement_zero(STATEMENT_ASM);
eat(T_asm);
- expect('(', end_error);
+ add_anchor_token(';');
+ add_anchor_token(')');
+ add_anchor_token(T_STRING_LITERAL);
+ expect('(');
+ rem_anchor_token(T_STRING_LITERAL);
statement->asms.asm_text = parse_string_literals();
statement->base.next = unit->global_asm;
unit->global_asm = statement;
- expect(')', end_error);
- expect(';', end_error);
-
-end_error:;
+ rem_anchor_token(')');
+ expect(')');
+ rem_anchor_token(';');
+ expect(';');
}
static void parse_linkage_specification(void)
linkage_kind_t old_linkage = current_linkage;
linkage_kind_t new_linkage;
- if (strcmp(linkage, "C") == 0) {
+ if (streq(linkage, "C")) {
new_linkage = LINKAGE_C;
- } else if (strcmp(linkage, "C++") == 0) {
+ } else if (streq(linkage, "C++")) {
new_linkage = LINKAGE_CXX;
} else {
errorf(&pos, "linkage string \"%s\" not recognized", linkage);
if (next_if('{')) {
parse_externals();
- expect('}', end_error);
+ expect('}');
} else {
parse_external();
}
-end_error:
assert(current_linkage == new_linkage);
current_linkage = old_linkage;
}
}
}
-void prepare_main_collect2(entity_t *entity)
+static void prepare_main_collect2(entity_t *const entity)
{
+ PUSH_SCOPE(&entity->function.statement->compound.scope);
+
// create call to __main
symbol_t *symbol = symbol_table_insert("__main");
entity_t *subsubmain_ent
expr_statement->base.next = compounds->statements;
compounds->statements = expr_statement;
+
+ POP_SCOPE();
}
void parse(void)