#include <stdarg.h>
#include <stdbool.h>
+#include "adt/strutil.h"
#include "parser.h"
#include "diagnostic.h"
#include "format_check.h"
#include "entity_t.h"
#include "attribute_t.h"
#include "lang_features.h"
-#include "walk_statements.h"
+#include "walk.h"
#include "warning.h"
#include "printer.h"
#include "adt/bitfiddle.h"
/** Point to the current function declaration if inside a function. */
static function_t *current_function = NULL;
static entity_t *current_entity = 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 linkage_kind_t current_linkage;
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;
-/** true if we are in a type property context (evaluation only for type) */
-static bool in_type_prop = false;
/** true if we are in an __extension__ context. */
static bool in_gcc_extension = false;
static struct obstack temp_obst;
static elf_visibility_tag_t default_visibility = ELF_VISIBILITY_DEFAULT;
-#define PUSH_PARENT(stmt) \
- statement_t *const prev_parent = current_parent; \
- ((void)(current_parent = (stmt)))
-#define POP_PARENT ((void)(current_parent = prev_parent))
+#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; \
+ ((void)(current_parent = new_parent))
+#define POP_PARENT() (assert(current_parent == new_parent), (void)(current_parent = old_parent))
+
+#define PUSH_SCOPE(scope) \
+ size_t const top = environment_top(); \
+ scope_t *const new_scope = (scope); \
+ 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; \
+ bool const old_gcc_extension = in_gcc_extension; \
+ while (next_if(T___extension__)) { \
+ in_gcc_extension = true; \
+ } \
+ do {} while (0)
+#define POP_EXTENSION() \
+ ((void)(in_gcc_extension = old_gcc_extension))
/** special symbol used for anonymous entities. */
static symbol_t *sym_anonymous = NULL;
/** The token anchor set */
-static unsigned char token_anchor_set[T_LAST_TOKEN];
+static unsigned short token_anchor_set[T_LAST_TOKEN];
/** The current source position. */
-#define HERE (&token.source_position)
+#define HERE (&token.base.source_position)
/** true if we are in GCC mode. */
#define GNU_MODE ((c_mode & _GNUC) || in_gcc_extension)
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: \
- case T_WIDE_CHARACTER_CONSTANT: \
- case T_WIDE_STRING_LITERAL: \
case T___FUNCDNAME__: \
case T___FUNCSIG__: \
- case T___FUNCTION__: \
case T___PRETTY_FUNCTION__: \
case T___alignof__: \
case T___builtin_classify_type: \
static size_t get_statement_struct_size(statement_kind_t kind)
{
static const size_t sizes[] = {
- [STATEMENT_INVALID] = sizeof(invalid_statement_t),
- [STATEMENT_EMPTY] = sizeof(empty_statement_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 size_t get_expression_struct_size(expression_kind_t kind)
{
static const size_t sizes[] = {
- [EXPR_INVALID] = sizeof(expression_base_t),
+ [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_LITERAL_CHARACTER] = sizeof(string_literal_expression_t),
[EXPR_STRING_LITERAL] = sizeof(string_literal_expression_t),
- [EXPR_WIDE_STRING_LITERAL] = sizeof(string_literal_expression_t),
[EXPR_COMPOUND_LITERAL] = sizeof(compound_literal_expression_t),
[EXPR_CALL] = sizeof(call_expression_t),
[EXPR_UNARY_FIRST] = sizeof(unary_expression_t),
res->base.kind = kind;
res->base.parent = current_parent;
- res->base.source_position = token.source_position;
+ res->base.source_position = *HERE;
return res;
}
res->base.kind = kind;
res->base.type = type_error_type;
- res->base.source_position = token.source_position;
+ res->base.source_position = *HERE;
return res;
}
* Creates a new invalid expression at the source position
* of the current token.
*/
-static expression_t *create_invalid_expression(void)
+static expression_t *create_error_expression(void)
{
- return allocate_expression_zero(EXPR_INVALID);
+ expression_t *expression = allocate_expression_zero(EXPR_ERROR);
+ expression->base.type = type_error_type;
+ return expression;
}
/**
* Creates a new invalid statement.
*/
-static statement_t *create_invalid_statement(void)
+static statement_t *create_error_statement(void)
{
- return allocate_statement_zero(STATEMENT_INVALID);
+ return allocate_statement_zero(STATEMENT_ERROR);
}
/**
return allocate_statement_zero(STATEMENT_EMPTY);
}
-static function_parameter_t *allocate_parameter(type_t *const type)
-{
- function_parameter_t *const param
- = obstack_alloc(type_obst, sizeof(*param));
- memset(param, 0, sizeof(*param));
- param->type = type;
- return param;
-}
-
/**
* Returns the size of an initializer node.
*
{
static const size_t sizes[] = {
[INITIALIZER_VALUE] = sizeof(initializer_value_t),
- [INITIALIZER_STRING] = sizeof(initializer_string_t),
- [INITIALIZER_WIDE_STRING] = sizeof(initializer_wide_string_t),
+ [INITIALIZER_STRING] = sizeof(initializer_value_t),
[INITIALIZER_LIST] = sizeof(initializer_list_t),
[INITIALIZER_DESIGNATOR] = sizeof(initializer_designator_t)
};
#endif
}
-static inline bool next_if(int const type)
+#define eat(token_kind) (assert(token.kind == (token_kind)), next_token())
+
+static inline bool next_if(token_kind_t const type)
{
- if (token.type == type) {
- next_token();
+ if (token.kind == type) {
+ eat(type);
return true;
} else {
return false;
/**
* Adds a token type to the token type anchor set (a multi-set).
*/
-static void add_anchor_token(int token_type)
-{
- assert(0 <= token_type && token_type < T_LAST_TOKEN);
- ++token_anchor_set[token_type];
-}
-
-/**
- * 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_type)
-{
- assert(0 <= token_type && token_type < T_LAST_TOKEN);
- int count = token_anchor_set[token_type];
- token_anchor_set[token_type] = 0;
- return count;
-}
-
-/**
- * Restore the number of token types to the given count.
- */
-static void restore_anchor_state(int token_type, int count)
+static void add_anchor_token(token_kind_t const token_kind)
{
- assert(0 <= token_type && token_type < T_LAST_TOKEN);
- token_anchor_set[token_type] = count;
+ assert(token_kind < T_LAST_TOKEN);
+ ++token_anchor_set[token_kind];
}
/**
* Remove a token type from the token type anchor set (a multi-set).
*/
-static void rem_anchor_token(int token_type)
+static void rem_anchor_token(token_kind_t const token_kind)
{
- assert(0 <= token_type && token_type < T_LAST_TOKEN);
- assert(token_anchor_set[token_type] != 0);
- --token_anchor_set[token_type];
-}
-
-/**
- * Return true if the token type of the current token is
- * in the anchor set.
- */
-static bool at_anchor(void)
-{
- if (token.type < 0)
- return false;
- return token_anchor_set[token.type];
+ assert(token_kind < T_LAST_TOKEN);
+ assert(token_anchor_set[token_kind] != 0);
+ --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;
unsigned parenthesis_count = 0;
unsigned brace_count = 0;
unsigned bracket_count = 0;
- while (token.type != end_token ||
+ while (token.kind != end_token ||
parenthesis_count != 0 ||
brace_count != 0 ||
bracket_count != 0) {
- switch (token.type) {
+ switch (token.kind) {
case T_EOF: return;
case '(': ++parenthesis_count; break;
case '{': ++brace_count; break;
if (bracket_count > 0)
--bracket_count;
check_stop:
- if (token.type == end_token &&
+ if (token.kind == end_token &&
parenthesis_count == 0 &&
brace_count == 0 &&
bracket_count == 0)
*/
static void eat_until_anchor(void)
{
- while (token_anchor_set[token.type] == 0) {
- if (token.type == '(' || token.type == '{' || token.type == '[')
- eat_until_matching_token(token.type);
+ while (token_anchor_set[token.kind] == 0) {
+ if (token.kind == '(' || token.kind == '{' || token.kind == '[')
+ eat_until_matching_token(token.kind);
next_token();
}
}
next_if('}');
}
-#define eat(token_type) (assert(token.type == (token_type)), next_token())
-
/**
* Report a parse error because an expected token was not found.
*/
msg, type1, type2);
}
+static bool skip_till(token_kind_t const expected, char const *const context)
+{
+ if (UNLIKELY(token.kind != expected)) {
+ parse_error_expected(context, expected, NULL);
+ add_anchor_token(expected);
+ eat_until_anchor();
+ rem_anchor_token(expected);
+ if (token.kind != expected)
+ return false;
+ }
+ return true;
+}
+
/**
* 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.type != (expected))) { \
- parse_error_expected(NULL, (expected), NULL); \
- add_anchor_token(expected); \
- eat_until_anchor(); \
- next_if((expected)); \
- rem_anchor_token(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 (skip_till(expected, NULL))
+ eat(expected);
+}
+
+static symbol_t *expect_identifier(char const *const context, source_position_t *const pos)
+{
+ if (!skip_till(T_IDENTIFIER, context))
+ return NULL;
+ symbol_t *const sym = token.base.symbol;
+ if (pos)
+ *pos = *HERE;
+ eat(T_IDENTIFIER);
+ return sym;
+}
/**
* Push a given scope on the scope stack and make it the
static entity_t *get_entity(const symbol_t *const symbol,
namespace_tag_t namespc)
{
- assert(namespc != NAMESPACE_INVALID);
entity_t *entity = symbol->entity;
for (; entity != NULL; entity = entity->base.symbol_next) {
if ((namespace_tag_t)entity->base.namespc == namespc)
{
symbol_t *symbol = entity->base.symbol;
entity_namespace_t namespc = entity->base.namespc;
- assert(namespc != NAMESPACE_INVALID);
+ assert(namespc != 0);
/* replace/add entity into entity list of the symbol */
entity_t **anchor;
stack_pop_to(&label_stack, new_top);
}
-static int get_akind_rank(atomic_type_kind_t akind)
-{
- return (int) akind;
-}
-
-/**
- * Return the type rank for an atomic type.
- */
-static int get_rank(const type_t *type)
+static atomic_type_kind_t get_akind(const type_t *type)
{
- assert(!is_typeref(type));
- if (type->kind == TYPE_ENUM)
- return get_akind_rank(type->enumt.akind);
-
- assert(type->kind == TYPE_ATOMIC);
- return get_akind_rank(type->atomic.akind);
+ assert(type->kind == TYPE_ATOMIC || type->kind == TYPE_COMPLEX
+ || type->kind == TYPE_IMAGINARY || type->kind == TYPE_ENUM);
+ return type->atomic.akind;
}
/**
*/
static type_t *promote_integer(type_t *type)
{
- if (type->kind == TYPE_BITFIELD)
- type = type->bitfield.base_type;
-
- if (get_rank(type) < get_akind_rank(ATOMIC_TYPE_INT))
+ if (get_akind_rank(get_akind(type)) < get_akind_rank(ATOMIC_TYPE_INT))
type = type_int;
return type;
}
-/**
- * Create a cast expression.
- *
- * @param expression the expression to cast
- * @param dest_type the destination type
- */
-static expression_t *create_cast_expression(expression_t *expression,
- type_t *dest_type)
-{
- expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST_IMPLICIT);
-
- cast->unary.value = expression;
- cast->base.type = dest_type;
-
- return cast;
-}
-
/**
* Check if a given expression represents a null pointer constant.
*
static bool is_null_pointer_constant(const expression_t *expression)
{
/* skip void* cast */
- if (expression->kind == EXPR_UNARY_CAST ||
- expression->kind == EXPR_UNARY_CAST_IMPLICIT) {
+ if (expression->kind == EXPR_UNARY_CAST) {
type_t *const type = skip_typeref(expression->base.type);
if (types_compatible(type, type_void_ptr))
expression = expression->unary.value;
if (source_type == dest_type)
return expression;
- return create_cast_expression(expression, dest_type);
+ expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST);
+ cast->unary.value = expression;
+ cast->base.type = dest_type;
+ cast->base.implicit = true;
+
+ return cast;
}
typedef enum assign_error_t {
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 parse_subexpression(PREC_ASSIGNMENT);
}
-static void warn_string_concat(const source_position_t *pos)
+static void append_string(string_t const *const s)
{
- warningf(WARN_TRADITIONAL, pos, "traditional C rejects string constant concatenation");
+ /* FIXME Using the ast_obstack is a hack. Using the symbol_obstack is not
+ * possible, because other tokens are grown there alongside. */
+ obstack_grow(&ast_obstack, s->begin, s->size);
}
-static string_t parse_string_literals(void)
+static string_t finish_string(void)
{
- assert(token.type == T_STRING_LITERAL);
- string_t result = token.literal;
+ obstack_1grow(&ast_obstack, '\0');
+ size_t const size = obstack_object_size(&ast_obstack) - 1;
+ char const *const string = obstack_finish(&ast_obstack);
+ return (string_t){ string, size };
+}
- next_token();
+static string_t concat_string_literals(string_encoding_t *const out_enc)
+{
+ assert(token.kind == T_STRING_LITERAL);
- while (token.type == T_STRING_LITERAL) {
- warn_string_concat(&token.source_position);
- result = concat_strings(&result, &token.literal);
- next_token();
+ string_t result;
+ string_encoding_t enc = token.string.encoding;
+ if (look_ahead(1)->kind == T_STRING_LITERAL) {
+ append_string(&token.string.string);
+ eat(T_STRING_LITERAL);
+ warningf(WARN_TRADITIONAL, HERE, "traditional C rejects string constant concatenation");
+ do {
+ if (token.string.encoding != STRING_ENCODING_CHAR) {
+ enc = token.string.encoding;
+ }
+ append_string(&token.string.string);
+ eat(T_STRING_LITERAL);
+ } while (token.kind == T_STRING_LITERAL);
+ result = finish_string();
+ } else {
+ result = token.string.string;
+ eat(T_STRING_LITERAL);
}
+ *out_enc = enc;
return result;
}
-/**
- * compare two string, ignoring double underscores on the second.
- */
-static int strcmp_underscore(const char *s1, const char *s2)
+static string_t parse_string_literals(char const *const context)
{
- 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);
- }
+ if (!skip_till(T_STRING_LITERAL, context))
+ return (string_t){ "", 0 };
+
+ string_encoding_t enc;
+ source_position_t const pos = *HERE;
+ string_t const res = concat_string_literals(&enc);
+
+ if (enc != STRING_ENCODING_CHAR) {
+ errorf(&pos, "expected plain string literal, got wide string literal");
}
- return strcmp(s1, s2);
+ return res;
}
static attribute_t *allocate_attribute_zero(attribute_kind_t kind)
{
attribute_t *attribute = allocate_ast_zero(sizeof(*attribute));
- attribute->kind = kind;
+ attribute->kind = kind;
+ attribute->source_position = *HERE;
return attribute;
}
{
attribute_argument_t *first = NULL;
attribute_argument_t **anchor = &first;
- if (token.type != ')') do {
+ if (token.kind != ')') do {
attribute_argument_t *argument = allocate_ast_zero(sizeof(*argument));
/* is it an identifier */
- if (token.type == T_IDENTIFIER
- && (look_ahead(1)->type == ',' || look_ahead(1)->type == ')')) {
- symbol_t *symbol = token.symbol;
+ if (token.kind == T_IDENTIFIER
+ && (look_ahead(1)->kind == ',' || look_ahead(1)->kind == ')')) {
argument->kind = ATTRIBUTE_ARGUMENT_SYMBOL;
- argument->v.symbol = symbol;
- next_token();
+ argument->v.symbol = token.base.symbol;
+ eat(T_IDENTIFIER);
} else {
/* must be an expression */
expression_t *expression = parse_assignment_expression();
*anchor = argument;
anchor = &argument->next;
} while (next_if(','));
- expect(')', end_error);
-
- return first;
-
-end_error:
- /* TODO... */
+ expect(')');
return first;
}
static attribute_t *parse_attribute_asm(void)
{
- eat(T_asm);
-
attribute_t *attribute = allocate_attribute_zero(ATTRIBUTE_GNU_ASM);
-
- expect('(', end_error);
+ eat(T_asm);
+ expect('(');
attribute->a.arguments = parse_attribute_arguments();
return attribute;
-
-end_error:
- return NULL;
-}
-
-static symbol_t *get_symbol_from_token(void)
-{
- switch(token.type) {
- case T_IDENTIFIER:
- return token.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_symbol(&token);
- default:
- return NULL;
- }
}
static attribute_t *parse_attribute_gnu_single(void)
{
/* parse "any-word" */
- symbol_t *symbol = get_symbol_from_token();
+ symbol_t *const symbol = token.base.symbol;
if (symbol == NULL) {
parse_error_expected("while parsing attribute((", T_IDENTIFIER, NULL);
return NULL;
}
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;
}
- next_token();
-
attribute_t *attribute = allocate_attribute_zero(kind);
+ next_token();
/* parse arguments */
if (next_if('('))
attribute_t **anchor = &first;
eat(T___attribute__);
- expect('(', end_error);
- expect('(', end_error);
+ add_anchor_token(')');
+ add_anchor_token(',');
+ expect('(');
+ expect('(');
- if (token.type != ')') do {
+ 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;
}
anchor = &(*anchor)->next;
attribute_t *attribute;
- switch (token.type) {
+ switch (token.kind) {
case T___attribute__:
attribute = parse_attribute_gnu();
if (attribute == NULL)
break;
case T_cdecl:
- next_token();
attribute = allocate_attribute_zero(ATTRIBUTE_MS_CDECL);
+ eat(T_cdecl);
break;
case T__fastcall:
- next_token();
attribute = allocate_attribute_zero(ATTRIBUTE_MS_FASTCALL);
+ eat(T__fastcall);
break;
case T__forceinline:
- next_token();
attribute = allocate_attribute_zero(ATTRIBUTE_MS_FORCEINLINE);
+ eat(T__forceinline);
break;
case T__stdcall:
- next_token();
attribute = allocate_attribute_zero(ATTRIBUTE_MS_STDCALL);
+ eat(T__stdcall);
break;
case T___thiscall:
/* TODO record modifier */
warningf(WARN_OTHER, HERE, "Ignoring declaration modifier %K", &token);
- eat(T___thiscall);
attribute = allocate_attribute_zero(ATTRIBUTE_MS_THISCALL);
+ eat(T___thiscall);
break;
default:
ent = determine_lhs_ent(ref, lhs_ent);
lhs_ent = ent;
} else {
- mark_vars_read(expr->select.compound, lhs_ent);
+ mark_vars_read(ref, lhs_ent);
}
mark_vars_read(expr->array_access.index, lhs_ent);
return ent;
}
case EXPR_SELECT: {
- if (is_type_compound(skip_typeref(expr->base.type))) {
+ mark_vars_read(expr->select.compound, lhs_ent);
+ if (is_type_compound(skip_typeref(expr->base.type)))
return determine_lhs_ent(expr->select.compound, lhs_ent);
- } else {
- mark_vars_read(expr->select.compound, lhs_ent);
- return NULL;
- }
+ return NULL;
}
case EXPR_UNARY_DEREFERENCE: {
return;
if (lhs_ent != entity && lhs_ent != ENT_ANY) {
- if (entity->kind == ENTITY_VARIABLE) {
- entity->variable.read = true;
- } else {
- entity->parameter.read = true;
- }
+ entity->variable.read = true;
}
return;
}
return;
case EXPR_ARRAY_ACCESS: {
+ mark_vars_read(expr->array_access.index, lhs_ent);
expression_t *const ref = expr->array_access.array_ref;
+ if (!is_type_array(skip_typeref(revert_automatic_type_conversion(ref)))) {
+ if (lhs_ent == ENT_ANY)
+ lhs_ent = NULL;
+ }
mark_vars_read(ref, lhs_ent);
- lhs_ent = determine_lhs_ent(ref, lhs_ent);
- mark_vars_read(expr->array_access.index, lhs_ent);
return;
}
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;
case EXPR_UNARY_POSTFIX_DECREMENT:
case EXPR_UNARY_PREFIX_INCREMENT:
case EXPR_UNARY_PREFIX_DECREMENT:
- case EXPR_UNARY_CAST_IMPLICIT:
case EXPR_UNARY_ASSUME:
unary:
mark_vars_read(expr->unary.value, lhs_ent);
determine_lhs_ent(expr->va_starte.ap, lhs_ent);
return;
- EXPR_LITERAL_CASES
- case EXPR_UNKNOWN:
- case EXPR_INVALID:
+ case EXPR_LITERAL_CASES:
+ case EXPR_LITERAL_CHARACTER:
+ case EXPR_ERROR:
case EXPR_STRING_LITERAL:
- case EXPR_WIDE_STRING_LITERAL:
case EXPR_COMPOUND_LITERAL: // TODO init?
case EXPR_SIZEOF:
case EXPR_CLASSIFY_TYPE:
case EXPR_OFFSETOF:
case EXPR_STATEMENT: // TODO
case EXPR_LABEL_ADDRESS:
- case EXPR_REFERENCE_ENUM_VALUE:
+ case EXPR_ENUM_CONSTANT:
return;
}
for (;;) {
designator_t *designator;
- switch (token.type) {
+ switch (token.kind) {
case '[':
designator = allocate_ast_zero(sizeof(designator[0]));
- designator->source_position = token.source_position;
- next_token();
+ designator->source_position = *HERE;
+ eat('[');
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.source_position;
- next_token();
- if (token.type != T_IDENTIFIER) {
- parse_error_expected("while parsing designator",
- T_IDENTIFIER, NULL);
+ designator->source_position = *HERE;
+ eat('.');
+ designator->symbol = expect_identifier("while parsing designator", NULL);
+ if (!designator->symbol)
return NULL;
- }
- designator->symbol = token.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,
- const string_t *const string)
-{
- /* TODO: check len vs. size of array type */
- (void) type;
-
- initializer_t *initializer = allocate_initializer_zero(INITIALIZER_STRING);
- initializer->string.string = *string;
-
- return initializer;
-}
-
-static initializer_t *initializer_from_wide_string(array_type_t *const type,
- const string_t *const string)
-{
- /* TODO: check len vs. size of array type */
- (void) type;
-
- initializer_t *const initializer =
- allocate_initializer_zero(INITIALIZER_WIDE_STRING);
- initializer->wide_string.string = *string;
-
- return initializer;
}
/**
{
/* TODO check that expression is a constant expression */
- /* §6.7.8.14/15 char array may be initialized by string literals */
- type_t *type = skip_typeref(orig_type);
- type_t *expr_type_orig = expression->base.type;
- type_t *expr_type = skip_typeref(expr_type_orig);
+ type_t *const type = skip_typeref(orig_type);
- if (is_type_array(type) && expr_type->kind == TYPE_POINTER) {
+ /* §6.7.8.14/15 char array may be initialized by string literals */
+ if (expression->kind == EXPR_STRING_LITERAL && is_type_array(type)) {
array_type_t *const array_type = &type->array;
type_t *const element_type = skip_typeref(array_type->element_type);
-
- if (element_type->kind == TYPE_ATOMIC) {
- atomic_type_kind_t akind = element_type->atomic.akind;
- switch (expression->kind) {
- case EXPR_STRING_LITERAL:
- if (akind == ATOMIC_TYPE_CHAR
- || akind == ATOMIC_TYPE_SCHAR
- || akind == ATOMIC_TYPE_UCHAR) {
- return initializer_from_string(array_type,
- &expression->string_literal.value);
- }
- break;
-
- case EXPR_WIDE_STRING_LITERAL: {
- type_t *bare_wchar_type = skip_typeref(type_wchar_t);
- if (get_unqualified_type(element_type) == bare_wchar_type) {
- return initializer_from_wide_string(array_type,
- &expression->string_literal.value);
- }
- break;
+ switch (expression->string_literal.encoding) {
+ case STRING_ENCODING_CHAR: {
+ if (is_type_atomic(element_type, ATOMIC_TYPE_CHAR) ||
+ is_type_atomic(element_type, ATOMIC_TYPE_SCHAR) ||
+ is_type_atomic(element_type, ATOMIC_TYPE_UCHAR)) {
+ goto make_string_init;
}
+ break;
+ }
- default:
- break;
+ case STRING_ENCODING_WIDE: {
+ type_t *bare_wchar_type = skip_typeref(type_wchar_t);
+ if (get_unqualified_type(element_type) == bare_wchar_type) {
+make_string_init:;
+ initializer_t *const init = allocate_initializer_zero(INITIALIZER_STRING);
+ init->value.value = expression;
+ return init;
}
+ break;
+ }
}
}
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.
*
{
/* there might be extra {} hierarchies */
int braces = 0;
- if (token.type == '{') {
+ if (token.kind == '{') {
warningf(WARN_OTHER, HERE, "extra curly braces around scalar initializer");
do {
eat('{');
++braces;
- } while (token.type == '{');
+ } while (token.kind == '{');
}
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);
bool additional_warning_displayed = false;
while (braces > 0) {
next_if(',');
- if (token.type != '}') {
+ if (token.kind != '}') {
if (!additional_warning_displayed) {
warningf(WARN_OTHER, HERE, "additional elements in scalar initializer");
additional_warning_displayed = true;
top->type = top_type;
if (is_type_compound(top_type)) {
- compound_t *compound = top_type->compound.compound;
- entity_t *entry = compound->members.entities;
+ compound_t *const compound = top_type->compound.compound;
+ entity_t *const entry = skip_unnamed_bitfields(compound->members.entities);
if (entry != NULL) {
- assert(entry->kind == ENTITY_COMPOUND_MEMBER);
top->v.compound_entry = &entry->declaration;
path->top_type = entry->declaration.type;
} else {
return false;
}
assert(iter->kind == ENTITY_COMPOUND_MEMBER);
- if (used_in_offsetof) {
- type_t *real_type = skip_typeref(iter->declaration.type);
- if (real_type->kind == TYPE_BITFIELD) {
- errorf(&designator->source_position,
- "offsetof designator '%Y' must not specify bitfield",
- symbol);
- return false;
- }
+ if (used_in_offsetof && iter->compound_member.bitfield) {
+ errorf(&designator->source_position,
+ "offsetof designator '%Y' must not specify bitfield",
+ symbol);
+ return false;
}
top->type = orig_type;
}
} else {
expression_t *array_index = designator->array_index;
- assert(designator->array_index != NULL);
+ if (is_constant_expression(array_index) != EXPR_CLASS_CONSTANT)
+ return true;
if (!is_type_array(type)) {
if (is_type_valid(type)) {
} else if (is_type_struct(type)) {
declaration_t *entry = top->v.compound_entry;
- entity_t *next_entity = entry->base.next;
+ entity_t *const next_entity = skip_unnamed_bitfields(entry->base.next);
if (next_entity != NULL) {
assert(is_declaration(next_entity));
entry = &next_entity->declaration;
{
next_if('{');
- while (token.type != '}') {
- if (token.type == T_EOF)
+ while (token.kind != '}') {
+ if (token.kind == T_EOF)
return;
- if (token.type == '{') {
+ if (token.kind == '{') {
eat_block();
continue;
}
type_t *outer_type, size_t top_path_level,
parse_initializer_env_t *env)
{
- if (token.type == '}') {
+ if (token.kind == '}') {
/* empty initializer */
return create_empty_initializer();
}
while (true) {
designator_t *designator = NULL;
- if (token.type == '.' || token.type == '[') {
+ if (token.kind == '.' || token.kind == '[') {
designator = parse_designation();
goto finish_designator;
- } else if (token.type == T_IDENTIFIER && look_ahead(1)->type == ':') {
+ } else if (token.kind == T_IDENTIFIER && look_ahead(1)->kind == ':') {
/* GNU-style designator ("identifier: value") */
designator = allocate_ast_zero(sizeof(designator[0]));
- designator->source_position = token.source_position;
- designator->symbol = token.symbol;
+ designator->source_position = *HERE;
+ designator->symbol = token.base.symbol;
eat(T_IDENTIFIER);
eat(':');
initializer_t *sub;
- if (token.type == '{') {
+ if (token.kind == '{') {
if (type != NULL && is_type_scalar(type)) {
sub = parse_scalar_initializer(type, env->must_be_constant);
} else {
if (type == NULL) {
if (env->entity != NULL) {
- errorf(HERE,
- "extra brace group at end of initializer for '%Y'",
- env->entity->base.symbol);
+ errorf(HERE, "extra brace group at end of initializer for '%N'", env->entity);
} else {
errorf(HERE, "extra brace group at end of initializer");
}
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);
source_position_t const* const pos = &expression->base.source_position;
if (env->entity != NULL) {
- warningf(WARN_OTHER, pos, "excess elements in initializer for '%Y'", env->entity->base.symbol);
+ warningf(WARN_OTHER, pos, "excess elements in initializer for '%N'", env->entity);
} else {
warningf(WARN_OTHER, pos, "excess elements in initializer");
}
}
/* handle { "string" } special case */
- if ((expression->kind == EXPR_STRING_LITERAL
- || expression->kind == EXPR_WIDE_STRING_LITERAL)
- && outer_type != NULL) {
+ if (expression->kind == EXPR_STRING_LITERAL && outer_type != NULL) {
sub = initializer_from_expression(outer_type, expression);
if (sub != NULL) {
next_if(',');
- if (token.type != '}') {
+ if (token.kind != '}') {
warningf(WARN_OTHER, HERE, "excessive elements in initializer for type '%T'", orig_type);
}
/* TODO: eat , ... */
ARR_APP1(initializer_t*, initializers, sub);
error_parse_next:
- if (token.type == '}') {
+ if (token.kind == '}') {
break;
}
- expect(',', end_error);
- if (token.type == '}') {
+ add_anchor_token('}');
+ expect(',');
+ rem_anchor_token('}');
+ if (token.kind == '}') {
break;
}
if (is_type_scalar(type)) {
result = parse_scalar_initializer(type, env->must_be_constant);
- } else if (token.type == '{') {
+ } else if (token.kind == '{') {
eat('{');
type_path_t path;
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 */
size = max_index + 1;
break;
- case INITIALIZER_STRING:
- size = result->string.string.size;
- break;
-
- case INITIALIZER_WIDE_STRING:
- size = result->wide_string.string.size;
+ case INITIALIZER_STRING: {
+ string_literal_expression_t const *const str = get_init_string(result);
+ size = get_string_len(str->encoding, &str->value) + 1;
break;
+ }
case INITIALIZER_DESIGNATOR:
case INITIALIZER_VALUE:
entity_t *entity = NULL;
attribute_t *attributes = NULL;
- if (token.type == T___attribute__) {
+ if (token.kind == T___attribute__) {
attributes = parse_attributes(NULL);
}
entity_kind_tag_t const kind = is_struct ? ENTITY_STRUCT : ENTITY_UNION;
- if (token.type == T_IDENTIFIER) {
+ if (token.kind == T_IDENTIFIER) {
/* the compound has a name, check if we have seen it already */
- symbol = token.symbol;
+ symbol = token.base.symbol;
entity = get_tag(symbol, kind);
- next_token();
+ eat(T_IDENTIFIER);
if (entity != NULL) {
if (entity->base.parent_scope != current_scope &&
- (token.type == '{' || token.type == ';')) {
+ (token.kind == '{' || token.kind == ';')) {
/* we're in an inner scope and have a definition. Shadow
* existing definition in outer scope */
entity = NULL;
- } else if (entity->compound.complete && token.type == '{') {
+ } else if (entity->compound.complete && token.kind == '{') {
source_position_t const *const ppos = &entity->base.source_position;
errorf(&pos, "multiple definitions of '%N' (previous definition %P)", entity, ppos);
/* clear members in the hope to avoid further errors */
entity->compound.members.entities = NULL;
}
}
- } else if (token.type != '{') {
+ } else if (token.kind != '{') {
char const *const msg =
is_struct ? "while parsing struct type specifier" :
"while parsing union type specifier";
}
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);
}
append_entity(current_scope, entity);
}
- if (token.type == '{') {
+ if (token.kind == '{') {
parse_compound_type_entries(&entity->compound);
/* ISO/IEC 14882:1998(E) §7.1.3:5 */
{
eat('{');
- if (token.type == '}') {
+ if (token.kind == '}') {
errorf(HERE, "empty enum not allowed");
- next_token();
+ eat('}');
return;
}
add_anchor_token('}');
+ add_anchor_token(',');
do {
- if (token.type != T_IDENTIFIER) {
- parse_error_expected("while parsing enum entry", T_IDENTIFIER, NULL);
- eat_block();
- rem_anchor_token('}');
- return;
- }
-
- entity_t *const entity = allocate_entity_zero(ENTITY_ENUM_VALUE, NAMESPACE_NORMAL, token.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.source_position;
- next_token();
+ rem_anchor_token('=');
if (next_if('=')) {
expression_t *value = parse_constant_expression();
}
record_entity(entity, false);
- } while (next_if(',') && token.type != '}');
+ } while (next_if(',') && token.kind != '}');
+ rem_anchor_token(',');
rem_anchor_token('}');
- expect('}', end_error);
-
-end_error:
- ;
+ expect('}');
}
static type_t *parse_enum_specifier(void)
symbol_t *symbol;
eat(T_enum);
- switch (token.type) {
+ switch (token.kind) {
case T_IDENTIFIER:
- symbol = token.symbol;
+ symbol = token.base.symbol;
entity = get_tag(symbol, ENTITY_ENUM);
- next_token();
+ eat(T_IDENTIFIER);
if (entity != NULL) {
if (entity->base.parent_scope != current_scope &&
- (token.type == '{' || token.type == ';')) {
+ (token.kind == '{' || token.kind == ';')) {
/* we're in an inner scope and have a definition. Shadow
* existing definition in outer scope */
entity = NULL;
- } else if (entity->enume.complete && token.type == '{') {
+ } else if (entity->enume.complete && token.kind == '{') {
source_position_t const *const ppos = &entity->base.source_position;
errorf(&pos, "multiple definitions of '%N' (previous definition %P)", entity, ppos);
}
}
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->enumt.enume = &entity->enume;
- type->enumt.akind = ATOMIC_TYPE_INT;
+ type_t *const type = allocate_type_zero(TYPE_ENUM);
+ type->enumt.enume = &entity->enume;
+ type->enumt.base.akind = ATOMIC_TYPE_INT;
- if (token.type == '{') {
+ if (token.kind == '{') {
if (symbol != NULL) {
environment_push(entity);
}
type_t *type;
- expect('(', end_error);
add_anchor_token(')');
+ expect('(');
expression_t *expression = NULL;
- bool old_type_prop = in_type_prop;
- bool old_gcc_extension = in_gcc_extension;
- in_type_prop = true;
-
- while (next_if(T___extension__)) {
- /* This can be a prefix to a typename or an expression. */
- in_gcc_extension = true;
- }
- switch (token.type) {
+ switch (token.kind) {
case T_IDENTIFIER:
- if (is_typedef_symbol(token.symbol)) {
+ if (is_typedef_symbol(token.base.symbol)) {
DECLARATION_START
type = parse_typename();
} else {
}
break;
}
- in_type_prop = old_type_prop;
- in_gcc_extension = old_gcc_extension;
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));
+ add_anchor_token(')');
+ add_anchor_token(',');
+ expect('(');
do {
- if (token.type != T_IDENTIFIER) {
- parse_error_expected("while parsing property declspec",
- T_IDENTIFIER, NULL);
- goto end_error;
- }
-
- symbol_t **prop;
- symbol_t *symbol = token.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.type != 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 = 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.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;
}
attribute_kind_t kind = ATTRIBUTE_UNKNOWN;
if (next_if(T_restrict)) {
kind = ATTRIBUTE_MS_RESTRICT;
- } else if (token.type == T_IDENTIFIER) {
- const char *name = token.symbol->string;
+ } else if (token.kind == T_IDENTIFIER) {
+ char const *const name = token.base.symbol->string;
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;
}
if (kind == ATTRIBUTE_UNKNOWN) {
warningf(WARN_ATTRIBUTE, HERE, "unknown __declspec '%s' ignored", name);
}
- eat(T_IDENTIFIER);
} else {
parse_error_expected("while parsing __declspec", T_IDENTIFIER, NULL);
return NULL;
}
attribute_t *attribute = allocate_attribute_zero(kind);
+ eat(T_IDENTIFIER);
if (kind == ATTRIBUTE_MS_PROPERTY) {
return parse_attribute_ms_property(attribute);
{
eat(T__declspec);
- expect('(', end_error);
-
- if (next_if(')'))
- return NULL;
-
add_anchor_token(')');
+ expect('(');
+ if (token.kind != ')') {
+ attribute_t **anchor = &first;
+ do {
+ while (*anchor != NULL)
+ anchor = &(*anchor)->next;
- attribute_t **anchor = &first;
- do {
- while (*anchor != NULL)
- anchor = &(*anchor)->next;
-
- attribute_t *attribute
- = parse_microsoft_extended_decl_modifier_single();
- if (attribute == NULL)
- goto end_error;
-
- *anchor = attribute;
- anchor = &attribute->next;
- } while (next_if(','));
-
- rem_anchor_token(')');
- expect(')', end_error);
- return first;
+ attribute_t *attribute
+ = parse_microsoft_extended_decl_modifier_single();
+ if (attribute == NULL)
+ break;
-end_error:
+ *anchor = attribute;
+ anchor = &attribute->next;
+ } while (next_if(','));
+ }
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;
static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
{
- type_t *type = NULL;
- type_qualifiers_t qualifiers = TYPE_QUALIFIER_NONE;
- unsigned type_specifiers = 0;
- bool newtype = false;
- bool saw_error = false;
- bool old_gcc_extension = in_gcc_extension;
+ type_t *type = NULL;
+ type_qualifiers_t qualifiers = TYPE_QUALIFIER_NONE;
+ unsigned type_specifiers = 0;
+ bool newtype = false;
+ bool saw_error = false;
memset(specifiers, 0, sizeof(*specifiers));
- specifiers->source_position = token.source_position;
+ specifiers->source_position = *HERE;
while (true) {
specifiers->attributes = parse_attributes(specifiers->attributes);
- switch (token.type) {
+ switch (token.kind) {
/* storage class */
#define MATCH_STORAGE_CLASS(token, class) \
case token: \
specifiers->storage_class = class; \
if (specifiers->thread_local) \
goto check_thread_storage_class; \
- next_token(); \
+ eat(token); \
break;
MATCH_STORAGE_CLASS(T_typedef, STORAGE_CLASS_TYPEDEF)
#define MATCH_TYPE_QUALIFIER(token, qualifier) \
case token: \
qualifiers |= qualifier; \
- next_token(); \
+ eat(token); \
break
MATCH_TYPE_QUALIFIER(T_const, TYPE_QUALIFIER_CONST);
MATCH_TYPE_QUALIFIER(T___uptr, TYPE_QUALIFIER_UPTR);
MATCH_TYPE_QUALIFIER(T___sptr, TYPE_QUALIFIER_SPTR);
- case T___extension__:
- next_token();
- in_gcc_extension = true;
- break;
-
/* type specifiers */
#define MATCH_SPECIFIER(token, specifier, name) \
case token: \
} else { \
type_specifiers |= specifier; \
} \
- next_token(); \
+ eat(token); \
break
MATCH_SPECIFIER(T__Bool, SPECIFIER_BOOL, "_Bool");
MATCH_SPECIFIER(T_wchar_t, SPECIFIER_WCHAR_T, "wchar_t");
case T_inline:
- next_token();
+ eat(T_inline);
specifiers->is_inline = true;
break;
#if 0
case T__forceinline:
- next_token();
+ eat(T__forceinline);
specifiers->modifiers |= DM_FORCEINLINE;
break;
#endif
} else {
type_specifiers |= SPECIFIER_LONG;
}
- next_token();
+ eat(T_long);
break;
-#define CHECK_DOUBLE_TYPE() \
- do { \
- if ( type != NULL) \
- errorf(HERE, "multiple data types in declaration specifiers"); \
- } while(0)
+#define CHECK_DOUBLE_TYPE() \
+ (type != NULL ? errorf(HERE, "multiple types in declaration specifiers") : (void)0)
case T_struct:
CHECK_DOUBLE_TYPE();
case T___builtin_va_list:
CHECK_DOUBLE_TYPE();
type = duplicate_type(type_valist);
- next_token();
+ eat(T___builtin_va_list);
break;
case T_IDENTIFIER: {
/* Be somewhat resilient to typos like 'unsigned lng* f()' in a
* declaration, so it doesn't generate errors about expecting '(' or
* '{' later on. */
- switch (look_ahead(1)->type) {
+ switch (look_ahead(1)->kind) {
STORAGE_CLASSES
TYPE_SPECIFIERS
case T_const:
case '&':
case '*':
errorf(HERE, "discarding stray %K in declaration specifier", &token);
- next_token();
+ eat(T_IDENTIFIER);
continue;
default:
}
}
- type_t *const typedef_type = get_typedef_type(token.symbol);
+ type_t *const typedef_type = get_typedef_type(token.base.symbol);
if (typedef_type == NULL) {
/* Be somewhat resilient to typos like 'vodi f()' at the beginning of a
* declaration, so it doesn't generate 'implicit int' followed by more
* errors later on. */
- token_type_t const la1_type = (token_type_t)look_ahead(1)->type;
+ token_kind_t const la1_type = (token_kind_t)look_ahead(1)->kind;
switch (la1_type) {
DECLARATION_START
case T_IDENTIFIER:
case '*': {
errorf(HERE, "%K does not name a type", &token);
- entity_t *entity =
- create_error_entity(token.symbol, ENTITY_TYPEDEF);
+ entity_t *const entity = create_error_entity(token.base.symbol, ENTITY_TYPEDEF);
type = allocate_type_zero(TYPE_TYPEDEF);
type->typedeft.typedefe = &entity->typedefe;
- next_token();
+ eat(T_IDENTIFIER);
saw_error = true;
continue;
}
}
}
- next_token();
+ eat(T_IDENTIFIER);
type = typedef_type;
break;
}
finish_specifiers:
specifiers->attributes = parse_attributes(specifiers->attributes);
- in_gcc_extension = old_gcc_extension;
-
if (type == NULL || (saw_error && type_specifiers != 0)) {
atomic_type_kind_t atomic_type;
} else {
errorf(pos, "multiple datatypes in declaration");
}
- goto end_error;
+ specifiers->type = type_error_type;
+ return;
}
}
if (type_specifiers & SPECIFIER_COMPLEX) {
- type = allocate_type_zero(TYPE_COMPLEX);
- type->complex.akind = atomic_type;
+ type = allocate_type_zero(TYPE_COMPLEX);
} else if (type_specifiers & SPECIFIER_IMAGINARY) {
- type = allocate_type_zero(TYPE_IMAGINARY);
- type->imaginary.akind = atomic_type;
+ type = allocate_type_zero(TYPE_IMAGINARY);
} else {
- type = allocate_type_zero(TYPE_ATOMIC);
- type->atomic.akind = atomic_type;
+ type = allocate_type_zero(TYPE_ATOMIC);
}
+ type->atomic.akind = atomic_type;
newtype = true;
} else if (type_specifiers != 0) {
errorf(&specifiers->source_position, "multiple datatypes in declaration");
if (specifiers->attributes != NULL)
type = handle_type_attributes(specifiers->attributes, type);
specifiers->type = type;
- return;
-
-end_error:
- specifiers->type = type_error_type;
}
static type_qualifiers_t parse_type_qualifiers(void)
type_qualifiers_t qualifiers = TYPE_QUALIFIER_NONE;
while (true) {
- switch (token.type) {
+ switch (token.kind) {
/* type qualifiers */
MATCH_TYPE_QUALIFIER(T_const, TYPE_QUALIFIER_CONST);
MATCH_TYPE_QUALIFIER(T_restrict, TYPE_QUALIFIER_RESTRICT);
*/
static void parse_identifier_list(scope_t *scope)
{
+ assert(token.kind == T_IDENTIFIER);
do {
- entity_t *const entity = allocate_entity_zero(ENTITY_PARAMETER, NAMESPACE_NORMAL, token.symbol);
- entity->base.source_position = token.source_position;
+ entity_t *const entity = allocate_entity_zero(ENTITY_PARAMETER, NAMESPACE_NORMAL, token.base.symbol, HERE);
/* a K&R parameter has no type, yet */
- next_token();
+ eat(T_IDENTIFIER);
if (scope != NULL)
append_entity(scope, entity);
- } while (next_if(',') && token.type == T_IDENTIFIER);
+ } while (next_if(',') && token.kind == T_IDENTIFIER);
}
static entity_t *parse_parameter(void)
static bool has_parameters(void)
{
/* func(void) is not a parameter */
- if (token.type == T_IDENTIFIER) {
- entity_t const *const entity = get_entity(token.symbol, NAMESPACE_NORMAL);
+ if (look_ahead(1)->kind != ')')
+ return true;
+ if (token.kind == T_IDENTIFIER) {
+ entity_t const *const entity = get_entity(token.base.symbol, NAMESPACE_NORMAL);
if (entity == NULL)
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;
- } else if (token.type != T_void) {
+ 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)->type != ')')
- return true;
next_token();
return false;
}
*/
static void parse_parameters(function_type_t *type, scope_t *scope)
{
- eat('(');
add_anchor_token(')');
- int saved_comma_state = save_and_reset_anchor_state(',');
-
- if (token.type == T_IDENTIFIER &&
- !is_typedef_symbol(token.symbol)) {
- token_type_t la1_type = (token_type_t)look_ahead(1)->type;
- if (la1_type == ',' || la1_type == ')') {
- type->kr_style_parameters = true;
- parse_identifier_list(scope);
- goto parameters_finished;
- }
- }
+ eat('(');
- if (token.type == ')') {
+ if (token.kind == T_IDENTIFIER &&
+ !is_typedef_symbol(token.base.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.type) {
+ switch (token.kind) {
case T_DOTDOTDOT:
- next_token();
+ eat(T_DOTDOTDOT);
type->variadic = true;
goto parameters_finished;
case T_IDENTIFIER:
- case T___extension__:
DECLARATION_START
{
entity_t *entity = parse_parameter();
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 {
- CONSTRUCT_INVALID,
- CONSTRUCT_POINTER,
+ CONSTRUCT_POINTER = 1,
CONSTRUCT_REFERENCE,
CONSTRUCT_FUNCTION,
CONSTRUCT_ARRAY
array->is_static = is_static;
expression_t *size = NULL;
- if (token.type == '*' && look_ahead(1)->type == ']') {
+ if (token.kind == '*' && look_ahead(1)->kind == ']') {
array->is_variable = true;
- next_token();
- } else if (token.type != ']') {
+ eat('*');
+ } else if (token.kind != ']') {
size = parse_assignment_expression();
/* §6.7.5.2:1 Array size must have integer type */
errorf(&array->base.pos, "static array parameters require a size");
rem_anchor_token(']');
- expect(']', end_error);
-
-end_error:
+ expect(']');
return cons;
}
for (;;) {
construct_type_t *type;
//variable_t *based = NULL; /* MS __based extension */
- switch (token.type) {
+ switch (token.kind) {
case '&':
type = parse_reference_declarator();
break;
ptr_operator_end: ;
construct_type_t *inner_types = NULL;
- switch (token.type) {
+ switch (token.kind) {
case T_IDENTIFIER:
if (env->must_be_abstract) {
errorf(HERE, "no identifier expected in typename");
} else {
- env->symbol = token.symbol;
- env->source_position = token.source_position;
+ env->symbol = token.base.symbol;
+ env->source_position = *HERE;
}
- next_token();
+ eat(T_IDENTIFIER);
break;
case '(': {
/* Parenthesized declarator or function declarator? */
token_t const *const la1 = look_ahead(1);
- switch (la1->type) {
+ switch (la1->kind) {
case T_IDENTIFIER:
- if (is_typedef_symbol(la1->symbol)) {
+ if (is_typedef_symbol(la1->base.symbol)) {
case ')':
/* §6.7.6:2 footnote 126: Empty parentheses in a type name are
* interpreted as ``function with no parameter specification'', rather
case '[':
case T___attribute__: /* FIXME __attribute__ might also introduce a parameter of a function declarator. */
/* Paranthesized declarator. */
- next_token();
+ eat('(');
add_anchor_token(')');
inner_types = parse_inner_declarator(env);
if (inner_types != NULL) {
env->must_be_abstract = true;
}
rem_anchor_token(')');
- expect(')', end_error);
+ expect(')');
}
break;
}
for (;;) {
construct_type_t *type;
- switch (token.type) {
+ switch (token.kind) {
case '(': {
scope_t *scope = NULL;
if (!env->must_be_abstract) {
*anchor = inner_types;
return first;
-end_error:
- return NULL;
}
static type_t *construct_declarator_type(construct_type_t *construct_list,
for (; iter != NULL; iter = iter->base.next) {
source_position_t const* const pos = &iter->base.pos;
switch (iter->kind) {
- case CONSTRUCT_INVALID:
- break;
case CONSTRUCT_FUNCTION: {
construct_function_type_t *function = &iter->function;
type_t *function_type = function->function_type;
errorf(pos, "function returning array is not allowed");
} else {
if (skipped_return_type->base.qualifiers != 0) {
- warningf(WARN_OTHER, pos, "type qualifiers in return type of function type are meaningless");
+ warningf(WARN_IGNORED_QUALIFIERS, pos, "type qualifiers in return type of function type are meaningless");
}
}
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)) {
- errorf(&env.source_position,
- "compound member '%Y' declared 'inline'", env.symbol);
+ errorf(&env.source_position, "'%N' declared 'inline'", entity);
}
if (specifiers->thread_local ||
specifiers->storage_class != STORAGE_CLASS_NONE) {
- errorf(&env.source_position,
- "compound member '%Y' must have no storage class",
- env.symbol);
+ errorf(&env.source_position, "'%N' must have no storage class", entity);
}
}
} 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;
}
}
if (invalid_storage_class) {
- errorf(&env.source_position, "invalid storage class for variable '%N'", entity);
+ errorf(&env.source_position, "invalid storage class for '%N'", entity);
}
}
}
- 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);
}
}
goto finish;
}
if (previous_entity->kind == ENTITY_TYPEDEF) {
- /* TODO: C++ allows this for exactly the same type */
- errorf(pos, "redefinition of '%N' (declared %P)", entity, ppos);
+ type_t *const type = skip_typeref(entity->typedefe.type);
+ type_t *const prev_type
+ = skip_typeref(previous_entity->typedefe.type);
+ 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) {
merge_in_attributes(decl, prev_decl->attributes);
} else if (!is_definition &&
is_type_valid(prev_type) &&
- strcmp(ppos->input_name, "<builtin>") != 0) {
- warningf(WARN_REDUNDANT_DECLS, pos, "redundant declaration for '%Y' (declared %P)", symbol, ppos);
+ !pos->is_system_header) {
+ warningf(WARN_REDUNDANT_DECLS, pos, "redundant declaration for '%N' (declared %P)", entity, ppos);
}
} else if (current_function == NULL) {
if (old_storage_class != STORAGE_CLASS_STATIC &&
new_storage_class == STORAGE_CLASS_STATIC) {
- errorf(pos, "static declaration of '%Y' follows non-static declaration (declared %P)", symbol, ppos);
+ errorf(pos, "static declaration of '%N' follows non-static declaration (declared %P)", entity, ppos);
} else if (old_storage_class == STORAGE_CLASS_EXTERN) {
prev_decl->storage_class = STORAGE_CLASS_NONE;
prev_decl->declared_storage_class = STORAGE_CLASS_NONE;
} else if (is_type_valid(prev_type)) {
if (old_storage_class == new_storage_class) {
error_redeclaration:
- errorf(pos, "redeclaration of '%Y' (declared %P)", symbol, ppos);
+ errorf(pos, "redeclaration of '%N' (declared %P)", entity, ppos);
} else {
- errorf(pos, "redeclaration of '%Y' with different linkage (declared %P)", symbol, ppos);
+ errorf(pos, "redeclaration of '%N' with different linkage (declared %P)", entity, ppos);
}
}
}
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);
static void parser_error_multiple_definition(entity_t *entity,
const source_position_t *source_position)
{
- errorf(source_position, "multiple definition of '%Y' (declared %P)",
- entity->base.symbol, &entity->base.source_position);
+ errorf(source_position, "redefinition of '%N' (declared %P)", entity, &entity->base.source_position);
}
static bool is_declaration_specifier(const token_t *token)
{
- switch (token->type) {
+ switch (token->kind) {
DECLARATION_START
return true;
case T_IDENTIFIER:
- return is_typedef_symbol(token->symbol);
+ return is_typedef_symbol(token->base.symbol);
default:
return false;
env.type = orig_type;
env.must_be_constant = must_be_constant;
env.entity = entity;
- current_init_decl = entity;
initializer_t *initializer = parse_initializer(&env);
- current_init_decl = NULL;
if (entity->kind == ENTITY_VARIABLE) {
/* §6.7.5:22 array initializers for arrays with unknown size
add_anchor_token(';');
add_anchor_token(',');
while (true) {
- entity_t *entity = finished_declaration(ndeclaration, token.type == '=');
+ entity_t *entity = finished_declaration(ndeclaration, token.kind == '=');
- if (token.type == '=') {
+ if (token.kind == '=') {
parse_init_declarator_rest(entity);
} else if (entity->kind == ENTITY_VARIABLE) {
/* 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)
parse_declaration_specifiers(&specifiers);
rem_anchor_token(';');
- if (token.type == ';') {
+ if (token.kind == ';') {
parse_anonymous_declaration_rest(&specifiers);
} else {
entity_t *entity = parse_declarator(&specifiers, flags);
add_anchor_token('{');
- /* push function parameters */
- size_t const top = environment_top();
- scope_t *old_scope = scope_push(&entity->function.parameters);
+ PUSH_SCOPE(&entity->function.parameters);
entity_t *parameter = entity->function.parameters.entities;
for ( ; parameter != NULL; parameter = parameter->base.next) {
/* parse declaration list */
for (;;) {
- switch (token.type) {
+ switch (token.kind) {
DECLARATION_START
- case T___extension__:
/* This covers symbols, which are no type, too, and results in
* better error messages. The typical cases are misspelled type
* names and missing includes. */
}
decl_list_end:
- /* pop function parameters */
- assert(current_scope == &entity->function.parameters);
- scope_pop(old_scope);
- environment_pop_to(top);
+ POP_SCOPE();
/* update function type */
type_t *new_type = duplicate_type(type);
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_LITERAL_CHARACTER:
case EXPR_STRING_LITERAL:
- case EXPR_WIDE_STRING_LITERAL:
case EXPR_COMPOUND_LITERAL: // TODO descend into initialisers
case EXPR_LABEL_ADDRESS:
case EXPR_CLASSIFY_TYPE:
case EXPR_BUILTIN_CONSTANT_P:
case EXPR_BUILTIN_TYPES_COMPATIBLE_P:
case EXPR_OFFSETOF:
- case EXPR_INVALID:
+ case EXPR_ERROR:
return true;
case EXPR_STATEMENT: {
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) &&
expression_returns(expr->binary.right);
-
- case EXPR_UNKNOWN:
- break;
}
panic("unhandled expression");
}
case INITIALIZER_STRING:
- case INITIALIZER_WIDE_STRING:
case INITIALIZER_DESIGNATOR: // designators have no payload
return true;
}
statement_t *last = stmt;
statement_t *next;
switch (stmt->kind) {
- case STATEMENT_INVALID:
+ case STATEMENT_ERROR:
case STATEMENT_EMPTY:
case STATEMENT_ASM:
next = stmt->base.next;
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");
}
}
switch (next->kind) {
- case STATEMENT_INVALID:
+ case STATEMENT_ERROR:
case STATEMENT_EMPTY:
case STATEMENT_DECLARATION:
case STATEMENT_EXPRESSION:
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
rem_anchor_token(';');
/* must be a declaration */
- if (token.type == ';') {
+ if (token.kind == ';') {
parse_anonymous_declaration_rest(&specifiers);
return;
}
rem_anchor_token(',');
/* must be a declaration */
- switch (token.type) {
+ switch (token.kind) {
case ',':
case ';':
case '=':
/* must be a function definition */
parse_kr_declaration_list(ndeclaration);
- if (token.type != '{') {
+ if (token.kind != '{') {
parse_error_expected("while parsing function definition", '{', NULL);
eat_until_matching_token(';');
return;
if (ndeclaration != entity) {
function->parameters = ndeclaration->function.parameters;
}
- assert(is_declaration(entity));
- type = skip_typeref(entity->declaration.type);
- /* push function parameters and switch scope */
- size_t const top = environment_top();
- scope_t *old_scope = scope_push(&function->parameters);
+ PUSH_SCOPE(&function->parameters);
entity_t *parameter = function->parameters.entities;
for (; parameter != NULL; parameter = parameter->base.next) {
/* 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;
- current_parent = NULL;
+ PUSH_CURRENT_ENTITY(entity);
+ PUSH_PARENT(NULL);
goto_first = NULL;
goto_anchor = &goto_first;
}
}
- assert(current_parent == 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);
}
- assert(current_scope == &function->parameters);
- scope_pop(old_scope);
- environment_pop_to(top);
-}
-
-static type_t *make_bitfield_type(type_t *base_type, expression_t *size,
- source_position_t *source_position,
- const symbol_t *symbol)
-{
- type_t *type = allocate_type_zero(TYPE_BITFIELD);
-
- type->bitfield.base_type = base_type;
- type->bitfield.size_expression = size;
-
- il_size_t bit_size;
- type_t *skipped_type = skip_typeref(base_type);
- if (!is_type_integer(skipped_type)) {
- errorf(source_position, "bitfield base type '%T' is not an integer type", base_type);
- bit_size = 0;
- } else {
- bit_size = get_type_size(base_type) * 8;
- }
-
- if (is_constant_expression(size) == EXPR_CLASS_CONSTANT) {
- long v = fold_constant_to_int(size);
- const symbol_t *user_symbol = symbol == NULL ? sym_anonymous : symbol;
-
- if (v < 0) {
- errorf(source_position, "negative width in bit-field '%Y'",
- user_symbol);
- } else if (v == 0 && symbol != NULL) {
- errorf(source_position, "zero width for bit-field '%Y'",
- user_symbol);
- } else if (bit_size > 0 && (il_size_t)v > bit_size) {
- errorf(source_position, "width of '%Y' exceeds its type",
- user_symbol);
- } else {
- type->bitfield.bit_size = v;
- }
- }
-
- return type;
+ POP_SCOPE();
}
static entity_t *find_compound_entry(compound_t *compound, symbol_t *symbol)
type_t *entry_type = entry->declaration.type;
type_t *res_type = get_qualified_type(entry_type, qualifiers);
+ /* bitfields need special treatment */
+ if (entry->compound_member.bitfield) {
+ unsigned bit_size = entry->compound_member.bit_size;
+ /* if fewer bits than an int, convert to int (see §6.3.1.1) */
+ if (bit_size < get_atomic_type_size(ATOMIC_TYPE_INT) * BITS_PER_BYTE) {
+ res_type = type_int;
+ }
+ }
+
/* we always do the auto-type conversions; the & and sizeof parser contains
* code to revert this! */
select->base.type = automatic_type_conversion(res_type);
- if (res_type->kind == TYPE_BITFIELD) {
- select->base.type = res_type->bitfield.base_type;
- }
+
return select;
}
symbol_t *iter_symbol = iter->base.symbol;
if (iter_symbol == NULL) {
type_t *type = iter->declaration.type;
- if (type->kind != TYPE_COMPOUND_STRUCT
- && type->kind != TYPE_COMPOUND_UNION)
+ if (!is_type_compound(type))
continue;
compound_t *sub_compound = type->compound.compound;
expression_t *sub_addr = create_select(pos, addr, qualifiers, iter);
sub_addr->base.source_position = *pos;
- sub_addr->select.implicit = true;
+ sub_addr->base.implicit = true;
return find_create_select(pos, sub_addr, qualifiers, sub_compound,
symbol);
}
return NULL;
}
+static void parse_bitfield_member(entity_t *entity)
+{
+ eat(':');
+
+ expression_t *size = parse_constant_expression();
+ long size_long;
+
+ assert(entity->kind == ENTITY_COMPOUND_MEMBER);
+ type_t *type = entity->declaration.type;
+ if (!is_type_integer(skip_typeref(type))) {
+ errorf(HERE, "bitfield base type '%T' is not an integer type",
+ type);
+ }
+
+ if (is_constant_expression(size) != EXPR_CLASS_CONSTANT) {
+ /* error already reported by parse_constant_expression */
+ size_long = get_type_size(type) * 8;
+ } else {
+ size_long = fold_constant_to_int(size);
+
+ const symbol_t *symbol = entity->base.symbol;
+ const symbol_t *user_symbol
+ = symbol == NULL ? sym_anonymous : symbol;
+ unsigned bit_size = get_type_size(type) * 8;
+ if (size_long < 0) {
+ errorf(HERE, "negative width in bit-field '%Y'", user_symbol);
+ } else if (size_long == 0 && symbol != NULL) {
+ errorf(HERE, "zero width for bit-field '%Y'", user_symbol);
+ } else if (bit_size > 0 && (unsigned)size_long > bit_size) {
+ errorf(HERE, "width of bitfield '%Y' exceeds its type",
+ user_symbol);
+ } else {
+ /* hope that people don't invent crazy types with more bits
+ * than our struct can hold */
+ assert(size_long <
+ (1 << sizeof(entity->compound_member.bit_size)*8));
+ }
+ }
+
+ entity->compound_member.bitfield = true;
+ entity->compound_member.bit_size = (unsigned char)size_long;
+}
+
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.type == ':') {
- source_position_t source_position = *HERE;
- next_token();
-
- type_t *base_type = specifiers->type;
- expression_t *size = parse_constant_expression();
+ if (token.kind == ':') {
+ /* anonymous bitfield */
+ type_t *type = specifiers->type;
+ 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;
- type_t *type = make_bitfield_type(base_type, size,
- &source_position, NULL);
+ parse_bitfield_member(entity);
attribute_t *attributes = parse_attributes(NULL);
attribute_t **anchor = &attributes;
while (*anchor != NULL)
anchor = &(*anchor)->next;
*anchor = specifiers->attributes;
-
- entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER, NAMESPACE_NORMAL, NULL);
- entity->base.source_position = source_position;
- entity->declaration.declared_storage_class = STORAGE_CLASS_NONE;
- entity->declaration.storage_class = STORAGE_CLASS_NONE;
- entity->declaration.type = type;
- entity->declaration.attributes = attributes;
-
if (attributes != NULL) {
handle_entity_attributes(attributes, entity);
}
+ entity->declaration.attributes = attributes;
+
append_entity(&compound->members, entity);
} else {
entity = parse_declarator(specifiers,
entity_t *prev = find_compound_entry(compound, symbol);
if (prev != NULL) {
source_position_t const *const ppos = &prev->base.source_position;
- errorf(pos, "multiple declarations of symbol '%Y' (declared %P)", symbol, ppos);
+ errorf(pos, "multiple declarations of '%N' (declared %P)", entity, ppos);
}
}
- if (token.type == ':') {
- source_position_t source_position = *HERE;
- next_token();
- expression_t *size = parse_constant_expression();
-
- type_t *type = entity->declaration.type;
- type_t *bitfield_type = make_bitfield_type(type, size,
- &source_position, entity->base.symbol);
+ if (token.kind == ':') {
+ parse_bitfield_member(entity);
attribute_t *attributes = parse_attributes(NULL);
- entity->declaration.type = bitfield_type;
handle_entity_attributes(attributes, entity);
} else {
type_t *orig_type = entity->declaration.type;
} else if (is_type_incomplete(type)) {
/* §6.7.2.1:16 flexible array member */
if (!is_type_array(type) ||
- token.type != ';' ||
- look_ahead(1)->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;
}
eat('{');
add_anchor_token('}');
- while (token.type != '}') {
- if (token.type == T_EOF) {
- errorf(HERE, "EOF while parsing struct");
- break;
+ for (;;) {
+ switch (token.kind) {
+ DECLARATION_START
+ case T___extension__:
+ case T_IDENTIFIER: {
+ PUSH_EXTENSION();
+ declaration_specifiers_t specifiers;
+ parse_declaration_specifiers(&specifiers);
+ parse_compound_declarators(compound, &specifiers);
+ POP_EXTENSION();
+ break;
+ }
+
+ default:
+ rem_anchor_token('}');
+ expect('}');
+ /* §6.7.2.1:7 */
+ compound->complete = true;
+ return;
}
- declaration_specifiers_t specifiers;
- parse_declaration_specifiers(&specifiers);
- parse_compound_declarators(compound, &specifiers);
}
- rem_anchor_token('}');
- next_token();
-
- /* §6.7.2.1:7 */
- compound->complete = true;
}
static type_t *parse_typename(void)
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)
+static type_t *get_string_type(string_encoding_t const enc)
{
- /* skip the error message if the error token was read */
- if (token.type != T_ERROR) {
- errorf(HERE, "expected expression, got token %K", &token);
+ bool const warn = is_warn_on(WARN_WRITE_STRINGS);
+ switch (enc) {
+ case STRING_ENCODING_CHAR: return warn ? type_const_char_ptr : type_char_ptr;
+ case STRING_ENCODING_WIDE: return warn ? type_const_wchar_t_ptr : type_wchar_t_ptr;
}
- next_token();
-
- return create_invalid_expression();
-}
-
-static type_t *get_string_type(void)
-{
- return is_warn_on(WARN_WRITE_STRINGS) ? type_const_char_ptr : type_char_ptr;
-}
-
-static type_t *get_wide_string_type(void)
-{
- return is_warn_on(WARN_WRITE_STRINGS) ? type_const_wchar_t_ptr : type_wchar_t_ptr;
+ panic("invalid string encoding");
}
/**
*/
static expression_t *parse_string_literal(void)
{
- source_position_t begin = token.source_position;
- string_t res = token.literal;
- bool is_wide = (token.type == T_WIDE_STRING_LITERAL);
-
- next_token();
- while (token.type == T_STRING_LITERAL
- || token.type == T_WIDE_STRING_LITERAL) {
- warn_string_concat(&token.source_position);
- res = concat_strings(&res, &token.literal);
- next_token();
- is_wide |= token.type == T_WIDE_STRING_LITERAL;
- }
-
- expression_t *literal;
- if (is_wide) {
- literal = allocate_expression_zero(EXPR_WIDE_STRING_LITERAL);
- literal->base.type = get_wide_string_type();
- } else {
- literal = allocate_expression_zero(EXPR_STRING_LITERAL);
- literal->base.type = get_string_type();
- }
- literal->base.source_position = begin;
- literal->literal.value = res;
-
- return literal;
+ expression_t *const expr = allocate_expression_zero(EXPR_STRING_LITERAL);
+ expr->string_literal.value = concat_string_literals(&expr->string_literal.encoding);
+ expr->base.type = get_string_type(expr->string_literal.encoding);
+ return expr;
}
/**
static expression_t *parse_boolean_literal(bool value)
{
expression_t *literal = allocate_expression_zero(EXPR_LITERAL_BOOLEAN);
- literal->base.source_position = token.source_position;
- literal->base.type = type_bool;
- literal->literal.value.begin = value ? "true" : "false";
- literal->literal.value.size = value ? 4 : 5;
+ literal->base.type = type_bool;
+ literal->literal.value.begin = value ? "true" : "false";
+ literal->literal.value.size = value ? 4 : 5;
- next_token();
+ eat(value ? T_true : T_false);
return literal;
}
static void warn_traditional_suffix(void)
{
- warningf(WARN_TRADITIONAL, HERE, "traditional C rejects the '%Y' suffix", token.symbol);
+ warningf(WARN_TRADITIONAL, HERE, "traditional C rejects the '%S' suffix",
+ &token.number.suffix);
}
static void check_integer_suffix(void)
{
- symbol_t *suffix = token.symbol;
- if (suffix == NULL)
+ const string_t *suffix = &token.number.suffix;
+ if (suffix->size == 0)
return;
bool not_traditional = false;
- const char *c = suffix->string;
+ const char *c = suffix->begin;
if (*c == 'l' || *c == 'L') {
++c;
if (*c == *(c-1)) {
}
}
if (*c != '\0') {
- errorf(&token.source_position,
- "invalid suffix '%s' on integer constant", suffix->string);
+ errorf(HERE, "invalid suffix '%S' on integer constant", suffix);
} else if (not_traditional) {
warn_traditional_suffix();
}
static type_t *check_floatingpoint_suffix(void)
{
- symbol_t *suffix = token.symbol;
- type_t *type = type_double;
- if (suffix == NULL)
+ const string_t *suffix = &token.number.suffix;
+ type_t *type = type_double;
+ if (suffix->size == 0)
return type;
bool not_traditional = false;
- const char *c = suffix->string;
+ const char *c = suffix->begin;
if (*c == 'f' || *c == 'F') {
++c;
type = type_float;
type = type_long_double;
}
if (*c != '\0') {
- errorf(&token.source_position,
- "invalid suffix '%s' on floatingpoint constant", suffix->string);
+ errorf(HERE, "invalid suffix '%S' on floatingpoint constant", suffix);
} else if (not_traditional) {
warn_traditional_suffix();
}
expression_kind_t kind;
type_t *type;
- switch (token.type) {
+ switch (token.kind) {
case T_INTEGER:
kind = EXPR_LITERAL_INTEGER;
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");
}
expression_t *literal = allocate_expression_zero(kind);
- literal->base.source_position = token.source_position;
- literal->base.type = type;
- literal->literal.value = token.literal;
- literal->literal.suffix = token.symbol;
+ literal->base.type = type;
+ literal->literal.value = token.number.number;
+ literal->literal.suffix = token.number.suffix;
next_token();
/* integer type depends on the size of the number and the size
*/
static expression_t *parse_character_constant(void)
{
- expression_t *literal = allocate_expression_zero(EXPR_LITERAL_CHARACTER);
- literal->base.source_position = token.source_position;
- literal->base.type = c_mode & _CXX ? type_char : type_int;
- literal->literal.value = token.literal;
+ expression_t *const literal = allocate_expression_zero(EXPR_LITERAL_CHARACTER);
+ literal->string_literal.encoding = token.string.encoding;
+ literal->string_literal.value = token.string.string;
+
+ size_t const size = get_string_len(token.string.encoding, &token.string.string);
+ switch (token.string.encoding) {
+ case STRING_ENCODING_CHAR:
+ literal->base.type = c_mode & _CXX ? type_char : type_int;
+ if (size > 1) {
+ if (!GNU_MODE && !(c_mode & _C99)) {
+ errorf(HERE, "more than 1 character in character constant");
+ } else {
+ literal->base.type = type_int;
+ warningf(WARN_MULTICHAR, HERE, "multi-character character constant");
+ }
+ }
+ break;
- size_t len = literal->literal.value.size;
- if (len > 1) {
- if (!GNU_MODE && !(c_mode & _C99)) {
- errorf(HERE, "more than 1 character in character constant");
- } else {
- literal->base.type = type_int;
+ case STRING_ENCODING_WIDE:
+ literal->base.type = type_int;
+ if (size > 1) {
warningf(WARN_MULTICHAR, HERE, "multi-character character constant");
}
+ break;
}
- next_token();
- return literal;
-}
-
-/**
- * Parse a wide character constant.
- */
-static expression_t *parse_wide_character_constant(void)
-{
- expression_t *literal = allocate_expression_zero(EXPR_LITERAL_WIDE_CHARACTER);
- literal->base.source_position = token.source_position;
- literal->base.type = type_int;
- literal->literal.value = token.literal;
-
- size_t len = wstrlen(&literal->literal.value);
- if (len > 1) {
- warningf(WARN_MULTICHAR, HERE, "multi-character character constant");
- }
-
- next_token();
+ eat(T_CHARACTER_CONSTANT);
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 = expression->select.compound_entry;
assert(is_declaration(entity));
type_t *type = entity->declaration.type;
- return get_qualified_type(type,
- expression->base.type->base.qualifiers);
+ return get_qualified_type(type, expression->base.type->base.qualifiers);
}
case EXPR_UNARY_DEREFERENCE: {
}
case EXPR_STRING_LITERAL: {
- size_t size = expression->string_literal.value.size;
- return make_array_type(type_char, size, TYPE_QUALIFIER_NONE);
- }
-
- case EXPR_WIDE_STRING_LITERAL: {
- size_t size = wstrlen(&expression->string_literal.value);
- return make_array_type(type_wchar_t, size, TYPE_QUALIFIER_NONE);
+ size_t const size = get_string_len(expression->string_literal.encoding, &expression->string_literal.value) + 1;
+ type_t *const elem = get_unqualified_type(expression->base.type->pointer.points_to);
+ return make_array_type(elem, size, TYPE_QUALIFIER_NONE);
}
case EXPR_COMPOUND_LITERAL:
entity_t *entity;
while (true) {
- if (token.type != 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.symbol;
- pos = *HERE;
- next_token();
/* lookup entity */
entity = lookup_entity(lookup_scope, symbol, NAMESPACE_NORMAL);
}
if (entity == NULL) {
- if (!strict_mode && token.type == '(') {
+ if (!strict_mode && token.kind == '(') {
/* an implicitly declared function */
- warningf(WARN_IMPLICIT_FUNCTION_DECLARATION, &pos, "implicit declaration of function '%Y'", symbol);
entity = create_implicit_function(symbol, &pos);
+ warningf(WARN_IMPLICIT_FUNCTION_DECLARATION, &pos, "implicit declaration of '%N'", entity);
} else {
errorf(&pos, "unknown identifier '%Y' found.", symbol);
entity = create_error_entity(symbol, ENTITY_VARIABLE);
static expression_t *parse_reference(void)
{
- source_position_t const pos = token.source_position;
+ source_position_t const pos = *HERE;
entity_t *const entity = parse_qualified_identifier();
type_t *orig_type;
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;
&& (current_function != NULL
&& entity->base.parent_scope->depth < current_function->parameters.depth)
&& (entity->kind == ENTITY_VARIABLE || entity->kind == ENTITY_PARAMETER)) {
- if (entity->kind == ENTITY_VARIABLE) {
- /* access of a variable from an outer function */
- entity->variable.address_taken = true;
- } else if (entity->kind == ENTITY_PARAMETER) {
- entity->parameter.address_taken = true;
- }
+ /* access of a variable from an outer function */
+ entity->variable.address_taken = true;
current_function->need_closure = true;
}
check_deprecated(&pos, entity);
- if (entity == current_init_decl && !in_type_prop && entity->kind == ENTITY_VARIABLE) {
- current_init_decl = NULL;
- warningf(WARN_INIT_SELF, &pos, "variable '%#N' is initialized by itself", entity);
- }
-
return expression;
}
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 */
return true;
}
-static expression_t *parse_compound_literal(type_t *type)
+static expression_t *parse_compound_literal(source_position_t const *const pos, type_t *type)
{
expression_t *expression = allocate_expression_zero(EXPR_COMPOUND_LITERAL);
+ expression->base.source_position = *pos;
parse_initializer_env_t env;
env.type = type;
*/
static expression_t *parse_cast(void)
{
- source_position_t source_position = token.source_position;
+ source_position_t const pos = *HERE;
eat('(');
add_anchor_token(')');
type_t *type = parse_typename();
rem_anchor_token(')');
- expect(')', end_error);
+ expect(')');
- if (token.type == '{') {
- return parse_compound_literal(type);
+ if (token.kind == '{') {
+ return parse_compound_literal(&pos, type);
}
expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST);
- cast->base.source_position = source_position;
+ cast->base.source_position = pos;
expression_t *value = parse_subexpression(PREC_CAST);
cast->base.type = type;
}
return cast;
-end_error:
- return create_invalid_expression();
}
/**
expression->base.type = type;
rem_anchor_token(')');
- expect(')', end_error);
-
-end_error:
+ expect(')');
return expression;
}
static expression_t *parse_parenthesized_expression(void)
{
token_t const* const la1 = look_ahead(1);
- switch (la1->type) {
+ switch (la1->kind) {
case '{':
/* gcc extension: a statement expression */
return parse_statement_expression();
case T_IDENTIFIER:
- if (is_typedef_symbol(la1->symbol)) {
+ if (is_typedef_symbol(la1->base.symbol)) {
DECLARATION_START
return parse_cast();
}
expression_t *result = parse_expression();
result->base.parenthesized = true;
rem_anchor_token(')');
- expect(')', end_error);
+ expect(')');
-end_error:
return result;
}
-static expression_t *parse_function_keyword(void)
+static expression_t *parse_function_keyword(funcname_kind_t const kind)
{
- /* TODO */
-
if (current_function == NULL) {
- errorf(HERE, "'__func__' used outside of a function");
+ errorf(HERE, "'%K' used outside of a function", &token);
}
expression_t *expression = allocate_expression_zero(EXPR_FUNCNAME);
expression->base.type = type_char_ptr;
- expression->funcname.kind = FUNCNAME_FUNCTION;
+ expression->funcname.kind = kind;
next_token();
return expression;
}
-static expression_t *parse_pretty_function_keyword(void)
-{
- if (current_function == NULL) {
- errorf(HERE, "'__PRETTY_FUNCTION__' used outside of a function");
- }
-
- expression_t *expression = allocate_expression_zero(EXPR_FUNCNAME);
- 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)
-{
- if (current_function == NULL) {
- errorf(HERE, "'__FUNCSIG__' used outside of a function");
- }
-
- expression_t *expression = allocate_expression_zero(EXPR_FUNCNAME);
- expression->base.type = type_char_ptr;
- expression->funcname.kind = FUNCNAME_FUNCSIG;
-
- eat(T___FUNCSIG__);
-
- return expression;
-}
-
-static expression_t *parse_funcdname_keyword(void)
-{
- if (current_function == NULL) {
- errorf(HERE, "'__FUNCDNAME__' used outside of a function");
- }
-
- expression_t *expression = allocate_expression_zero(EXPR_FUNCNAME);
- expression->base.type = type_char_ptr;
- expression->funcname.kind = FUNCNAME_FUNCDNAME;
-
- eat(T___FUNCDNAME__);
-
- return expression;
-}
-
static designator_t *parse_designator(void)
{
- designator_t *result = allocate_ast_zero(sizeof(result[0]));
- result->source_position = *HERE;
-
- if (token.type != 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.symbol;
- next_token();
designator_t *last_designator = result;
while (true) {
if (next_if('.')) {
- if (token.type != 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.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);
+ add_anchor_token(')');
add_anchor_token(',');
+ expect('(');
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;
descend_into_subtype(&path);
if (!walk_designator(&path, designator, true)) {
- return create_invalid_expression();
+ return create_error_expression();
}
DEL_ARR_F(path.path);
return expression;
-end_error:
- return create_invalid_expression();
+}
+
+static bool is_last_parameter(expression_t *const param)
+{
+ if (param->kind == EXPR_REFERENCE) {
+ entity_t *const entity = param->reference.entity;
+ if (entity->kind == ENTITY_PARAMETER &&
+ !entity->base.next &&
+ entity->base.parent_scope == ¤t_function->parameters) {
+ return true;
+ }
+ }
+
+ if (!is_type_valid(skip_typeref(param->base.type)))
+ return true;
+
+ return false;
}
/**
- * Parses a _builtin_va_start() expression.
+ * Parses a __builtin_va_start() expression.
*/
static expression_t *parse_va_start(void)
{
eat(T___builtin_va_start);
- expect('(', end_error);
+ add_anchor_token(')');
add_anchor_token(',');
+ expect('(');
expression->va_starte.ap = parse_assignment_expression();
rem_anchor_token(',');
- expect(',', end_error);
- expression_t *const expr = parse_assignment_expression();
- if (expr->kind == EXPR_REFERENCE) {
- entity_t *const entity = expr->reference.entity;
- if (!current_function->base.type->function.variadic) {
- errorf(&expr->base.source_position,
- "'va_start' used in non-variadic function");
- } else if (entity->base.parent_scope != ¤t_function->parameters ||
- entity->base.next != NULL ||
- entity->kind != ENTITY_PARAMETER) {
- errorf(&expr->base.source_position,
- "second argument of 'va_start' must be last parameter of the current function");
- } else {
- expression->va_starte.parameter = &entity->variable;
- }
- expect(')', end_error);
- return expression;
+ expect(',');
+ expression_t *const param = parse_assignment_expression();
+ expression->va_starte.parameter = param;
+ rem_anchor_token(')');
+ expect(')');
+
+ if (!current_function) {
+ errorf(&expression->base.source_position, "'va_start' used outside of function");
+ } else if (!current_function->base.type->function.variadic) {
+ errorf(&expression->base.source_position, "'va_start' used in non-variadic function");
+ } else if (!is_last_parameter(param)) {
+ errorf(¶m->base.source_position, "second argument of 'va_start' must be last parameter of the current function");
}
- expect(')', end_error);
-end_error:
- return create_invalid_expression();
+
+ return expression;
}
/**
eat(T___builtin_va_arg);
- expect('(', end_error);
+ add_anchor_token(')');
+ add_anchor_token(',');
+ expect('(');
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_invalid_expression();
}
/**
eat(T___builtin_va_copy);
- expect('(', end_error);
+ add_anchor_token(')');
+ add_anchor_token(',');
+ expect('(');
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_invalid_expression();
}
/**
eat(T___builtin_constant_p);
- expect('(', end_error);
add_anchor_token(')');
+ expect('(');
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_invalid_expression();
}
/**
eat(T___builtin_types_compatible_p);
- expect('(', end_error);
add_anchor_token(')');
add_anchor_token(',');
+ expect('(');
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_invalid_expression();
}
-
-/**
- * Parses a __builtin_is_*() compare expression.
- */
-static expression_t *parse_compare_builtin(void)
-{
- expression_t *expression;
-
- switch (token.type) {
- case T___builtin_isgreater:
- expression = allocate_expression_zero(EXPR_BINARY_ISGREATER);
- break;
- case T___builtin_isgreaterequal:
- expression = allocate_expression_zero(EXPR_BINARY_ISGREATEREQUAL);
- break;
- case T___builtin_isless:
- expression = allocate_expression_zero(EXPR_BINARY_ISLESS);
- break;
- case T___builtin_islessequal:
- expression = allocate_expression_zero(EXPR_BINARY_ISLESSEQUAL);
- break;
- case T___builtin_islessgreater:
- expression = allocate_expression_zero(EXPR_BINARY_ISLESSGREATER);
- break;
- case T___builtin_isunordered:
- expression = allocate_expression_zero(EXPR_BINARY_ISUNORDERED);
- break;
- default:
- internal_errorf(HERE, "invalid compare builtin found");
- }
- expression->base.source_position = *HERE;
+
+/**
+ * Parses a __builtin_is_*() compare expression.
+ */
+static expression_t *parse_compare_builtin(void)
+{
+ expression_kind_t kind;
+ switch (token.kind) {
+ case T___builtin_isgreater: kind = EXPR_BINARY_ISGREATER; break;
+ case T___builtin_isgreaterequal: kind = EXPR_BINARY_ISGREATEREQUAL; break;
+ case T___builtin_isless: kind = EXPR_BINARY_ISLESS; break;
+ case T___builtin_islessequal: kind = EXPR_BINARY_ISLESSEQUAL; break;
+ case T___builtin_islessgreater: kind = EXPR_BINARY_ISLESSGREATER; break;
+ case T___builtin_isunordered: kind = EXPR_BINARY_ISUNORDERED; break;
+ default: internal_errorf(HERE, "invalid compare builtin found");
+ }
+ expression_t *const expression = allocate_expression_zero(kind);
next_token();
- expect('(', end_error);
+ add_anchor_token(')');
+ add_anchor_token(',');
+ expect('(');
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_invalid_expression();
}
/**
eat(T__assume);
- expect('(', end_error);
add_anchor_token(')');
+ expect('(');
expression->unary.value = parse_assignment_expression();
rem_anchor_token(')');
- expect(')', end_error);
+ expect(')');
expression->base.type = type_void;
return expression;
-end_error:
- return create_invalid_expression();
}
/**
* Return the label for the current symbol or create a new one.
*/
-static label_t *get_label(void)
+static label_t *get_label(char const *const context)
{
- assert(token.type == T_IDENTIFIER);
assert(current_function != NULL);
- entity_t *label = get_entity(token.symbol, NAMESPACE_LABEL);
+ symbol_t *const sym = expect_identifier(context, NULL);
+ if (!sym)
+ return NULL;
+
+ entity_t *label = get_entity(sym, NAMESPACE_LABEL);
/* If we find a local label, we already created the declaration. */
if (label != NULL && label->kind == ENTITY_LOCAL_LABEL) {
if (label->base.parent_scope != current_scope) {
}
} 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.symbol);
+ source_position_t const nowhere = { NULL, 0, 0, false };
+ label = allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, sym, &nowhere);
label_push(label);
}
- eat(T_IDENTIFIER);
return &label->label;
}
*/
static expression_t *parse_label_address(void)
{
- source_position_t source_position = token.source_position;
+ source_position_t const source_position = *HERE;
eat(T_ANDAND);
- if (token.type != T_IDENTIFIER) {
- parse_error_expected("while parsing label address", T_IDENTIFIER, NULL);
- return create_invalid_expression();
- }
- label_t *const label = get_label();
+ label_t *const label = get_label("while parsing label address");
+ if (!label)
+ return create_error_expression();
+
label->used = true;
label->address_taken = true;
{
/* the result is a (int)0 */
expression_t *literal = allocate_expression_zero(EXPR_LITERAL_MS_NOOP);
- literal->base.type = type_int;
- literal->base.source_position = token.source_position;
- literal->literal.value.begin = "__noop";
- literal->literal.value.size = 6;
+ literal->base.type = type_int;
+ literal->literal.value.begin = "__noop";
+ literal->literal.value.size = 6;
eat(T___noop);
- if (token.type == '(') {
+ if (token.kind == '(') {
/* parse arguments */
eat('(');
add_anchor_token(')');
add_anchor_token(',');
- if (token.type != ')') do {
+ 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;
}
*/
static expression_t *parse_primary_expression(void)
{
- switch (token.type) {
+ switch (token.kind) {
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:
- case T_WIDE_STRING_LITERAL: return parse_string_literal();
- case T___FUNCTION__:
- case T___func__: return parse_function_keyword();
- case T___PRETTY_FUNCTION__: return parse_pretty_function_keyword();
- case T___FUNCSIG__: return parse_funcsig_keyword();
- case T___FUNCDNAME__: return parse_funcdname_keyword();
+ case T_STRING_LITERAL: return parse_string_literal();
+ case T___func__: return parse_function_keyword(FUNCNAME_FUNCTION);
+ case T___PRETTY_FUNCTION__: return parse_function_keyword(FUNCNAME_PRETTY_FUNCTION);
+ case T___FUNCSIG__: return parse_function_keyword(FUNCNAME_FUNCSIG);
+ case T___FUNCDNAME__: return parse_function_keyword(FUNCNAME_FUNCDNAME);
case T___builtin_offsetof: return parse_offsetof();
case T___builtin_va_start: return parse_va_start();
case T___builtin_va_arg: return parse_va_arg();
case T_COLONCOLON:
return parse_reference();
case T_IDENTIFIER:
- if (!is_typedef_symbol(token.symbol)) {
+ if (!is_typedef_symbol(token.base.symbol)) {
return parse_reference();
}
/* FALLTHROUGH */
parse_declaration_specifiers(&specifiers);
type_t const *const type = parse_abstract_declarator(specifiers.type);
errorf(&pos, "encountered type '%T' while parsing expression", type);
- return create_invalid_expression();
+ return create_error_expression();
}
}
errorf(HERE, "unexpected token %K, expected an expression", &token);
eat_until_anchor();
- return create_invalid_expression();
+ return create_error_expression();
}
static expression_t *parse_array_expression(expression_t *left)
arr->base.type = res_type;
rem_anchor_token(']');
- expect(']', end_error);
-end_error:
+ expect(']');
return expr;
}
+static bool is_bitfield(const expression_t *expression)
+{
+ return expression->kind == EXPR_SELECT
+ && expression->select.compound_entry->compound_member.bitfield;
+}
+
static expression_t *parse_typeprop(expression_kind_t const kind)
{
expression_t *tp_expression = allocate_expression_zero(kind);
eat(kind == EXPR_SIZEOF ? T_sizeof : T___alignof__);
- /* we only refer to a type property, mark this case */
- bool old = in_type_prop;
- in_type_prop = true;
-
type_t *orig_type;
expression_t *expression;
- if (token.type == '(' && is_declaration_specifier(look_ahead(1))) {
- next_token();
+ if (token.kind == '(' && is_declaration_specifier(look_ahead(1))) {
+ source_position_t const pos = *HERE;
+ eat('(');
add_anchor_token(')');
orig_type = parse_typename();
rem_anchor_token(')');
- expect(')', end_error);
+ expect(')');
- if (token.type == '{') {
+ if (token.kind == '{') {
/* It was not sizeof(type) after all. It is sizeof of an expression
* starting with a compound literal */
- expression = parse_compound_literal(orig_type);
+ expression = parse_compound_literal(&pos, orig_type);
goto typeprop_expression;
}
} else {
expression = parse_subexpression(PREC_UNARY);
typeprop_expression:
+ if (is_bitfield(expression)) {
+ char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
+ errorf(&tp_expression->base.source_position,
+ "operand of %s expression must not be a bitfield", what);
+ }
+
tp_expression->typeprop.tp_expression = expression;
orig_type = revert_automatic_type_conversion(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) {
} else {
wrong_type = "function";
}
- } else {
- if (is_type_incomplete(type))
- wrong_type = "incomplete";
}
- if (type->kind == TYPE_BITFIELD)
- wrong_type = "bitfield";
if (wrong_type != NULL) {
char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
what, wrong_type, orig_type);
}
-end_error:
- in_type_prop = old;
return tp_expression;
}
static expression_t *parse_select_expression(expression_t *addr)
{
- assert(token.type == '.' || token.type == T_MINUSGREATER);
- bool select_left_arrow = (token.type == T_MINUSGREATER);
+ assert(token.kind == '.' || token.kind == T_MINUSGREATER);
+ bool select_left_arrow = (token.kind == T_MINUSGREATER);
source_position_t const pos = *HERE;
next_token();
- if (token.type != T_IDENTIFIER) {
- parse_error_expected("while parsing select", T_IDENTIFIER, NULL);
- return create_invalid_expression();
- }
- symbol_t *symbol = token.symbol;
- next_token();
+ symbol_t *const symbol = expect_identifier("while parsing select", NULL);
+ if (!symbol)
+ return create_error_expression();
type_t *const orig_type = addr->base.type;
type_t *const type = skip_typeref(orig_type);
type_left = type;
}
- if (type_left->kind != TYPE_COMPOUND_STRUCT &&
- type_left->kind != TYPE_COMPOUND_UNION) {
-
+ if (!is_type_compound(type_left)) {
if (is_type_valid(type_left) && !saw_error) {
errorf(&pos,
"request for member '%Y' in something not a struct or union, but '%T'",
symbol, type_left);
}
- return create_invalid_expression();
+ return create_error_expression();
}
compound_t *compound = type_left->compound.compound;
if (!compound->complete) {
errorf(&pos, "request for member '%Y' in incomplete type '%T'",
symbol, type_left);
- return create_invalid_expression();
+ return create_error_expression();
}
type_qualifiers_t qualifiers = type_left->base.qualifiers;
if (result == NULL) {
errorf(&pos, "'%T' has no member named '%Y'", orig_type, symbol);
- return create_invalid_expression();
+ return create_error_expression();
}
return result;
/**
* Handle the semantic restrictions of builtin calls
*/
-static void handle_builtin_argument_restrictions(call_expression_t *call) {
- switch (call->function->reference.entity->function.btk) {
- case bk_gnu_builtin_return_address:
- case bk_gnu_builtin_frame_address: {
+static void handle_builtin_argument_restrictions(call_expression_t *call)
+{
+ entity_t *entity = call->function->reference.entity;
+ switch (entity->function.btk) {
+ case BUILTIN_FIRM:
+ switch (entity->function.b.firm_builtin_kind) {
+ case ir_bk_return_address:
+ case ir_bk_frame_address: {
/* argument must be constant */
call_argument_t *argument = call->arguments;
if (is_constant_expression(argument->expression) == EXPR_CLASS_VARIABLE) {
errorf(&call->base.source_position,
- "argument of '%Y' must be a constant expression",
- call->function->reference.entity->base.symbol);
- }
- break;
- }
- case bk_gnu_builtin_object_size:
- if (call->arguments == NULL)
- break;
-
- call_argument_t *arg = call->arguments->next;
- if (arg != NULL && is_constant_expression(arg->expression) == EXPR_CLASS_VARIABLE) {
- errorf(&call->base.source_position,
- "second argument of '%Y' must be a constant expression",
+ "argument of '%Y' must be a constant expression",
call->function->reference.entity->base.symbol);
}
break;
- case bk_gnu_builtin_prefetch:
+ }
+ case ir_bk_prefetch:
/* second and third argument must be constant if existent */
if (call->arguments == NULL)
break;
if (rw != NULL) {
if (is_constant_expression(rw->expression) == EXPR_CLASS_VARIABLE) {
errorf(&call->base.source_position,
- "second argument of '%Y' must be a constant expression",
- call->function->reference.entity->base.symbol);
+ "second argument of '%Y' must be a constant expression",
+ call->function->reference.entity->base.symbol);
}
locality = rw->next;
}
if (locality != NULL) {
if (is_constant_expression(locality->expression) == EXPR_CLASS_VARIABLE) {
errorf(&call->base.source_position,
- "third argument of '%Y' must be a constant expression",
- call->function->reference.entity->base.symbol);
+ "third argument of '%Y' must be a constant expression",
+ call->function->reference.entity->base.symbol);
}
locality = rw->next;
}
break;
default:
break;
+ }
+
+ case BUILTIN_OBJECT_SIZE:
+ if (call->arguments == NULL)
+ break;
+
+ call_argument_t *arg = call->arguments->next;
+ if (arg != NULL && is_constant_expression(arg->expression) == EXPR_CLASS_VARIABLE) {
+ errorf(&call->base.source_position,
+ "second argument of '%Y' must be a constant expression",
+ call->function->reference.entity->base.symbol);
+ }
+ break;
+ default:
+ break;
}
}
add_anchor_token(')');
add_anchor_token(',');
- if (token.type != ')') {
+ if (token.kind != ')') {
call_argument_t **anchor = &call->arguments;
do {
call_argument_t *argument = allocate_ast_zero(sizeof(*argument));
}
rem_anchor_token(',');
rem_anchor_token(')');
- expect(')', end_error);
+ expect(')');
if (function_type == NULL)
return result;
if (expression->kind == EXPR_REFERENCE) {
reference_expression_t *reference = &expression->reference;
if (reference->entity->kind == ENTITY_FUNCTION &&
- reference->entity->function.btk != bk_none)
+ reference->entity->function.btk != BUILTIN_NONE)
handle_builtin_argument_restrictions(call);
}
-end_error:
return result;
}
expression_t *true_expression = expression;
bool gnu_cond = false;
- if (GNU_MODE && token.type == ':') {
+ if (GNU_MODE && token.kind == ':') {
gnu_cond = true;
} else {
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))) {
*/
static expression_t *parse_extension(void)
{
- eat(T___extension__);
-
- bool old_gcc_extension = in_gcc_extension;
- in_gcc_extension = true;
+ PUSH_EXTENSION();
expression_t *expression = parse_subexpression(PREC_UNARY);
- in_gcc_extension = old_gcc_extension;
+ POP_EXTENSION();
return expression;
}
eat(T___builtin_classify_type);
- expect('(', end_error);
add_anchor_token(')');
+ expect('(');
expression_t *expression = parse_expression();
rem_anchor_token(')');
- expect(')', end_error);
+ expect(')');
result->classify_type.type_expression = expression;
return result;
-end_error:
- return create_invalid_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");
}
eat(T_throw);
expression_t *value = NULL;
- switch (token.type) {
+ switch (token.kind) {
EXPRESSION_START {
value = parse_assignment_expression();
/* ISO/IEC 14882:1998(E) §15.1:3 */
"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);
expression->base.type = orig_type;
}
+static void promote_unary_int_expr(unary_expression_t *const expr, type_t *const type)
+{
+ type_t *const res_type = promote_integer(type);
+ expr->base.type = res_type;
+ expr->value = create_implicit_cast(expr->value, res_type);
+}
+
static void semantic_unexpr_arithmetic(unary_expression_t *expression)
{
type_t *const orig_type = expression->value->base.type;
"operation needs an arithmetic type");
}
return;
+ } else if (is_type_integer(type)) {
+ promote_unary_int_expr(expression, type);
+ } else {
+ expression->base.type = orig_type;
}
-
- expression->base.type = orig_type;
}
static void semantic_unexpr_plus(unary_expression_t *expression)
return;
}
- expression->base.type = orig_type;
+ promote_unary_int_expr(expression, type);
}
static void semantic_dereference(unary_expression_t *expression)
errorf(pos, "address of register '%N' requested", entity);
}
- if (entity->kind == ENTITY_VARIABLE) {
- entity->variable.address_taken = true;
- } else {
- assert(entity->kind == ENTITY_PARAMETER);
- entity->parameter.address_taken = true;
- }
+ entity->variable.address_taken = true;
}
/**
if (!is_lvalue(value)) {
errorf(&expression->base.source_position, "'&' requires an lvalue");
}
- if (type->kind == TYPE_BITFIELD) {
+ if (is_bitfield(value)) {
errorf(&expression->base.source_position,
- "'&' not allowed on object with bitfield type '%T'",
- type);
+ "'&' not allowed on bitfield");
}
set_address_taken(value, false);
expression->base.type = make_pointer_type(orig_type, TYPE_QUALIFIER_NONE);
}
-#define CREATE_UNARY_EXPRESSION_PARSER(token_type, unexpression_type, sfunc) \
+#define CREATE_UNARY_EXPRESSION_PARSER(token_kind, unexpression_type, sfunc) \
static expression_t *parse_##unexpression_type(void) \
{ \
expression_t *unary_expression \
= allocate_expression_zero(unexpression_type); \
- eat(token_type); \
+ eat(token_kind); \
unary_expression->unary.value = parse_subexpression(PREC_UNARY); \
\
sfunc(&unary_expression->unary); \
CREATE_UNARY_EXPRESSION_PARSER(T_MINUSMINUS, EXPR_UNARY_PREFIX_DECREMENT,
semantic_incdec)
-#define CREATE_UNARY_POSTFIX_EXPRESSION_PARSER(token_type, unexpression_type, \
+#define CREATE_UNARY_POSTFIX_EXPRESSION_PARSER(token_kind, unexpression_type, \
sfunc) \
static expression_t *parse_##unexpression_type(expression_t *left) \
{ \
expression_t *unary_expression \
= allocate_expression_zero(unexpression_type); \
- eat(token_type); \
+ eat(token_kind); \
unary_expression->unary.value = left; \
\
sfunc(&unary_expression->unary); \
if (type_left == type_right)
return type_left;
- bool const signed_left = is_type_signed(type_left);
- bool const signed_right = is_type_signed(type_right);
- int const rank_left = get_rank(type_left);
- int const rank_right = get_rank(type_right);
+ bool const signed_left = is_type_signed(type_left);
+ bool const signed_right = is_type_signed(type_right);
+ unsigned const rank_left = get_akind_rank(get_akind(type_left));
+ unsigned const rank_right = get_akind_rank(get_akind(type_right));
if (signed_left == signed_right)
return rank_left >= rank_right ? type_left : type_right;
- int s_rank;
- int u_rank;
+ unsigned s_rank;
+ unsigned u_rank;
+ atomic_type_kind_t s_akind;
+ atomic_type_kind_t u_akind;
type_t *s_type;
type_t *u_type;
if (signed_left) {
- s_rank = rank_left;
s_type = type_left;
- u_rank = rank_right;
u_type = type_right;
} else {
- s_rank = rank_right;
s_type = type_right;
- u_rank = rank_left;
u_type = type_left;
}
+ s_akind = get_akind(s_type);
+ u_akind = get_akind(u_type);
+ s_rank = get_akind_rank(s_akind);
+ u_rank = get_akind_rank(u_akind);
if (u_rank >= s_rank)
return u_type;
- /* casting rank to atomic_type_kind is a bit hacky, but makes things
- * easier here... */
- if (get_atomic_type_size((atomic_type_kind_t) s_rank)
- > get_atomic_type_size((atomic_type_kind_t) u_rank))
+ if (get_atomic_type_size(s_akind) > get_atomic_type_size(u_akind))
return s_type;
- switch (s_rank) {
- case ATOMIC_TYPE_INT: return type_unsigned_int;
- case ATOMIC_TYPE_LONG: return type_unsigned_long;
- case ATOMIC_TYPE_LONGLONG: return type_unsigned_long_long;
+ switch (s_akind) {
+ case ATOMIC_TYPE_INT: return type_unsigned_int;
+ case ATOMIC_TYPE_LONG: return type_unsigned_long;
+ case ATOMIC_TYPE_LONGLONG: return type_unsigned_long_long;
- default: panic("invalid atomic type");
+ default: panic("invalid atomic 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 {
expr = expr->unary.value;
}
- if (expr->kind == EXPR_STRING_LITERAL
- || expr->kind == EXPR_WIDE_STRING_LITERAL) {
+ if (expr->kind == EXPR_STRING_LITERAL) {
source_position_t const *const pos = &expr->base.source_position;
warningf(WARN_ADDRESS, pos, "comparison with string literal results in unspecified behaviour");
}
{
switch (is_constant_expression(expr)) {
case EXPR_CLASS_ERROR: return false;
- case EXPR_CLASS_CONSTANT: return fold_constant_to_int(expr) < 0;
+ case EXPR_CLASS_CONSTANT: return constant_is_negative(expr);
default: return true;
}
}
static bool expression_has_effect(const expression_t *const expr)
{
switch (expr->kind) {
- case EXPR_UNKNOWN: break;
- case EXPR_INVALID: return true; /* do NOT warn */
+ 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_MS_NOOP: return true;
case EXPR_LITERAL_BOOLEAN:
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;
case EXPR_CALL: {
const call_expression_t *const call = &expr->call;
* 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_CAST_IMPLICIT: return true;
case EXPR_UNARY_ASSUME: return true;
case EXPR_UNARY_DELETE: return true;
case EXPR_UNARY_DELETE_ARRAY: return true;
/**
* @param prec_r precedence of the right operand
*/
-#define CREATE_BINEXPR_PARSER(token_type, binexpression_type, prec_r, sfunc) \
+#define CREATE_BINEXPR_PARSER(token_kind, binexpression_type, prec_r, sfunc) \
static expression_t *parse_##binexpression_type(expression_t *left) \
{ \
expression_t *binexpr = allocate_expression_zero(binexpression_type); \
binexpr->binary.left = left; \
- eat(token_type); \
+ eat(token_kind); \
\
expression_t *right = parse_subexpression(prec_r); \
\
static expression_t *parse_subexpression(precedence_t precedence)
{
- if (token.type < 0) {
- return expected_expression_error();
- }
-
expression_parser_function_t *parser
- = &expression_parsers[token.type];
- source_position_t source_position = token.source_position;
+ = &expression_parsers[token.kind];
expression_t *left;
if (parser->parser != NULL) {
left = parse_primary_expression();
}
assert(left != NULL);
- left->base.source_position = source_position;
while (true) {
- if (token.type < 0) {
- return expected_expression_error();
- }
-
- parser = &expression_parsers[token.type];
+ parser = &expression_parsers[token.kind];
if (parser->infix_parser == NULL)
break;
if (parser->infix_precedence < precedence)
left = parser->infix_parser(left);
assert(left != NULL);
- assert(left->kind != EXPR_UNKNOWN);
- left->base.source_position = source_position;
}
return left;
* Register a parser for a prefix-like operator.
*
* @param parser the parser function
- * @param token_type the token type of the prefix token
+ * @param token_kind the token type of the prefix token
*/
static void register_expression_parser(parse_expression_function parser,
- int token_type)
+ int token_kind)
{
- expression_parser_function_t *entry = &expression_parsers[token_type];
+ expression_parser_function_t *entry = &expression_parsers[token_kind];
- if (entry->parser != NULL) {
- diagnosticf("for token '%k'\n", (token_type_t)token_type);
- panic("trying to register multiple expression parsers for a token");
- }
+ assert(!entry->parser);
entry->parser = parser;
}
* Register a parser for an infix operator with given precedence.
*
* @param parser the parser function
- * @param token_type the token type of the infix operator
+ * @param token_kind the token type of the infix operator
* @param precedence the precedence of the operator
*/
static void register_infix_parser(parse_expression_infix_function parser,
- int token_type, precedence_t precedence)
+ int token_kind, precedence_t precedence)
{
- expression_parser_function_t *entry = &expression_parsers[token_type];
+ expression_parser_function_t *entry = &expression_parsers[token_kind];
- if (entry->infix_parser != NULL) {
- diagnosticf("for token '%k'\n", (token_type_t)token_type);
- panic("trying to register multiple infix expression parsers for a "
- "token");
- }
+ assert(!entry->infix_parser);
entry->infix_parser = parser;
entry->infix_precedence = precedence;
}
asm_argument_t *result = NULL;
asm_argument_t **anchor = &result;
- while (token.type == T_STRING_LITERAL || token.type == '[') {
+ 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.type != 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.symbol;
-
- expect(']', end_error);
}
- argument->constraints = parse_string_literals();
- expect('(', end_error);
+ argument->constraints = parse_string_literals("asm argument");
add_anchor_token(')');
+ expect('(');
expression_t *expression = parse_expression();
rem_anchor_token(')');
if (is_out) {
size = get_atomic_type_size(akind);
} else {
flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC;
- size = get_atomic_type_size(get_intptr_kind());
+ size = get_type_size(type_void_ptr);
}
do {
value_size = get_atomic_type_size(value_akind);
} else if (value_kind == TYPE_POINTER) {
value_flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC;
- value_size = get_atomic_type_size(get_intptr_kind());
+ value_size = get_type_size(type_void_ptr);
} else {
break;
}
mark_vars_read(expression, NULL);
}
argument->expression = expression;
- expect(')', end_error);
+ expect(')');
set_address_taken(expression, true);
}
return result;
-end_error:
- return NULL;
}
/**
asm_clobber_t *result = NULL;
asm_clobber_t **anchor = &result;
- while (token.type == T_STRING_LITERAL) {
+ while (token.kind == T_STRING_LITERAL) {
asm_clobber_t *clobber = allocate_ast_zero(sizeof(clobber[0]));
- clobber->clobber = parse_string_literals();
+ clobber->clobber = parse_string_literals(NULL);
*anchor = clobber;
anchor = &clobber->next;
asm_statement_t *asm_statement = &statement->asms;
eat(T_asm);
+ add_anchor_token(')');
+ add_anchor_token(':');
+ add_anchor_token(T_STRING_LITERAL);
if (next_if(T_volatile))
asm_statement->is_volatile = true;
- expect('(', end_error);
- add_anchor_token(')');
- if (token.type != T_STRING_LITERAL) {
- parse_error_expected("after asm(", T_STRING_LITERAL, NULL);
- goto end_of_asm;
- }
- asm_statement->asm_text = parse_string_literals();
+ expect('(');
+ rem_anchor_token(T_STRING_LITERAL);
+ asm_statement->asm_text = parse_string_literals("asm statement");
- add_anchor_token(':');
- if (!next_if(':')) {
- rem_anchor_token(':');
- goto end_of_asm;
- }
+ if (next_if(':'))
+ asm_statement->outputs = parse_asm_arguments(true);
- asm_statement->outputs = parse_asm_arguments(true);
- if (!next_if(':')) {
- rem_anchor_token(':');
- goto end_of_asm;
- }
+ if (next_if(':'))
+ asm_statement->inputs = parse_asm_arguments(false);
- asm_statement->inputs = parse_asm_arguments(false);
- if (!next_if(':')) {
- rem_anchor_token(':');
- goto end_of_asm;
- }
rem_anchor_token(':');
+ if (next_if(':'))
+ asm_statement->clobbers = parse_asm_clobbers();
- asm_statement->clobbers = parse_asm_clobbers();
-
-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_invalid_statement();
}
static statement_t *parse_label_inner_statement(statement_t const *const label, char const *const label_kind)
{
statement_t *inner_stmt;
- switch (token.type) {
+ switch (token.kind) {
case '}':
errorf(&label->base.source_position, "%s at end of compound statement", label_kind);
- inner_stmt = create_invalid_statement();
+ inner_stmt = create_error_statement();
break;
case ';':
* statement after a label. label:; is commonly used to have a label
* before a closing brace. */
inner_stmt = create_empty_statement();
- next_token();
+ eat(';');
break;
}
/* FALLTHROUGH */
default:
inner_stmt = parse_statement();
- /* ISO/IEC 14882:1998(E) §6:1/§6.7 Declarations are statements */
+ /* ISO/IEC 9899:1999(E) §6.8:1/6.8.2:1 Declarations are no statements */
+ /* ISO/IEC 14882:1998(E) §6:1/§6.7 Declarations are statements */
if (inner_stmt->kind == STATEMENT_DECLARATION && !(c_mode & _CXX)) {
errorf(&inner_stmt->base.source_position, "declaration after %s", label_kind);
}
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) {
statement->case_label.statement = parse_label_inner_statement(statement, "case label");
- POP_PARENT;
+ POP_PARENT();
return statement;
}
PUSH_PARENT(statement);
- expect(':', end_error);
-end_error:
+ expect(':');
if (current_switch != NULL) {
const case_label_statement_t *def_label = current_switch->default_label;
statement->case_label.statement = parse_label_inner_statement(statement, "default label");
- POP_PARENT;
+ POP_PARENT();
return statement;
}
static statement_t *parse_label_statement(void)
{
statement_t *const statement = allocate_statement_zero(STATEMENT_LABEL);
- label_t *const label = get_label();
+ label_t *const label = get_label(NULL /* Cannot fail, token is T_IDENTIFIER. */);
statement->label.label = label;
PUSH_PARENT(statement);
eat(':');
+ if (token.kind == T___attribute__ && !(c_mode & _CXX)) {
+ parse_attributes(NULL); // TODO process attributes
+ }
+
statement->label.statement = parse_label_inner_statement(statement, "label");
/* remember the labels in a list for later checking */
*label_anchor = &statement->label;
label_anchor = &statement->label.next;
- POP_PARENT;
+ POP_PARENT();
return statement;
}
+static statement_t *parse_inner_statement(void)
+{
+ statement_t *const stmt = parse_statement();
+ /* ISO/IEC 9899:1999(E) §6.8:1/6.8.2:1 Declarations are no statements */
+ /* ISO/IEC 14882:1998(E) §6:1/§6.7 Declarations are statements */
+ if (stmt->kind == STATEMENT_DECLARATION && !(c_mode & _CXX)) {
+ errorf(&stmt->base.source_position, "declaration as inner statement, use {}");
+ }
+ return stmt;
+}
+
+/**
+ * Parse an expression in parentheses and mark its variables as read.
+ */
+static expression_t *parse_condition(void)
+{
+ add_anchor_token(')');
+ expect('(');
+ 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_statement();
+ statement_t *const true_stmt = parse_inner_statement();
statement->ifs.true_statement = true_stmt;
rem_anchor_token(T_else);
+ if (true_stmt->kind == STATEMENT_EMPTY) {
+ warningf(WARN_EMPTY_BODY, HERE,
+ "suggest braces around empty body in an ‘if’ statement");
+ }
+
if (next_if(T_else)) {
- statement->ifs.false_statement = parse_statement();
+ statement->ifs.false_statement = parse_inner_statement();
+
+ if (statement->ifs.false_statement->kind == STATEMENT_EMPTY) {
+ warningf(WARN_EMPTY_BODY, HERE,
+ "suggest braces around empty body in an ‘if’ statement");
+ }
} else if (true_stmt->kind == STATEMENT_IF &&
true_stmt->ifs.false_statement != NULL) {
source_position_t const *const pos = &true_stmt->base.source_position;
warningf(WARN_PARENTHESES, pos, "suggest explicit braces to avoid ambiguous 'else'");
}
- POP_PARENT;
+ 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);
- if (get_rank(type) >= get_akind_rank(ATOMIC_TYPE_LONG)) {
+ if (get_akind_rank(get_akind(type)) >= get_akind_rank(ATOMIC_TYPE_LONG)) {
warningf(WARN_TRADITIONAL, &expr->base.source_position, "'%T' switch expression not converted to '%T' in ISO C", type, type_int);
}
} else if (is_type_valid(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;
- statement->switchs.body = parse_statement();
+ statement->switchs.body = parse_inner_statement();
current_switch = rem;
if (statement->switchs.default_label == NULL) {
}
check_enum_cases(&statement->switchs);
- POP_PARENT;
+ POP_SCOPE();
+ POP_PARENT();
return statement;
-end_error:
- POP_PARENT;
- return create_invalid_statement();
}
static statement_t *parse_loop_body(statement_t *const loop)
statement_t *const rem = current_loop;
current_loop = loop;
- statement_t *const body = parse_statement();
+ statement_t *const body = parse_inner_statement();
current_loop = rem;
return body;
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_PARENT;
+ POP_SCOPE();
+ POP_PARENT();
return statement;
-end_error:
- POP_PARENT;
- return create_invalid_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_PARENT;
+ POP_SCOPE();
+ POP_PARENT();
return statement;
-end_error:
- POP_PARENT;
- return create_invalid_statement();
}
/**
eat(T_for);
- expect('(', end_error1);
- add_anchor_token(')');
-
PUSH_PARENT(statement);
+ PUSH_SCOPE_STATEMENT(&statement->fors.scope);
- size_t const top = environment_top();
- scope_t *old_scope = scope_push(&statement->fors.scope);
+ add_anchor_token(')');
+ expect('(');
- bool old_gcc_extension = in_gcc_extension;
- while (next_if(T___extension__)) {
- in_gcc_extension = true;
- }
+ PUSH_EXTENSION();
if (next_if(';')) {
} else if (is_declaration_specifier(&token)) {
warningf(WARN_UNUSED_VALUE, &init->base.source_position, "initialisation of 'for'-statement has no effect");
}
rem_anchor_token(';');
- expect(';', end_error2);
+ expect(';');
}
- in_gcc_extension = old_gcc_extension;
- if (token.type != ';') {
+ POP_EXTENSION();
+
+ if (token.kind != ';') {
add_anchor_token(';');
expression_t *const cond = parse_expression();
statement->fors.condition = cond;
mark_vars_read(cond, NULL);
rem_anchor_token(';');
}
- expect(';', end_error2);
- if (token.type != ')') {
+ expect(';');
+ if (token.kind != ')') {
expression_t *const step = parse_expression();
statement->fors.step = step;
mark_vars_read(step, ENT_ANY);
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);
- assert(current_scope == &statement->fors.scope);
- scope_pop(old_scope);
- environment_pop_to(top);
-
- POP_PARENT;
+ POP_SCOPE();
+ POP_PARENT();
return statement;
-
-end_error2:
- POP_PARENT;
- rem_anchor_token(')');
- assert(current_scope == &statement->fors.scope);
- scope_pop(old_scope);
- environment_pop_to(top);
- /* fallthrough */
-
-end_error1:
- return create_invalid_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.type == 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_invalid_statement();
- }
+ statement = allocate_statement_zero(STATEMENT_GOTO);
+ eat(T_goto);
- /* remember the goto's in a list for later checking */
- *goto_anchor = &statement->gotos;
- goto_anchor = &statement->gotos.next;
+ label_t *const label = get_label("while parsing goto");
+ if (label) {
+ label->used = true;
+ statement->gotos.label = label;
- expect(';', end_error);
+ /* remember the goto's in a list for later checking */
+ *goto_anchor = &statement->gotos;
+ goto_anchor = &statement->gotos.next;
+ } else {
+ statement->gotos.label = &allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, sym_anonymous, &builtin_source_position)->label;
+ }
+ }
-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 is_local_variable(entity);
}
-/**
- * Check if a given expression represents a local variable and
- * return its declaration then, else return NULL.
- */
-entity_t *expression_is_variable(const expression_t *expression)
+static void err_or_warn(source_position_t const *const pos, char const *const msg)
{
- if (expression->base.kind != EXPR_REFERENCE) {
- return NULL;
+ if (c_mode & _CXX || strict_mode) {
+ errorf(pos, msg);
+ } else {
+ warningf(WARN_OTHER, pos, msg);
}
- entity_t *entity = expression->reference.entity;
- if (entity->kind != ENTITY_VARIABLE)
- return NULL;
-
- return entity;
}
/**
*/
static statement_t *parse_return(void)
{
- eat(T_return);
-
statement_t *statement = allocate_statement_zero(STATEMENT_RETURN);
+ eat(T_return);
expression_t *return_value = NULL;
- if (token.type != ';') {
+ if (token.kind != ';') {
return_value = parse_expression();
mark_vars_read(return_value, NULL);
}
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;
}
statement->ms_try.try_statement = parse_compound_statement(false);
current_try = rem;
- POP_PARENT;
+ 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_invalid_statement();
}
+ statement->ms_try.final_statement = parse_compound_statement(false);
return statement;
-end_error:
- return create_invalid_statement();
}
static statement_t *parse_empty_statement(void)
entity_t *begin = NULL;
entity_t *end = NULL;
entity_t **anchor = &begin;
+ add_anchor_token(';');
+ add_anchor_token(',');
do {
- if (token.type != T_IDENTIFIER) {
- parse_error_expected("while parsing local label declaration",
- T_IDENTIFIER, NULL);
- goto end_error;
- }
- symbol_t *symbol = token.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);
- } else {
- entity = allocate_entity_zero(ENTITY_LOCAL_LABEL, NAMESPACE_LABEL, symbol);
- entity->base.parent_scope = current_scope;
- entity->base.source_position = token.source_position;
+ source_position_t pos;
+ symbol_t *const symbol = expect_identifier("while parsing local label declaration", &pos);
+ if (symbol) {
+ entity_t *entity = get_entity(symbol, NAMESPACE_LABEL);
+ if (entity != NULL && entity->base.parent_scope == current_scope) {
+ source_position_t const *const ppos = &entity->base.source_position;
+ errorf(&pos, "multiple definitions of '%N' (previous definition %P)", entity, ppos);
+ } else {
+ entity = allocate_entity_zero(ENTITY_LOCAL_LABEL, NAMESPACE_LABEL, symbol, &pos);
+ entity->base.parent_scope = current_scope;
- *anchor = entity;
- anchor = &entity->base.next;
- end = entity;
+ *anchor = entity;
+ anchor = &entity->base.next;
+ end = entity;
- environment_push(entity);
+ environment_push(entity);
+ }
}
- next_token();
} while (next_if(','));
- expect(';', end_error);
-end_error:
+ rem_anchor_token(',');
+ rem_anchor_token(';');
+ expect(';');
statement->declaration.declarations_begin = begin;
statement->declaration.declarations_end = end;
return statement;
entity_t *entity = NULL;
symbol_t *symbol = NULL;
- if (token.type == T_IDENTIFIER) {
- symbol = token.symbol;
- next_token();
-
+ if (token.kind == T_IDENTIFIER) {
+ symbol = token.base.symbol;
entity = get_entity(symbol, NAMESPACE_NORMAL);
- if (entity != NULL
- && entity->kind != ENTITY_NAMESPACE
- && entity->base.parent_scope == current_scope) {
- if (is_entity_valid(entity)) {
- error_redefined_as_different_kind(&token.source_position,
- entity, ENTITY_NAMESPACE);
- }
+ if (entity && entity->kind != ENTITY_NAMESPACE) {
entity = NULL;
+ if (entity->base.parent_scope == current_scope && is_entity_valid(entity)) {
+ error_redefined_as_different_kind(HERE, entity, ENTITY_NAMESPACE);
+ }
}
+ eat(T_IDENTIFIER);
}
if (entity == NULL) {
- entity = allocate_entity_zero(ENTITY_NAMESPACE, NAMESPACE_NORMAL, symbol);
- entity->base.source_position = token.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.type == '=') {
+ if (token.kind == '=') {
/* 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_t *old_scope = scope_push(&entity->namespacee.members);
+ 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_scope == &entity->namespacee.members);
- assert(current_entity == entity);
- current_entity = old_current_entity;
- scope_pop(old_scope);
- environment_pop_to(top);
+ POP_CURRENT_ENTITY();
+ POP_SCOPE();
}
/**
*/
static statement_t *intern_parse_statement(void)
{
- statement_t *statement = NULL;
-
/* declaration or statement */
- add_anchor_token(';');
- switch (token.type) {
+ statement_t *statement;
+ switch (token.kind) {
case T_IDENTIFIER: {
- token_type_t la1_type = (token_type_t)look_ahead(1)->type;
+ token_kind_t la1_type = (token_kind_t)look_ahead(1)->kind;
if (la1_type == ':') {
statement = parse_label_statement();
- } else if (is_typedef_symbol(token.symbol)) {
+ } else if (is_typedef_symbol(token.base.symbol)) {
statement = parse_declaration_statement();
} else {
/* it's an identifier, the grammar says this must be an
switch (la1_type) {
case '&':
case '*':
- if (get_entity(token.symbol, NAMESPACE_NORMAL) != NULL) {
+ if (get_entity(token.base.symbol, NAMESPACE_NORMAL) != NULL) {
default:
statement = parse_expression_statement();
} else {
break;
}
- case T___extension__:
+ case T___extension__: {
/* This can be a prefix to a declaration or an expression statement.
* We simply eat it now and parse the rest with tail recursion. */
- while (next_if(T___extension__)) {}
- bool old_gcc_extension = in_gcc_extension;
- in_gcc_extension = true;
+ PUSH_EXTENSION();
statement = intern_parse_statement();
- in_gcc_extension = old_gcc_extension;
+ POP_EXTENSION();
break;
+ }
DECLARATION_START
statement = parse_declaration_statement();
default:
errorf(HERE, "unexpected token %K while parsing statement", &token);
- statement = create_invalid_statement();
- if (!at_anchor())
- next_token();
+ statement = create_error_statement();
+ eat_until_anchor();
break;
}
- rem_anchor_token(';');
-
- assert(statement != NULL
- && statement->base.source_position.input_name != NULL);
return statement;
}
statement_t *statement = allocate_statement_zero(STATEMENT_COMPOUND);
PUSH_PARENT(statement);
+ PUSH_SCOPE(&statement->compound.scope);
eat('{');
add_anchor_token('}');
add_anchor_token('*');
add_anchor_token('+');
add_anchor_token('-');
+ add_anchor_token(';');
add_anchor_token('{');
add_anchor_token('~');
add_anchor_token(T_CHARACTER_CONSTANT);
add_anchor_token(T_MINUSMINUS);
add_anchor_token(T_PLUSPLUS);
add_anchor_token(T_STRING_LITERAL);
- add_anchor_token(T_WIDE_CHARACTER_CONSTANT);
- add_anchor_token(T_WIDE_STRING_LITERAL);
add_anchor_token(T__Bool);
add_anchor_token(T__Complex);
add_anchor_token(T__Imaginary);
- add_anchor_token(T___FUNCTION__);
add_anchor_token(T___PRETTY_FUNCTION__);
add_anchor_token(T___alignof__);
add_anchor_token(T___attribute__);
add_anchor_token(T_wchar_t);
add_anchor_token(T_while);
- size_t const top = environment_top();
- scope_t *old_scope = scope_push(&statement->compound.scope);
-
statement_t **anchor = &statement->compound.statements;
bool only_decls_so_far = true;
- while (token.type != '}') {
- if (token.type == 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 (is_invalid_statement(sub_statement)) {
- /* an error occurred. if we are at an anchor, return */
- if (at_anchor())
- goto end_error;
- continue;
+ if (sub_statement->kind == STATEMENT_ERROR) {
+ 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___attribute__);
rem_anchor_token(T___alignof__);
rem_anchor_token(T___PRETTY_FUNCTION__);
- rem_anchor_token(T___FUNCTION__);
rem_anchor_token(T__Imaginary);
rem_anchor_token(T__Complex);
rem_anchor_token(T__Bool);
- rem_anchor_token(T_WIDE_STRING_LITERAL);
- rem_anchor_token(T_WIDE_CHARACTER_CONSTANT);
rem_anchor_token(T_STRING_LITERAL);
rem_anchor_token(T_PLUSPLUS);
rem_anchor_token(T_MINUSMINUS);
rem_anchor_token(T_CHARACTER_CONSTANT);
rem_anchor_token('~');
rem_anchor_token('{');
+ rem_anchor_token(';');
rem_anchor_token('-');
rem_anchor_token('+');
rem_anchor_token('*');
rem_anchor_token('&');
rem_anchor_token('!');
rem_anchor_token('}');
- assert(current_scope == &statement->compound.scope);
- scope_pop(old_scope);
- environment_pop_to(top);
- POP_PARENT;
+ POP_SCOPE();
+ POP_PARENT();
return statement;
}
s = "defined";
}
- warningf(why, &declaration->base.source_position, "'%#N' %s but not used", entity);
+ warningf(why, &declaration->base.source_position, "'%#N' %s but not used", entity, s);
}
}
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('(');
- statement->asms.asm_text = parse_string_literals();
+ rem_anchor_token(T_STRING_LITERAL);
+ statement->asms.asm_text = parse_string_literals("global asm");
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)
eat(T_extern);
source_position_t const pos = *HERE;
- char const *const linkage = parse_string_literals().begin;
+ char const *const linkage = parse_string_literals(NULL).begin;
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);
- new_linkage = LINKAGE_INVALID;
+ new_linkage = LINKAGE_C;
}
current_linkage = new_linkage;
if (next_if('{')) {
parse_externals();
- expect('}', end_error);
+ expect('}');
} else {
parse_external();
}
-end_error:
assert(current_linkage == new_linkage);
current_linkage = old_linkage;
}
static void parse_external(void)
{
- switch (token.type) {
+ switch (token.kind) {
+ case T_extern:
+ if (look_ahead(1)->kind == T_STRING_LITERAL) {
+ parse_linkage_specification();
+ } else {
DECLARATION_START_NO_EXTERN
case T_IDENTIFIER:
case T___extension__:
/* tokens below are for implicit int */
- case '&': /* & x; -> int& x; (and error later, because C++ has no
- implicit int) */
- case '*': /* * x; -> int* x; */
- case '(': /* (x); -> int (x); */
- parse_external_declaration();
- return;
-
- case T_extern:
- if (look_ahead(1)->type == T_STRING_LITERAL) {
- parse_linkage_specification();
- } else {
+ case '&': /* & x; -> int& x; (and error later, because C++ has no
+ implicit int) */
+ case '*': /* * x; -> int* x; */
+ case '(': /* (x); -> int (x); */
+ PUSH_EXTENSION();
parse_external_declaration();
+ POP_EXTENSION();
}
return;
case ';':
if (!strict_mode) {
- warningf(WARN_OTHER, HERE, "stray ';' outside of function");
- next_token();
+ warningf(WARN_STRAY_SEMICOLON, HERE, "stray ';' outside of function");
+ eat(';');
return;
}
/* FALLTHROUGH */
default:
errorf(HERE, "stray %K outside of function", &token);
- if (token.type == '(' || token.type == '{' || token.type == '[')
- eat_until_matching_token(token.type);
+ if (token.kind == '(' || token.kind == '{' || token.kind == '[')
+ eat_until_matching_token(token.kind);
next_token();
return;
}
#ifndef NDEBUG
/* make a copy of the anchor set, so we can check if it is restored after parsing */
- unsigned char token_anchor_copy[T_LAST_TOKEN];
+ unsigned short token_anchor_copy[T_LAST_TOKEN];
memcpy(token_anchor_copy, token_anchor_set, sizeof(token_anchor_copy));
#endif
- while (token.type != T_EOF && token.type != '}') {
+ while (token.kind != T_EOF && token.kind != '}') {
#ifndef NDEBUG
for (int i = 0; i < T_LAST_TOKEN; ++i) {
- unsigned char count = token_anchor_set[i] - token_anchor_copy[i];
+ unsigned short count = token_anchor_set[i] - token_anchor_copy[i];
if (count != 0) {
/* the anchor set and its copy differs */
internal_errorf(HERE, "Leaked anchor token %k %d times", i, count);
while (true) {
parse_externals();
- if (token.type == T_EOF)
+ if (token.kind == T_EOF)
break;
errorf(HERE, "stray %K outside of function", &token);
- if (token.type == '(' || token.type == '{' || token.type == '[')
- eat_until_matching_token(token.type);
+ if (token.kind == '(' || token.kind == '{' || token.kind == '[')
+ eat_until_matching_token(token.kind);
next_token();
}
}
{
environment_stack = NEW_ARR_F(stack_entry_t, 0);
label_stack = NEW_ARR_F(stack_entry_t, 0);
- diagnostic_count = 0;
error_count = 0;
warning_count = 0;
}
}
-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)