#include <config.h>
#include <assert.h>
+#include <ctype.h>
#include <stdarg.h>
#include <stdbool.h>
#include "parser.h"
#include "diagnostic.h"
#include "format_check.h"
-#include "lexer.h"
+#include "preprocessor.h"
#include "symbol_t.h"
#include "token_t.h"
#include "types.h"
#include "walk.h"
#include "warning.h"
#include "printer.h"
+#include "ast2firm.h"
#include "adt/bitfiddle.h"
#include "adt/error.h"
#include "adt/array.h"
storage_class_t storage_class;
unsigned char alignment; /**< Alignment, 0 if not set. */
bool is_inline : 1;
- bool thread_local : 1; /**< GCC __thread */
+ bool thread_local : 1;
attribute_t *attributes; /**< list of attributes */
type_t *type;
};
static elf_visibility_tag_t default_visibility = ELF_VISIBILITY_DEFAULT;
+#define PUSH_CURRENT_ENTITY(entity) \
+ entity_t *const new_current_entity = (entity); \
+ entity_t *const old_current_entity = current_entity; \
+ ((void)(current_entity = new_current_entity))
+#define POP_CURRENT_ENTITY() (assert(current_entity == new_current_entity), (void)(current_entity = old_current_entity))
+
#define PUSH_PARENT(stmt) \
statement_t *const new_parent = (stmt); \
statement_t *const old_parent = current_parent; \
#define 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 short token_anchor_set[T_LAST_TOKEN];
case T_static: \
case T_auto: \
case T_register: \
- case T___thread:
+ case T__Thread_local:
#define TYPE_QUALIFIERS \
case T_const: \
case '~': \
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_NUMBER: \
case T_MINUSMINUS: \
case T_PLUSPLUS: \
case T_STRING_LITERAL: \
- case T_WIDE_CHARACTER_CONSTANT: \
- case T_WIDE_STRING_LITERAL: \
+ case T__Alignof: \
case T___FUNCDNAME__: \
case T___FUNCSIG__: \
- case T___FUNCTION__: \
case T___PRETTY_FUNCTION__: \
- case T___alignof__: \
case T___builtin_classify_type: \
case T___builtin_constant_p: \
case T___builtin_isgreater: \
[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),
[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_LITERAL_MS_NOOP] = sizeof(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.base.source_position;
+ res->base.source_position = *HERE;
return res;
}
res->base.kind = kind;
res->base.type = type_error_type;
- res->base.source_position = token.base.source_position;
+ res->base.source_position = *HERE;
return res;
}
{
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)
};
static inline void next_token(void)
{
token = lookahead_buffer[lookahead_bufpos];
- lookahead_buffer[lookahead_bufpos] = lexer_token;
- lexer_next_token();
+ lookahead_buffer[lookahead_bufpos] = pp_token;
+ next_preprocessing_token();
lookahead_bufpos = (lookahead_bufpos + 1) % MAX_LOOKAHEAD;
#endif
}
-static inline bool next_if(token_kind_t const type)
+static inline void eat(token_kind_t const kind)
{
- if (token.kind == type) {
- next_token();
+ assert(token.kind == kind);
+ (void)kind;
+ next_token();
+}
+
+static inline bool next_if(token_kind_t const kind)
+{
+ if (token.kind == kind) {
+ eat(kind);
return true;
} else {
return false;
next_if('}');
}
-#define eat(token_kind) (assert(token.kind == (token_kind)), next_token())
-
/**
* Report a parse error because an expected token was not found.
*/
msg, type1, type2);
}
-/**
- * Expect the current token is the expected token.
- * If not, generate an error and skip until the next anchor.
- */
-static void expect(token_kind_t const expected)
+static bool skip_till(token_kind_t const expected, char const *const context)
{
if (UNLIKELY(token.kind != expected)) {
- parse_error_expected(NULL, expected, NULL);
+ parse_error_expected(context, expected, NULL);
add_anchor_token(expected);
eat_until_anchor();
rem_anchor_token(expected);
if (token.kind != expected)
- return;
+ return false;
}
- eat(expected);
+ return true;
+}
+
+/**
+ * Expect the current token is the expected token.
+ * 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 (token.kind != T_IDENTIFIER) {
- parse_error_expected(context, T_IDENTIFIER, NULL);
- add_anchor_token(T_IDENTIFIER);
- eat_until_anchor();
- rem_anchor_token(T_IDENTIFIER);
- if (token.kind != T_IDENTIFIER)
- return NULL;
- }
- symbol_t *const sym = token.identifier.symbol;
+ if (!skip_till(T_IDENTIFIER, context))
+ return NULL;
+ symbol_t *const sym = token.base.symbol;
if (pos)
*pos = *HERE;
eat(T_IDENTIFIER);
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(string_encoding_t const enc)
{
- assert(token.kind == T_STRING_LITERAL);
- string_t result = token.string.string;
+ 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, enc };
+}
- next_token();
+static string_t concat_string_literals(void)
+{
+ assert(token.kind == T_STRING_LITERAL);
- while (token.kind == T_STRING_LITERAL) {
- warn_string_concat(&token.base.source_position);
- result = concat_strings(&result, &token.string.string);
- next_token();
+ string_t result;
+ if (look_ahead(1)->kind == T_STRING_LITERAL) {
+ append_string(&token.literal.string);
+ eat(T_STRING_LITERAL);
+ warningf(WARN_TRADITIONAL, HERE, "traditional C rejects string constant concatenation");
+ string_encoding_t enc = token.literal.string.encoding;
+ do {
+ if (token.literal.string.encoding != STRING_ENCODING_CHAR) {
+ enc = token.literal.string.encoding;
+ }
+ append_string(&token.literal.string);
+ eat(T_STRING_LITERAL);
+ } while (token.kind == T_STRING_LITERAL);
+ result = finish_string(enc);
+ } else {
+ result = token.literal.string;
+ eat(T_STRING_LITERAL);
}
return result;
}
+static string_t parse_string_literals(char const *const context)
+{
+ if (!skip_till(T_STRING_LITERAL, context))
+ return (string_t){ "", 0, STRING_ENCODING_CHAR };
+
+ source_position_t const pos = *HERE;
+ string_t const res = concat_string_literals();
+
+ if (res.encoding != STRING_ENCODING_CHAR) {
+ errorf(&pos, "expected plain string literal, got wide string literal");
+ }
+
+ return res;
+}
+
static attribute_t *allocate_attribute_zero(attribute_kind_t kind)
{
attribute_t *attribute = allocate_ast_zero(sizeof(*attribute));
/* is it an identifier */
if (token.kind == T_IDENTIFIER
&& (look_ahead(1)->kind == ',' || look_ahead(1)->kind == ')')) {
- symbol_t *symbol = token.identifier.symbol;
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();
return attribute;
}
-static symbol_t *get_symbol_from_token(void)
-{
- switch(token.kind) {
- case T_CHARACTER_CONSTANT:
- case T_EOF:
- case T_FLOATINGPOINT:
- case T_FLOATINGPOINT_HEXADECIMAL:
- case T_INTEGER:
- case T_INTEGER_HEXADECIMAL:
- case T_INTEGER_OCTAL:
- case T_STRING_LITERAL:
- case T_WIDE_CHARACTER_CONSTANT:
- case T_WIDE_STRING_LITERAL:
- return NULL;
-
- default:
- return token.identifier.symbol;
- }
-}
-
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;
char const *const name = symbol->string;
for (kind = ATTRIBUTE_GNU_FIRST;; ++kind) {
if (kind > ATTRIBUTE_GNU_LAST) {
+ /* special case for "__const" */
+ if (token.kind == T_const) {
+ kind = ATTRIBUTE_GNU_CONST;
+ break;
+ }
+
warningf(WARN_ATTRIBUTE, HERE, "unknown attribute '%s' ignored", name);
/* TODO: we should still save the attribute in the list... */
kind = ATTRIBUTE_UNKNOWN;
attribute_t **anchor = &first;
eat(T___attribute__);
+ add_anchor_token(')');
+ add_anchor_token(',');
expect('(');
expect('(');
- add_anchor_token(')');
- add_anchor_token(',');
if (token.kind != ')') do {
attribute_t *attribute = parse_attribute_gnu_single();
if (attribute) {
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_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:
switch (token.kind) {
case '[':
designator = allocate_ast_zero(sizeof(designator[0]));
- designator->source_position = token.base.source_position;
- next_token();
+ designator->source_position = *HERE;
+ eat('[');
add_anchor_token(']');
designator->array_index = parse_constant_expression();
rem_anchor_token(']');
break;
case '.':
designator = allocate_ast_zero(sizeof(designator[0]));
- designator->source_position = token.base.source_position;
- next_token();
+ designator->source_position = *HERE;
+ eat('.');
designator->symbol = expect_identifier("while parsing designator", NULL);
if (!designator->symbol)
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;
-}
-
/**
* Build an initializer from a given expression.
*/
{
/* 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.value.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;
+ }
}
}
}
} 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)) {
return create_empty_initializer();
}
+ initializer_t *result = NULL;
+
type_t *orig_type = path->top_type;
type_t *type = NULL;
} 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.base.source_position;
- designator->symbol = token.identifier.symbol;
+ designator->source_position = *HERE;
+ designator->symbol = token.base.symbol;
eat(T_IDENTIFIER);
eat(':');
} 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");
}
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) {
- sub = initializer_from_expression(outer_type, expression);
- if (sub != NULL) {
+ if (expression->kind == EXPR_STRING_LITERAL && outer_type != NULL) {
+ result = initializer_from_expression(outer_type, expression);
+ if (result != NULL) {
next_if(',');
if (token.kind != '}') {
- warningf(WARN_OTHER, HERE, "excessive elements in initializer for type '%T'", orig_type);
+ warningf(WARN_OTHER, HERE, "excessive elements in initializer for type '%T'", outer_type);
}
/* TODO: eat , ... */
- return sub;
+ goto out;
}
}
ARR_APP1(initializer_t*, initializers, sub);
error_parse_next:
- if (token.kind == '}') {
+ if (!next_if(','))
break;
- }
- add_anchor_token('}');
- expect(',');
- rem_anchor_token('}');
if (token.kind == '}') {
break;
}
size_t len = ARR_LEN(initializers);
size_t size = sizeof(initializer_list_t) + len * sizeof(initializers[0]);
- initializer_t *result = allocate_ast_zero(size);
- result->kind = INITIALIZER_LIST;
- result->list.len = len;
+ result = allocate_ast_zero(size);
+ result->kind = INITIALIZER_LIST;
+ result->list.len = len;
memcpy(&result->list.initializers, initializers,
len * sizeof(initializers[0]));
-
- DEL_ARR_F(initializers);
- ascend_to(path, top_path_level+1);
-
- return result;
+ goto out;
end_error:
skip_initializers();
+out:
DEL_ARR_F(initializers);
ascend_to(path, top_path_level+1);
- return NULL;
+ return result;
}
static expression_t *make_size_literal(size_t value)
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: {
+ size = get_string_len(&get_init_string(result)->value) + 1;
break;
+ }
case INITIALIZER_DESIGNATOR:
case INITIALIZER_VALUE:
entity_kind_tag_t const kind = is_struct ? ENTITY_STRUCT : ENTITY_UNION;
if (token.kind == T_IDENTIFIER) {
/* the compound has a name, check if we have seen it already */
- symbol = token.identifier.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 &&
}
if (attributes != NULL) {
+ entity->compound.attributes = attributes;
handle_entity_attributes(attributes, entity);
}
if (token.kind == '}') {
errorf(HERE, "empty enum not allowed");
- next_token();
+ eat('}');
return;
}
eat(T_enum);
switch (token.kind) {
case T_IDENTIFIER:
- symbol = token.identifier.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 &&
type_t *type;
- expect('(');
add_anchor_token(')');
+ expect('(');
expression_t *expression = NULL;
switch (token.kind) {
case T_IDENTIFIER:
- if (is_typedef_symbol(token.identifier.symbol)) {
+ if (is_typedef_symbol(token.base.symbol)) {
DECLARATION_START
type = parse_typename();
} else {
}
typedef enum specifiers_t {
+ SPECIFIER_NONE = 0,
SPECIFIER_SIGNED = 1 << 0,
SPECIFIER_UNSIGNED = 1 << 1,
SPECIFIER_LONG = 1 << 2,
{
attribute_property_argument_t *const property = allocate_ast_zero(sizeof(*property));
- expect('(');
-
add_anchor_token(')');
add_anchor_token(',');
+ expect('(');
+
do {
add_anchor_token('=');
source_position_t pos;
if (next_if(T_restrict)) {
kind = ATTRIBUTE_MS_RESTRICT;
} else if (token.kind == T_IDENTIFIER) {
- const char *name = token.identifier.symbol->string;
+ 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);
{
eat(T__declspec);
+ add_anchor_token(')');
expect('(');
if (token.kind != ')') {
- add_anchor_token(')');
-
attribute_t **anchor = &first;
do {
while (*anchor != NULL)
*anchor = attribute;
anchor = &attribute->next;
} while (next_if(','));
-
- rem_anchor_token(')');
}
+ rem_anchor_token(')');
expect(')');
return first;
}
bool saw_error = false;
memset(specifiers, 0, sizeof(*specifiers));
- specifiers->source_position = token.base.source_position;
+ specifiers->source_position = *HERE;
while (true) {
specifiers->attributes = parse_attributes(specifiers->attributes);
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)
= parse_microsoft_extended_decl_modifier(specifiers->attributes);
break;
- case T___thread:
+ case T__Thread_local:
if (specifiers->thread_local) {
- errorf(HERE, "duplicate '__thread'");
+ errorf(HERE, "duplicate %K", &token);
} else {
specifiers->thread_local = true;
check_thread_storage_class:
case STORAGE_CLASS_REGISTER: wrong = "register"; goto wrong_thread_storage_class;
case STORAGE_CLASS_TYPEDEF: wrong = "typedef"; goto wrong_thread_storage_class;
wrong_thread_storage_class:
- errorf(HERE, "'__thread' used with '%s'", wrong);
+ errorf(HERE, "%K used with '%s'", &token, wrong);
break;
}
}
#define MATCH_TYPE_QUALIFIER(token, qualifier) \
case token: \
qualifiers |= qualifier; \
- next_token(); \
+ eat(token); \
break
MATCH_TYPE_QUALIFIER(T_const, TYPE_QUALIFIER_CONST);
} 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() \
case T___builtin_va_list:
CHECK_DOUBLE_TYPE();
type = duplicate_type(type_valist);
- next_token();
+ eat(T___builtin_va_list);
break;
case T_IDENTIFIER: {
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.identifier.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
case '*': {
errorf(HERE, "%K does not name a type", &token);
- symbol_t *symbol = token.identifier.symbol;
- entity_t *entity
- = create_error_entity(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;
}
} else {
errorf(pos, "multiple datatypes in declaration");
}
- goto end_error;
+ specifiers->type = type_error_type;
+ return;
}
}
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)
{
assert(token.kind == T_IDENTIFIER);
do {
- entity_t *const entity = allocate_entity_zero(ENTITY_PARAMETER, NAMESPACE_NORMAL, token.identifier.symbol, HERE);
+ 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);
if (look_ahead(1)->kind != ')')
return true;
if (token.kind == T_IDENTIFIER) {
- entity_t const *const entity
- = get_entity(token.identifier.symbol, NAMESPACE_NORMAL);
+ entity_t const *const entity = get_entity(token.base.symbol, NAMESPACE_NORMAL);
if (entity == NULL)
return true;
if (entity->kind != ENTITY_TYPEDEF)
*/
static void parse_parameters(function_type_t *type, scope_t *scope)
{
- eat('(');
add_anchor_token(')');
+ eat('(');
- if (token.kind == T_IDENTIFIER &&
- !is_typedef_symbol(token.identifier.symbol) &&
+ 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);
do {
switch (token.kind) {
case T_DOTDOTDOT:
- next_token();
+ eat(T_DOTDOTDOT);
type->variadic = true;
goto parameters_finished;
expression_t *size = NULL;
if (token.kind == '*' && look_ahead(1)->kind == ']') {
array->is_variable = true;
- next_token();
+ eat('*');
} else if (token.kind != ']') {
size = parse_assignment_expression();
if (env->must_be_abstract) {
errorf(HERE, "no identifier expected in typename");
} else {
- env->symbol = token.identifier.symbol;
- env->source_position = token.base.source_position;
+ env->symbol = token.base.symbol;
+ env->source_position = *HERE;
}
- next_token();
+ eat(T_IDENTIFIER);
break;
case '(': {
token_t const *const la1 = look_ahead(1);
switch (la1->kind) {
case T_IDENTIFIER:
- if (is_typedef_symbol(la1->identifier.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) {
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) {
}
}
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);
}
}
}
}
}
-/**
- * Check if a symbol is the equal to "main".
- */
-static bool is_sym_main(const symbol_t *const sym)
-{
- return streq(sym->string, "main");
-}
-
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);
}
}
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) {
} else if (!is_definition &&
is_type_valid(prev_type) &&
!pos->is_system_header) {
- warningf(WARN_REDUNDANT_DECLS, pos, "redundant declaration for '%Y' (declared %P)", symbol, ppos);
+ 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)
DECLARATION_START
return true;
case T_IDENTIFIER:
- return is_typedef_symbol(token->identifier.symbol);
+ return is_typedef_symbol(token->base.symbol);
default:
return false;
warn_unused_entity(WARN_UNUSED_PARAMETER, scope->entities, NULL);
}
if (is_warn_on(WARN_UNUSED_VARIABLE)) {
- walk_statements(current_function->statement, check_unused_variables,
- NULL);
+ walk_statements(current_function->body, check_unused_variables, NULL);
}
}
case EXPR_REFERENCE:
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 INITIALIZER_STRING:
- case INITIALIZER_WIDE_STRING:
case INITIALIZER_DESIGNATOR: // designators have no payload
return true;
}
return;
if (is_constant_expression(expr) == EXPR_CLASS_CONSTANT) {
- long const val = fold_constant_to_int(expr);
+ ir_tarval *const val = fold_constant_to_tarval(expr);
case_label_statement_t * defaults = NULL;
for (case_label_statement_t *i = switchs->first_case; i != NULL; i = i->next) {
if (i->expression == NULL) {
continue;
}
- if (i->first_case <= val && val <= i->last_case) {
+ if (i->first_case == val || i->last_case == val ||
+ ((tarval_cmp(i->first_case, val) & ir_relation_less_equal)
+ && (tarval_cmp(val, i->last_case) & ir_relation_less_equal))) {
check_reachable((statement_t*)i);
return;
}
next = parent;
switch (parent->kind) {
- case STATEMENT_WHILE: goto continue_while;
case STATEMENT_DO_WHILE: goto continue_do_while;
case STATEMENT_FOR: goto continue_for;
switch (parent->kind) {
case STATEMENT_SWITCH:
- case STATEMENT_WHILE:
case STATEMENT_DO_WHILE:
case STATEMENT_FOR:
last = parent;
next = stmt->case_label.statement;
break;
- case STATEMENT_WHILE: {
- while_statement_t const *const whiles = &stmt->whiles;
- expression_t const *const cond = whiles->condition;
-
- if (!expression_returns(cond))
- return;
-
- int const val = determine_truth(cond);
-
- if (val >= 0)
- check_reachable(whiles->body);
-
- if (val > 0)
- return;
-
- next = stmt->base.next;
- break;
- }
-
case STATEMENT_DO_WHILE:
next = stmt->do_while.body;
break;
type_t *const ret = skip_typeref(type->function.return_type);
if (!is_type_void(ret) &&
is_type_valid(ret) &&
- !is_sym_main(current_function->base.base.symbol)) {
+ !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");
}
next = next->base.next;
break;
- case STATEMENT_WHILE: {
-continue_while:
- if (next->base.reachable)
- return;
- next->base.reachable = true;
-
- while_statement_t const *const whiles = &next->whiles;
- expression_t const *const cond = whiles->condition;
-
- if (!expression_returns(cond))
- return;
-
- int const val = determine_truth(cond);
-
- if (val >= 0)
- check_reachable(whiles->body);
-
- if (val > 0)
- return;
-
- last = next;
- next = next->base.next;
- break;
- }
-
case STATEMENT_DO_WHILE: {
continue_do_while:
if (next->base.reachable)
environment_push(parameter);
}
- if (function->statement != NULL) {
+ if (function->body != NULL) {
parser_error_multiple_definition(entity, HERE);
eat_block();
} else {
/* parse function body */
int label_stack_top = label_top();
function_t *old_current_function = current_function;
- entity_t *old_current_entity = current_entity;
current_function = function;
- current_entity = entity;
+ PUSH_CURRENT_ENTITY(entity);
PUSH_PARENT(NULL);
goto_first = NULL;
label_anchor = &label_first;
statement_t *const body = parse_compound_statement(false);
- function->statement = body;
+ function->body = body;
first_err = true;
check_labels();
check_declarations();
}
}
- if (is_main(entity) && enable_main_collect2_hack)
- prepare_main_collect2(entity);
+ 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);
}
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;
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);
}
}
static expression_parser_function_t expression_parsers[T_LAST_TOKEN];
-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)
+static type_t *get_string_type(string_encoding_t const enc)
{
- return is_warn_on(WARN_WRITE_STRINGS) ? type_const_wchar_t_ptr : type_wchar_t_ptr;
+ 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;
+ }
+ panic("invalid string encoding");
}
/**
*/
static expression_t *parse_string_literal(void)
{
- source_position_t begin = token.base.source_position;
- string_t res = token.string.string;
- bool is_wide = (token.kind == T_WIDE_STRING_LITERAL);
-
- next_token();
- while (token.kind == T_STRING_LITERAL
- || token.kind == T_WIDE_STRING_LITERAL) {
- warn_string_concat(&token.base.source_position);
- res = concat_strings(&res, &token.string.string);
- next_token();
- is_wide |= token.kind == 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->base.type = get_string_type(expr->string_literal.value.encoding);
+ return expr;
}
/**
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)
+static void warn_traditional_suffix(char const *const suffix)
{
- warningf(WARN_TRADITIONAL, HERE, "traditional C rejects the '%S' suffix",
- &token.number.suffix);
+ warningf(WARN_TRADITIONAL, HERE, "traditional C rejects the '%s' suffix", suffix);
}
-static void check_integer_suffix(void)
+static void check_integer_suffix(expression_t *const expr, char const *const suffix)
{
- const string_t *suffix = &token.number.suffix;
- if (suffix->size == 0)
- return;
-
- bool not_traditional = false;
- const char *c = suffix->begin;
- if (*c == 'l' || *c == 'L') {
- ++c;
- if (*c == *(c-1)) {
- not_traditional = true;
- ++c;
- if (*c == 'u' || *c == 'U') {
+ unsigned spec = SPECIFIER_NONE;
+ char const *c = suffix;
+ for (;;) {
+ specifiers_t add;
+ if (*c == 'L' || *c == 'l') {
+ add = SPECIFIER_LONG;
+ if (*c == c[1]) {
+ add |= SPECIFIER_LONG_LONG;
++c;
}
- } else if (*c == 'u' || *c == 'U') {
- not_traditional = true;
- ++c;
+ } else if (*c == 'U' || *c == 'u') {
+ add = SPECIFIER_UNSIGNED;
+ } else {
+ break;
}
- } else if (*c == 'u' || *c == 'U') {
- not_traditional = true;
++c;
- if (*c == 'l' || *c == 'L') {
- ++c;
- if (*c == *(c-1)) {
- ++c;
- }
- }
- }
- if (*c != '\0') {
- errorf(&token.base.source_position,
- "invalid suffix '%S' on integer constant", suffix);
- } else if (not_traditional) {
- warn_traditional_suffix();
+ if (spec & add)
+ goto error;
+ spec |= add;
+ }
+
+ if (*c == '\0') {
+ type_t *type;
+ switch (spec) {
+ case SPECIFIER_NONE: type = type_int; break;
+ case SPECIFIER_LONG: type = type_long; break;
+ case SPECIFIER_LONG | SPECIFIER_LONG_LONG: type = type_long_long; break;
+ case SPECIFIER_UNSIGNED: type = type_unsigned_int; break;
+ case SPECIFIER_UNSIGNED | SPECIFIER_LONG: type = type_unsigned_long; break;
+ case SPECIFIER_UNSIGNED | SPECIFIER_LONG | SPECIFIER_LONG_LONG: type = type_unsigned_long_long; break;
+ default: panic("inconsistent suffix");
+ }
+ if (spec != SPECIFIER_NONE && spec != SPECIFIER_LONG) {
+ warn_traditional_suffix(suffix);
+ }
+ expr->base.type = type;
+ /* Integer type depends on the size of the number and the size
+ * representable by the types. The backend/codegeneration has to
+ * determine that. */
+ determine_literal_type(&expr->literal);
+ } else {
+error:
+ errorf(HERE, "invalid suffix '%s' on integer constant", suffix);
}
}
-static type_t *check_floatingpoint_suffix(void)
+static void check_floatingpoint_suffix(expression_t *const expr, char const *const suffix)
{
- 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->begin;
- if (*c == 'f' || *c == 'F') {
- ++c;
- type = type_float;
- } else if (*c == 'l' || *c == 'L') {
- ++c;
- type = type_long_double;
- }
- if (*c != '\0') {
- errorf(&token.base.source_position,
- "invalid suffix '%S' on floatingpoint constant", suffix);
- } else if (not_traditional) {
- warn_traditional_suffix();
+ type_t *type;
+ char const *c = suffix;
+ switch (*c) {
+ case 'F':
+ case 'f': type = type_float; ++c; break;
+ case 'L':
+ case 'l': type = type_long_double; ++c; break;
+ default: type = type_double; break;
}
- return type;
+ if (*c == '\0') {
+ expr->base.type = type;
+ if (suffix[0] != '\0') {
+ warn_traditional_suffix(suffix);
+ }
+ } else {
+ errorf(HERE, "invalid suffix '%s' on floatingpoint constant", suffix);
+ }
}
-/**
- * Parse an integer constant.
- */
static expression_t *parse_number_literal(void)
{
- expression_kind_t kind;
- type_t *type;
+ string_t const *const str = &token.literal.string;
+ char const * i = str->begin;
+ unsigned digits = 0;
+ bool is_float = false;
- 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;
+ /* Parse base prefix. */
+ unsigned base;
+ if (*i == '0') {
+ switch (*++i) {
+ case 'B': case 'b': base = 2; ++i; break;
+ case 'X': case 'x': base = 16; ++i; break;
+ default: base = 8; digits |= 1U << 0; break;
+ }
+ } else {
+ base = 10;
+ }
+
+ /* Parse mantissa. */
+ for (;; ++i) {
+ unsigned digit;
+ switch (*i) {
+ case '.':
+ if (is_float) {
+ errorf(HERE, "multiple decimal points in %K", &token);
+ i = 0;
+ goto done;
+ }
+ is_float = true;
+ if (base == 8)
+ base = 10;
+ continue;
+
+ case '0': digit = 0; break;
+ case '1': digit = 1; break;
+ case '2': digit = 2; break;
+ case '3': digit = 3; break;
+ case '4': digit = 4; break;
+ case '5': digit = 5; break;
+ case '6': digit = 6; break;
+ case '7': digit = 7; break;
+ case '8': digit = 8; break;
+ case '9': digit = 9; break;
+ case 'A': case 'a': digit = 10; break;
+ case 'B': case 'b': digit = 11; break;
+ case 'C': case 'c': digit = 12; break;
+ case 'D': case 'd': digit = 13; break;
+ case 'E': case 'e': digit = 14; break;
+ case 'F': case 'f': digit = 15; break;
+
+ default: goto done_mantissa;
+ }
+
+ if (digit >= 10 && base != 16)
+ goto done_mantissa;
+
+ digits |= 1U << digit;
+ }
+done_mantissa:
+
+ /* Parse exponent. */
+ switch (base) {
+ case 2:
+ if (is_float)
+ errorf(HERE, "binary floating %K not allowed", &token);
break;
- case T_FLOATINGPOINT:
- kind = EXPR_LITERAL_FLOATINGPOINT;
- type = check_floatingpoint_suffix();
+
+ case 8:
+ case 10:
+ if (*i == 'E' || *i == 'e') {
+ base = 10;
+ goto parse_exponent;
+ }
break;
- case T_FLOATINGPOINT_HEXADECIMAL:
- kind = EXPR_LITERAL_FLOATINGPOINT_HEXADECIMAL;
- type = check_floatingpoint_suffix();
+
+ case 16:
+ if (*i == 'P' || *i == 'p') {
+parse_exponent:
+ ++i;
+ is_float = true;
+
+ if (*i == '-' || *i == '+')
+ ++i;
+
+ if (isdigit(*i)) {
+ do {
+ ++i;
+ } while (isdigit(*i));
+ } else {
+ errorf(HERE, "exponent of %K has no digits", &token);
+ }
+ } else if (is_float) {
+ errorf(HERE, "hexadecimal floating %K requires an exponent", &token);
+ i = 0;
+ }
break;
+
default:
- panic("unexpected token type in parse_number_literal");
+ panic("invalid base");
}
- expression_t *literal = allocate_expression_zero(kind);
- 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
- * representable by the types. The backend/codegeneration has to determine
- * that
- */
- determine_literal_type(&literal->literal);
- return literal;
-}
-
-/**
- * Parse a character constant.
- */
-static expression_t *parse_character_constant(void)
-{
- expression_t *literal = allocate_expression_zero(EXPR_LITERAL_CHARACTER);
- literal->base.type = c_mode & _CXX ? type_char : type_int;
- literal->literal.value = token.string.string;
+done:;
+ expression_t *const expr = allocate_expression_zero(is_float ? EXPR_LITERAL_FLOATINGPOINT : EXPR_LITERAL_INTEGER);
+ expr->literal.value = *str;
- 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");
+ if (i) {
+ if (digits == 0) {
+ errorf(HERE, "%K has no digits", &token);
+ } else if (digits & ~((1U << base) - 1)) {
+ errorf(HERE, "invalid digit in %K", &token);
} else {
- literal->base.type = type_int;
- warningf(WARN_MULTICHAR, HERE, "multi-character character constant");
+ expr->literal.suffix = i;
+ if (is_float) {
+ check_floatingpoint_suffix(expr, i);
+ } else {
+ check_integer_suffix(expr, i);
+ }
}
}
- next_token();
- return literal;
+ eat(T_NUMBER);
+ return expr;
}
/**
- * Parse a wide character constant.
+ * Parse a character constant.
*/
-static expression_t *parse_wide_character_constant(void)
+static expression_t *parse_character_constant(void)
{
- expression_t *literal = allocate_expression_zero(EXPR_LITERAL_WIDE_CHARACTER);
- literal->base.type = type_int;
- literal->literal.value = token.string.string;
+ expression_t *const literal = allocate_expression_zero(EXPR_LITERAL_CHARACTER);
+ literal->string_literal.value = token.literal.string;
- size_t len = wstrlen(&literal->literal.value);
- if (len > 1) {
- warningf(WARN_MULTICHAR, HERE, "multi-character character constant");
+ size_t const size = get_string_len(&token.literal.string);
+ switch (token.literal.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;
+
+ case STRING_ENCODING_WIDE:
+ literal->base.type = type_int;
+ if (size > 1) {
+ warningf(WARN_MULTICHAR, HERE, "multi-character character constant");
+ }
+ break;
}
- next_token();
+ eat(T_CHARACTER_CONSTANT);
return literal;
}
}
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.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:
if (entity == NULL) {
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.base.source_position;
+ source_position_t const pos = *HERE;
entity_t *const entity = parse_qualified_identifier();
type_t *orig_type;
&& (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;
}
return parse_statement_expression();
case T_IDENTIFIER:
- if (is_typedef_symbol(la1->identifier.symbol)) {
+ if (is_typedef_symbol(la1->base.symbol)) {
DECLARATION_START
return parse_cast();
}
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 *const result = allocate_ast_zero(sizeof(result[0]));
eat(T___builtin_offsetof);
- expect('(');
add_anchor_token(')');
add_anchor_token(',');
+ expect('(');
type_t *type = parse_typename();
rem_anchor_token(',');
expect(',');
return 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('(');
add_anchor_token(')');
add_anchor_token(',');
+ expect('(');
expression->va_starte.ap = parse_assignment_expression();
rem_anchor_token(',');
expect(',');
- 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;
- }
- } else {
- expression = create_error_expression();
- }
+ 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");
+ }
+
return expression;
}
eat(T___builtin_va_arg);
- expect('(');
add_anchor_token(')');
add_anchor_token(',');
+ expect('(');
call_argument_t ap;
ap.expression = parse_assignment_expression();
expression->va_arge.ap = ap.expression;
eat(T___builtin_va_copy);
- expect('(');
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",
eat(T___builtin_constant_p);
- expect('(');
add_anchor_token(')');
+ expect('(');
expression->builtin_constant.value = parse_assignment_expression();
rem_anchor_token(')');
expect(')');
eat(T___builtin_types_compatible_p);
- expect('(');
add_anchor_token(')');
add_anchor_token(',');
+ expect('(');
expression->builtin_types_compatible.left = parse_typename();
rem_anchor_token(',');
expect(',');
*/
static expression_t *parse_compare_builtin(void)
{
- expression_t *expression;
-
+ expression_kind_t kind;
switch (token.kind) {
- 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;
+ 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('(');
add_anchor_token(')');
add_anchor_token(',');
+ expect('(');
expression->binary.left = parse_assignment_expression();
rem_anchor_token(',');
expect(',');
eat(T__assume);
- expect('(');
add_anchor_token(')');
+ expect('(');
expression->unary.value = parse_assignment_expression();
rem_anchor_token(')');
expect(')');
/**
* 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.kind == T_IDENTIFIER);
assert(current_function != NULL);
- entity_t *label = get_entity(token.identifier.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. */
source_position_t const nowhere = { NULL, 0, 0, false };
- label = allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, token.identifier.symbol, &nowhere);
+ 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.base.source_position;
+ source_position_t const source_position = *HERE;
eat(T_ANDAND);
- if (token.kind != T_IDENTIFIER) {
- parse_error_expected("while parsing label address", T_IDENTIFIER, NULL);
+
+ label_t *const label = get_label("while parsing label address");
+ if (!label)
return create_error_expression();
- }
- label_t *const label = get_label();
label->used = true;
label->address_taken = true;
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_NUMBER: 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.identifier.symbol)) {
+ if (!is_typedef_symbol(token.base.symbol)) {
return parse_reference();
}
/* FALLTHROUGH */
expression_t *tp_expression = allocate_expression_zero(kind);
tp_expression->base.type = type_size_t;
- eat(kind == EXPR_SIZEOF ? T_sizeof : T___alignof__);
+ eat(kind == EXPR_SIZEOF ? T_sizeof : T__Alignof);
type_t *orig_type;
expression_t *expression;
if (token.kind == '(' && is_declaration_specifier(look_ahead(1))) {
source_position_t const pos = *HERE;
- next_token();
+ eat('(');
add_anchor_token(')');
orig_type = parse_typename();
rem_anchor_token(')');
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'",
"third argument of '%Y' must be a constant expression",
call->function->reference.entity->base.symbol);
}
- locality = rw->next;
}
break;
default:
eat(T___builtin_classify_type);
- expect('(');
add_anchor_token(')');
+ expect('(');
expression_t *expression = parse_expression();
rem_anchor_token(')');
expect(')');
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;
}
/**
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");
}
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;
{
expression_parser_function_t *entry = &expression_parsers[token_kind];
- if (entry->parser != NULL) {
- diagnosticf("for token '%k'\n", (token_kind_t)token_kind);
- panic("trying to register multiple expression parsers for a token");
- }
+ assert(!entry->parser);
entry->parser = parser;
}
{
expression_parser_function_t *entry = &expression_parsers[token_kind];
- if (entry->infix_parser != NULL) {
- diagnosticf("for token '%k'\n", (token_kind_t)token_kind);
- panic("trying to register multiple infix expression parsers for a "
- "token");
- }
+ assert(!entry->infix_parser);
entry->infix_parser = parser;
entry->infix_precedence = precedence;
}
register_expression_parser(parse_EXPR_UNARY_PREFIX_INCREMENT, T_PLUSPLUS);
register_expression_parser(parse_EXPR_UNARY_PREFIX_DECREMENT, T_MINUSMINUS);
register_expression_parser(parse_sizeof, T_sizeof);
- register_expression_parser(parse_alignof, T___alignof__);
+ register_expression_parser(parse_alignof, T__Alignof);
register_expression_parser(parse_extension, T___extension__);
register_expression_parser(parse_builtin_classify_type, T___builtin_classify_type);
register_expression_parser(parse_delete, T_delete);
return NULL;
}
- argument->constraints = parse_string_literals();
- expect('(');
+ argument->constraints = parse_string_literals("asm argument");
add_anchor_token(')');
+ expect('(');
expression_t *expression = parse_expression();
rem_anchor_token(')');
if (is_out) {
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('(');
- add_anchor_token(')');
- if (token.kind != T_STRING_LITERAL) {
- parse_error_expected("after asm(", T_STRING_LITERAL, NULL);
- goto end_of_asm;
- }
- asm_statement->asm_text = parse_string_literals();
+ 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(')');
expect(';');
* 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 */
}
statement->case_label.is_bad = true;
} else {
- long const val = fold_constant_to_int(expression);
+ ir_tarval *val = fold_constant_to_tarval(expression);
statement->case_label.first_case = val;
statement->case_label.last_case = val;
}
}
statement->case_label.is_bad = true;
} else {
- long const val = fold_constant_to_int(end_range);
+ ir_tarval *val = fold_constant_to_tarval(end_range);
statement->case_label.last_case = val;
- if (val < statement->case_label.first_case) {
+ if (tarval_cmp(val, statement->case_label.first_case)
+ == ir_relation_less) {
statement->case_label.is_empty_range = true;
warningf(WARN_OTHER, pos, "empty range specified");
}
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);
} else {
label->base.source_position = *pos;
label->statement = statement;
+ label->n_users += 1;
}
eat(':');
*/
static expression_t *parse_condition(void)
{
- expect('(');
add_anchor_token(')');
+ expect('(');
expression_t *const expr = parse_expression();
mark_vars_read(expr, NULL);
rem_anchor_token(')');
{
if (!is_warn_on(WARN_SWITCH_ENUM))
return;
- const type_t *type = skip_typeref(statement->expression->base.type);
+ type_t *type = skip_typeref(statement->expression->base.type);
if (! is_type_enum(type))
return;
- const enum_type_t *enumt = &type->enumt;
+ enum_type_t *enumt = &type->enumt;
/* if we have a default, no warnings */
if (statement->default_label != NULL)
return;
+ determine_enum_values(enumt);
+
/* FIXME: calculation of value should be done while parsing */
/* TODO: quadratic algorithm here. Change to an n log n one */
- long last_value = -1;
- const entity_t *entry = enumt->enume->base.next;
+ const entity_t *entry = enumt->enume->base.next;
for (; entry != NULL && entry->kind == ENTITY_ENUM_VALUE;
entry = entry->base.next) {
- const expression_t *expression = entry->enum_value.value;
- long value = expression != NULL ? fold_constant_to_int(expression) : last_value + 1;
- bool found = false;
- for (const case_label_statement_t *l = statement->first_case; l != NULL; l = l->next) {
+ ir_tarval *value = entry->enum_value.tv;
+ bool found = false;
+ for (const case_label_statement_t *l = statement->first_case; l != NULL;
+ l = l->next) {
if (l->expression == NULL)
continue;
- if (l->first_case <= value && value <= l->last_case) {
+ if (l->first_case == l->last_case && l->first_case != value)
+ continue;
+ if ((tarval_cmp(l->first_case, value) & ir_relation_less_equal)
+ && (tarval_cmp(value, l->last_case) & ir_relation_less_equal)) {
found = true;
break;
}
source_position_t const *const pos = &statement->base.source_position;
warningf(WARN_SWITCH_ENUM, pos, "'%N' not handled in switch", entry);
}
- last_value = value;
}
}
*/
static statement_t *parse_while(void)
{
- statement_t *statement = allocate_statement_zero(STATEMENT_WHILE);
+ statement_t *statement = allocate_statement_zero(STATEMENT_FOR);
eat(T_while);
PUSH_PARENT(statement);
- PUSH_SCOPE_STATEMENT(&statement->whiles.scope);
+ PUSH_SCOPE_STATEMENT(&statement->fors.scope);
expression_t *const cond = parse_condition();
- statement->whiles.condition = cond;
+ statement->fors.condition = cond;
/* ยง6.8.5:2 The controlling expression of an iteration statement shall
* have scalar type. */
semantic_condition(cond, "condition of 'while'-statement");
- statement->whiles.body = parse_loop_body(statement);
+ statement->fors.body = parse_loop_body(statement);
POP_SCOPE();
POP_PARENT();
PUSH_PARENT(statement);
PUSH_SCOPE_STATEMENT(&statement->fors.scope);
- expect('(');
add_anchor_token(')');
+ expect('(');
PUSH_EXTENSION();
} else {
statement = allocate_statement_zero(STATEMENT_GOTO);
eat(T_goto);
- if (token.kind == T_IDENTIFIER) {
- label_t *const label = get_label();
+
+ label_t *const label = get_label("while parsing goto");
+ if (label) {
+ label->n_users += 1;
label->used = true;
statement->gotos.label = label;
*goto_anchor = &statement->gotos;
goto_anchor = &statement->gotos.next;
} else {
- if (GNU_MODE)
- parse_error_expected("while parsing goto", T_IDENTIFIER, '*', NULL);
- else
- parse_error_expected("while parsing goto", T_IDENTIFIER, NULL);
- eat_until_anchor();
statement->gotos.label = &allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, sym_anonymous, &builtin_source_position)->label;
}
}
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)
-{
- if (expression->base.kind != EXPR_REFERENCE) {
- return NULL;
- }
- entity_t *entity = expression->reference.entity;
- if (entity->kind != ENTITY_VARIABLE)
- return NULL;
-
- return entity;
-}
-
static void err_or_warn(source_position_t const *const pos, char const *const msg)
{
if (c_mode & _CXX || strict_mode) {
entity_t *begin = NULL;
entity_t *end = NULL;
entity_t **anchor = &begin;
+ add_anchor_token(';');
+ add_anchor_token(',');
do {
source_position_t pos;
symbol_t *const symbol = expect_identifier("while parsing local label declaration", &pos);
- if (!symbol)
- goto end_error;
-
- 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;
+ 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);
+ }
}
} while (next_if(','));
+ rem_anchor_token(',');
+ rem_anchor_token(';');
expect(';');
-end_error:
statement->declaration.declarations_begin = begin;
statement->declaration.declarations_end = end;
return statement;
symbol_t *symbol = NULL;
if (token.kind == T_IDENTIFIER) {
- symbol = token.identifier.symbol;
- next_token();
-
+ 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.base.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) {
append_entity(current_scope, entity);
PUSH_SCOPE(&entity->namespacee.members);
-
- entity_t *old_current_entity = current_entity;
- current_entity = entity;
+ PUSH_CURRENT_ENTITY(entity);
add_anchor_token('}');
expect('{');
rem_anchor_token('}');
expect('}');
- assert(current_entity == entity);
- current_entity = old_current_entity;
+ POP_CURRENT_ENTITY();
POP_SCOPE();
}
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.identifier.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.identifier.symbol, NAMESPACE_NORMAL) != NULL) {
+ if (get_entity(token.base.symbol, NAMESPACE_NORMAL) != NULL) {
default:
statement = parse_expression_statement();
} else {
add_anchor_token('~');
add_anchor_token(T_CHARACTER_CONSTANT);
add_anchor_token(T_COLONCOLON);
- add_anchor_token(T_FLOATINGPOINT);
add_anchor_token(T_IDENTIFIER);
- add_anchor_token(T_INTEGER);
add_anchor_token(T_MINUSMINUS);
+ add_anchor_token(T_NUMBER);
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__Alignof);
add_anchor_token(T__Bool);
add_anchor_token(T__Complex);
add_anchor_token(T__Imaginary);
- add_anchor_token(T___FUNCTION__);
+ add_anchor_token(T__Thread_local);
add_anchor_token(T___PRETTY_FUNCTION__);
- add_anchor_token(T___alignof__);
add_anchor_token(T___attribute__);
add_anchor_token(T___builtin_va_start);
add_anchor_token(T___extension__);
add_anchor_token(T___imag__);
add_anchor_token(T___label__);
add_anchor_token(T___real__);
- add_anchor_token(T___thread);
add_anchor_token(T_asm);
add_anchor_token(T_auto);
add_anchor_token(T_bool);
rem_anchor_token(T_bool);
rem_anchor_token(T_auto);
rem_anchor_token(T_asm);
- rem_anchor_token(T___thread);
rem_anchor_token(T___real__);
rem_anchor_token(T___label__);
rem_anchor_token(T___imag__);
rem_anchor_token(T___extension__);
rem_anchor_token(T___builtin_va_start);
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__Thread_local);
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__Alignof);
rem_anchor_token(T_STRING_LITERAL);
rem_anchor_token(T_PLUSPLUS);
+ rem_anchor_token(T_NUMBER);
rem_anchor_token(T_MINUSMINUS);
- rem_anchor_token(T_INTEGER);
rem_anchor_token(T_IDENTIFIER);
- rem_anchor_token(T_FLOATINGPOINT);
rem_anchor_token(T_COLONCOLON);
rem_anchor_token(T_CHARACTER_CONSTANT);
rem_anchor_token('~');
continue;
why = WARN_UNUSED_FUNCTION;
- s = entity->function.statement != NULL ? "defined" : "declared";
+ s = entity->function.body != NULL ? "defined" : "declared";
} else {
why = WARN_UNUSED_VARIABLE;
s = "defined";
expect('(');
rem_anchor_token(T_STRING_LITERAL);
- statement->asms.asm_text = parse_string_literals();
+ statement->asms.asm_text = parse_string_literals("global asm");
statement->base.next = unit->global_asm;
unit->global_asm = statement;
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;
case ';':
if (!strict_mode) {
warningf(WARN_STRAY_SEMICOLON, HERE, "stray ';' outside of function");
- next_token();
+ eat(';');
return;
}
/* FALLTHROUGH */
{
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;
print_to_file(stderr);
static void prepare_main_collect2(entity_t *const entity)
{
- PUSH_SCOPE(&entity->function.statement->compound.scope);
+ PUSH_SCOPE(&entity->function.body->compound.scope);
// create call to __main
symbol_t *symbol = symbol_table_insert("__main");
expr_statement->base.source_position = builtin_source_position;
expr_statement->expression.expression = call;
- statement_t *statement = entity->function.statement;
- assert(statement->kind == STATEMENT_COMPOUND);
- compound_statement_t *compounds = &statement->compound;
+ statement_t *const body = entity->function.body;
+ assert(body->kind == STATEMENT_COMPOUND);
+ compound_statement_t *compounds = &body->compound;
expr_statement->base.next = compounds->statements;
compounds->statements = expr_statement;
*/
void init_parser(void)
{
- sym_anonymous = symbol_table_insert("<anonymous>");
-
memset(token_anchor_set, 0, sizeof(token_anchor_set));
init_expression_parsers();