static statement_t *parse_compound_statement(bool inside_expression_statement);
static statement_t *parse_statement(void);
-static expression_t *parse_sub_expression(precedence_t);
+static expression_t *parse_subexpression(precedence_t);
static expression_t *parse_expression(void);
static type_t *parse_typename(void);
static void parse_externals(void);
static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
declarator_flags_t flags);
-static entity_t *record_entity(entity_t *entity, bool is_definition);
-
static void semantic_comparison(binary_expression_t *expression);
-static void create_gnu_builtins(void);
-static void create_microsoft_intrinsics(void);
-
#define STORAGE_CLASSES \
STORAGE_CLASSES_NO_EXTERN \
case T_extern:
TYPE_QUALIFIERS \
TYPE_SPECIFIERS
-#define EXPRESSION_START \
- case '!': \
- case '&': \
- case '(': \
- case '*': \
- case '+': \
- case '-': \
- case '~': \
- case T_ANDAND: \
- case T_CHARACTER_CONSTANT: \
- case T_FLOATINGPOINT: \
- case T_INTEGER: \
- 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: \
- case T___builtin_constant_p: \
- case T___builtin_isgreater: \
- case T___builtin_isgreaterequal: \
- case T___builtin_isless: \
- case T___builtin_islessequal: \
- case T___builtin_islessgreater: \
- case T___builtin_isunordered: \
- case T___builtin_offsetof: \
- case T___builtin_va_arg: \
- case T___builtin_va_start: \
- case T___builtin_va_copy: \
- case T___func__: \
- case T___noop: \
- case T__assume: \
- case T_delete: \
- case T_false: \
- case T_sizeof: \
- case T_throw: \
+#define EXPRESSION_START \
+ case '!': \
+ case '&': \
+ case '(': \
+ case '*': \
+ case '+': \
+ case '-': \
+ 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_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: \
+ case T___builtin_constant_p: \
+ case T___builtin_isgreater: \
+ case T___builtin_isgreaterequal: \
+ case T___builtin_isless: \
+ case T___builtin_islessequal: \
+ case T___builtin_islessgreater: \
+ case T___builtin_isunordered: \
+ case T___builtin_offsetof: \
+ case T___builtin_va_arg: \
+ case T___builtin_va_copy: \
+ case T___builtin_va_start: \
+ case T___func__: \
+ case T___noop: \
+ case T__assume: \
+ case T_delete: \
+ case T_false: \
+ case T_sizeof: \
+ case T_throw: \
case T_true:
-/**
- * Allocate an AST node with given size and
- * initialize all fields with zero.
- */
-static void *allocate_ast_zero(size_t size)
-{
- void *res = allocate_ast(size);
- memset(res, 0, size);
- return res;
-}
-
-/**
- * Returns the size of an entity node.
- *
- * @param kind the entity kind
- */
-static size_t get_entity_struct_size(entity_kind_t kind)
-{
- static const size_t sizes[] = {
- [ENTITY_VARIABLE] = sizeof(variable_t),
- [ENTITY_PARAMETER] = sizeof(parameter_t),
- [ENTITY_COMPOUND_MEMBER] = sizeof(compound_member_t),
- [ENTITY_FUNCTION] = sizeof(function_t),
- [ENTITY_TYPEDEF] = sizeof(typedef_t),
- [ENTITY_STRUCT] = sizeof(compound_t),
- [ENTITY_UNION] = sizeof(compound_t),
- [ENTITY_ENUM] = sizeof(enum_t),
- [ENTITY_ENUM_VALUE] = sizeof(enum_value_t),
- [ENTITY_LABEL] = sizeof(label_t),
- [ENTITY_LOCAL_LABEL] = sizeof(label_t),
- [ENTITY_NAMESPACE] = sizeof(namespace_t)
- };
- assert(kind < lengthof(sizes));
- assert(sizes[kind] != 0);
- return sizes[kind];
-}
-
-/**
- * Allocate an entity of given kind and initialize all
- * fields with zero.
- *
- * @param kind the kind of the entity to allocate
- */
-static entity_t *allocate_entity_zero(entity_kind_t kind)
-{
- size_t size = get_entity_struct_size(kind);
- entity_t *entity = allocate_ast_zero(size);
- entity->kind = kind;
- return entity;
-}
-
/**
* Returns the size of a statement node.
*
[EXPR_INVALID] = sizeof(expression_base_t),
[EXPR_REFERENCE] = sizeof(reference_expression_t),
[EXPR_REFERENCE_ENUM_VALUE] = sizeof(reference_expression_t),
- [EXPR_CONST] = sizeof(const_expression_t),
- [EXPR_CHARACTER_CONSTANT] = sizeof(const_expression_t),
- [EXPR_WIDE_CHARACTER_CONSTANT] = sizeof(const_expression_t),
+ [EXPR_LITERAL_INTEGER] = sizeof(literal_expression_t),
+ [EXPR_LITERAL_INTEGER_OCTAL] = sizeof(literal_expression_t),
+ [EXPR_LITERAL_INTEGER_HEXADECIMAL]= sizeof(literal_expression_t),
+ [EXPR_LITERAL_FLOATINGPOINT] = sizeof(literal_expression_t),
+ [EXPR_LITERAL_FLOATINGPOINT_HEXADECIMAL] = sizeof(literal_expression_t),
+ [EXPR_LITERAL_CHARACTER] = sizeof(literal_expression_t),
+ [EXPR_LITERAL_WIDE_CHARACTER] = sizeof(literal_expression_t),
[EXPR_STRING_LITERAL] = sizeof(string_literal_expression_t),
- [EXPR_WIDE_STRING_LITERAL] = sizeof(wide_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),
return allocate_statement_zero(STATEMENT_EMPTY);
}
-/**
- * Returns the size of a type node.
- *
- * @param kind the type kind
- */
-static size_t get_type_struct_size(type_kind_t kind)
-{
- static const size_t sizes[] = {
- [TYPE_ATOMIC] = sizeof(atomic_type_t),
- [TYPE_COMPLEX] = sizeof(complex_type_t),
- [TYPE_IMAGINARY] = sizeof(imaginary_type_t),
- [TYPE_BITFIELD] = sizeof(bitfield_type_t),
- [TYPE_COMPOUND_STRUCT] = sizeof(compound_type_t),
- [TYPE_COMPOUND_UNION] = sizeof(compound_type_t),
- [TYPE_ENUM] = sizeof(enum_type_t),
- [TYPE_FUNCTION] = sizeof(function_type_t),
- [TYPE_POINTER] = sizeof(pointer_type_t),
- [TYPE_ARRAY] = sizeof(array_type_t),
- [TYPE_BUILTIN] = sizeof(builtin_type_t),
- [TYPE_TYPEDEF] = sizeof(typedef_type_t),
- [TYPE_TYPEOF] = sizeof(typeof_type_t),
- };
- assert(lengthof(sizes) == (int)TYPE_TYPEOF + 1);
- assert(kind <= TYPE_TYPEOF);
- assert(sizes[kind] != 0);
- return sizes[kind];
-}
-
-/**
- * Allocate a type node of given kind and initialize all
- * fields with zero.
- *
- * @param kind type kind to allocate
- */
-static type_t *allocate_type_zero(type_kind_t kind)
-{
- size_t size = get_type_struct_size(kind);
- type_t *res = obstack_alloc(type_obst, size);
- memset(res, 0, size);
- res->base.kind = kind;
-
- return res;
-}
-
static function_parameter_t *allocate_parameter(type_t *const type)
{
- function_parameter_t *const param = obstack_alloc(type_obst, sizeof(*param));
+ function_parameter_t *const param
+ = obstack_alloc(type_obst, sizeof(*param));
memset(param, 0, sizeof(*param));
param->type = type;
return param;
/**
* Expect the current token is the expected token.
* If not, generate an error, eat the current statement,
- * and goto the end_error label.
+ * and goto the error_label label.
*/
#define expect(expected, error_label) \
do { \
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 (entity->base.namespc == namespc)
}
}
- ARR_SHRINKLEN(*stack_ptr, (int) new_top);
+ ARR_SHRINKLEN(*stack_ptr, new_top);
}
/**
}
type_t *const type = skip_typeref(expression->base.type);
- return
- is_type_integer(type) &&
- is_constant_expression(expression) &&
- !fold_constant_to_bool(expression);
+ if (!is_type_integer(type))
+ return false;
+ switch (is_constant_expression(expression)) {
+ case EXPR_CLASS_ERROR: return true;
+ case EXPR_CLASS_CONSTANT: return !fold_constant_to_bool(expression);
+ default: return false;
+ }
}
/**
return ASSIGN_WARNING_POINTER_FROM_INT;
}
} else if ((is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) ||
- (is_type_atomic(type_left, ATOMIC_TYPE_BOOL)
- && is_type_pointer(type_right))) {
+ (is_type_atomic(type_left, ATOMIC_TYPE_BOOL)
+ && is_type_pointer(type_right))) {
return ASSIGN_SUCCESS;
} else if ((is_type_compound(type_left) && is_type_compound(type_right))
|| (is_type_builtin(type_left) && is_type_builtin(type_right))) {
static expression_t *parse_constant_expression(void)
{
- expression_t *result = parse_sub_expression(PREC_CONDITIONAL);
+ expression_t *result = parse_subexpression(PREC_CONDITIONAL);
- if (!is_constant_expression(result)) {
+ if (is_constant_expression(result) == EXPR_CLASS_VARIABLE) {
errorf(&result->base.source_position,
"expression '%E' is not constant", result);
}
static expression_t *parse_assignment_expression(void)
{
- return parse_sub_expression(PREC_ASSIGNMENT);
+ return parse_subexpression(PREC_ASSIGNMENT);
+}
+
+static void warn_string_concat(const source_position_t *pos)
+{
+ if (warning.traditional) {
+ warningf(pos, "traditional C rejects string constant concatenation");
+ }
}
static string_t parse_string_literals(void)
{
assert(token.type == T_STRING_LITERAL);
- string_t result = token.v.string;
+ string_t result = token.literal;
next_token();
while (token.type == T_STRING_LITERAL) {
- result = concat_strings(&result, &token.v.string);
+ warn_string_concat(&token.source_position);
+ result = concat_strings(&result, &token.literal);
next_token();
}
/* is it an identifier */
if (token.type == T_IDENTIFIER
&& (look_ahead(1)->type == ',' || look_ahead(1)->type == ')')) {
- symbol_t *symbol = token.v.symbol;
+ symbol_t *symbol = token.symbol;
argument->kind = ATTRIBUTE_ARGUMENT_SYMBOL;
argument->v.symbol = symbol;
next_token();
{
switch(token.type) {
case T_IDENTIFIER:
- return token.v.symbol;
+ return token.symbol;
case T_auto:
case T_char:
case T_double:
symbol_t *symbol = get_symbol_from_token();
if (symbol == NULL) {
parse_error_expected("while parsing attribute((", T_IDENTIFIER, NULL);
- goto end_error;
+ return NULL;
}
const char *name = symbol->string;
attribute->a.arguments = parse_attribute_arguments();
return attribute;
-
-end_error:
- return NULL;
}
static attribute_t *parse_attribute_gnu(void)
determine_lhs_ent(expr->va_starte.ap, lhs_ent);
return;
+ EXPR_LITERAL_CASES
case EXPR_UNKNOWN:
case EXPR_INVALID:
- case EXPR_CONST:
- case EXPR_CHARACTER_CONSTANT:
- case EXPR_WIDE_CHARACTER_CONSTANT:
case EXPR_STRING_LITERAL:
case EXPR_WIDE_STRING_LITERAL:
case EXPR_COMPOUND_LITERAL: // TODO init?
T_IDENTIFIER, NULL);
return NULL;
}
- designator->symbol = token.v.symbol;
+ designator->symbol = token.symbol;
next_token();
break;
default:
return NULL;
}
-static initializer_t *initializer_from_string(array_type_t *type,
+static initializer_t *initializer_from_string(array_type_t *const type,
const string_t *const string)
{
/* TODO: check len vs. size of array type */
}
static initializer_t *initializer_from_wide_string(array_type_t *const type,
- wide_string_t *const string)
+ const string_t *const string)
{
/* TODO: check len vs. size of array type */
(void) type;
type_t *type = skip_typeref(orig_type);
type_t *expr_type_orig = expression->base.type;
type_t *expr_type = skip_typeref(expr_type_orig);
+
if (is_type_array(type) && expr_type->kind == TYPE_POINTER) {
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.value);
- }
- break;
+ 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->wide_string.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;
+ }
- default:
- break;
+ default:
+ break;
}
}
}
*/
static bool is_initializer_constant(const expression_t *expression)
{
- return is_constant_expression(expression)
- || is_address_constant(expression);
+ return
+ is_constant_expression(expression) != EXPR_CLASS_VARIABLE ||
+ is_address_constant(expression) != EXPR_CLASS_VARIABLE;
}
/**
type_t *real_type = skip_typeref(iter->declaration.type);
if (real_type->kind == TYPE_BITFIELD) {
errorf(&designator->source_position,
- "offsetof designator '%Y' may not specify bitfield",
+ "offsetof designator '%Y' must not specify bitfield",
symbol);
goto failed;
}
long array_size = type->array.size;
if (index >= array_size) {
errorf(&designator->source_position,
- "designator [%E] (%d) exceeds array size %d",
- array_index, index, array_size);
+ "designator [%E] (%d) exceeds array size %d",
+ array_index, index, array_size);
}
}
}
/* GNU-style designator ("identifier: value") */
designator = allocate_ast_zero(sizeof(designator[0]));
designator->source_position = token.source_position;
- designator->symbol = token.v.symbol;
+ designator->symbol = token.symbol;
eat(T_IDENTIFIER);
eat(':');
return NULL;
}
+static expression_t *make_size_literal(size_t value)
+{
+ expression_t *literal = allocate_expression_zero(EXPR_LITERAL_INTEGER);
+ literal->base.type = type_size_t;
+
+ char buf[128];
+ snprintf(buf, sizeof(buf), "%u", (unsigned) value);
+ literal->literal.value = make_string(buf);
+
+ return literal;
+}
+
/**
* Parses an initializer. Parsers either a compound literal
* (env->declaration == NULL) or an initializer of a declaration.
static initializer_t *parse_initializer(parse_initializer_env_t *env)
{
type_t *type = skip_typeref(env->type);
- size_t max_index = 0xdeadbeaf; // TODO: Resolve this uninitialized variable problem
+ size_t max_index = 0;
initializer_t *result;
if (is_type_scalar(type)) {
internal_errorf(HERE, "invalid initializer type");
}
- expression_t *cnst = allocate_expression_zero(EXPR_CONST);
- cnst->base.type = type_size_t;
- cnst->conste.v.int_value = size;
-
type_t *new_type = duplicate_type(type);
- new_type->array.size_expression = cnst;
+ new_type->array.size_expression = make_size_literal(size);
new_type->array.size_constant = true;
new_type->array.has_implicit_size = true;
new_type->array.size = size;
entity_kind_tag_t const kind = is_struct ? ENTITY_STRUCT : ENTITY_UNION;
if (token.type == T_IDENTIFIER) {
/* the compound has a name, check if we have seen it already */
- symbol = token.v.symbol;
+ symbol = token.symbol;
next_token();
entity_t *entity = get_tag(symbol, kind);
entity_t *entity = allocate_entity_zero(ENTITY_ENUM_VALUE);
entity->enum_value.enum_type = enum_type;
- entity->base.symbol = token.v.symbol;
+ entity->base.namespc = NAMESPACE_NORMAL;
+ entity->base.symbol = token.symbol;
entity->base.source_position = token.source_position;
next_token();
eat(T_enum);
switch (token.type) {
case T_IDENTIFIER:
- symbol = token.v.symbol;
+ symbol = token.symbol;
next_token();
entity = get_tag(symbol, ENTITY_ENUM);
}
switch (token.type) {
case T_IDENTIFIER:
- if (is_typedef_symbol(token.v.symbol)) {
+ if (is_typedef_symbol(token.symbol)) {
+ TYPENAME_START
type = parse_typename();
} else {
+ default:
expression = parse_expression();
type = revert_automatic_type_conversion(expression);
}
break;
-
- TYPENAME_START
- type = parse_typename();
- break;
-
- default:
- expression = parse_expression();
- type = expression->base.type;
- break;
}
in_type_prop = old_type_prop;
in_gcc_extension = old_gcc_extension;
}
bool is_put;
- symbol_t *symbol = token.v.symbol;
+ symbol_t *symbol = token.symbol;
next_token();
if (strcmp(symbol->string, "put") == 0) {
is_put = true;
goto end_error;
}
if (is_put) {
- property->put_symbol = token.v.symbol;
+ property->put_symbol = token.symbol;
} else {
- property->get_symbol = token.v.symbol;
+ property->get_symbol = token.symbol;
}
next_token();
} while (next_if(','));
if (next_if(T_restrict)) {
kind = ATTRIBUTE_MS_RESTRICT;
} else if (token.type == T_IDENTIFIER) {
- const char *name = token.v.symbol->string;
+ const char *name = token.symbol->string;
next_token();
for (attribute_kind_t k = ATTRIBUTE_MS_FIRST; k <= ATTRIBUTE_MS_LAST;
++k) {
static entity_t *create_error_entity(symbol_t *symbol, entity_kind_tag_t kind)
{
entity_t *entity = allocate_entity_zero(kind);
+ entity->base.namespc = NAMESPACE_NORMAL;
entity->base.source_position = *HERE;
entity->base.symbol = symbol;
if (is_declaration(entity)) {
break;
char const* wrong;
- case STORAGE_CLASS_AUTO: wrong = "auto"; goto wrong_thread_stoarge_class;
- case STORAGE_CLASS_REGISTER: wrong = "register"; goto wrong_thread_stoarge_class;
- case STORAGE_CLASS_TYPEDEF: wrong = "typedef"; goto wrong_thread_stoarge_class;
-wrong_thread_stoarge_class:
+ case STORAGE_CLASS_AUTO: wrong = "auto"; goto wrong_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);
break;
}
}
}
- type_t *const typedef_type = get_typedef_type(token.v.symbol);
+ type_t *const typedef_type = get_typedef_type(token.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
errorf(HERE, "%K does not name a type", &token);
entity_t *entity =
- create_error_entity(token.v.symbol, ENTITY_TYPEDEF);
+ create_error_entity(token.symbol, ENTITY_TYPEDEF);
type = allocate_type_zero(TYPE_TYPEDEF);
type->typedeft.typedefe = &entity->typedefe;
entity_t *entity = allocate_entity_zero(ENTITY_PARAMETER);
entity->base.source_position = token.source_position;
entity->base.namespc = NAMESPACE_NORMAL;
- entity->base.symbol = token.v.symbol;
+ entity->base.symbol = token.symbol;
/* a K&R parameter has no type, yet */
next_token();
{
/* func(void) is not a parameter */
if (token.type == T_IDENTIFIER) {
- entity_t const *const entity = get_entity(token.v.symbol, NAMESPACE_NORMAL);
+ entity_t const *const entity = get_entity(token.symbol, NAMESPACE_NORMAL);
if (entity == NULL)
return true;
if (entity->kind != ENTITY_TYPEDEF)
int saved_comma_state = save_and_reset_anchor_state(',');
if (token.type == T_IDENTIFIER &&
- !is_typedef_symbol(token.v.symbol)) {
+ !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;
parsed_array_t array;
};
+static construct_type_t *allocate_declarator_zero(construct_type_kind_t const kind, size_t const size)
+{
+ construct_type_t *const cons = obstack_alloc(&temp_obst, size);
+ memset(cons, 0, size);
+ cons->kind = kind;
+ return cons;
+}
+
+/* §6.7.5.1 */
static construct_type_t *parse_pointer_declarator(void)
{
eat('*');
- parsed_pointer_t *pointer = obstack_alloc(&temp_obst, sizeof(pointer[0]));
- memset(pointer, 0, sizeof(pointer[0]));
- pointer->base.kind = CONSTRUCT_POINTER;
- pointer->type_qualifiers = parse_type_qualifiers();
- //pointer->base_variable = base_variable;
+ construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_POINTER, sizeof(parsed_pointer_t));
+ cons->pointer.type_qualifiers = parse_type_qualifiers();
+ //cons->pointer.base_variable = base_variable;
- return (construct_type_t*) pointer;
+ return cons;
}
+/* ISO/IEC 14882:1998(E) §8.3.2 */
static construct_type_t *parse_reference_declarator(void)
{
eat('&');
- construct_type_t *cons = obstack_alloc(&temp_obst, sizeof(cons->reference));
- parsed_reference_t *reference = &cons->reference;
- memset(reference, 0, sizeof(*reference));
- cons->kind = CONSTRUCT_REFERENCE;
+ if (!(c_mode & _CXX))
+ errorf(HERE, "references are only available for C++");
+
+ construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_REFERENCE, sizeof(parsed_reference_t));
return cons;
}
+/* §6.7.5.2 */
static construct_type_t *parse_array_declarator(void)
{
eat('[');
add_anchor_token(']');
- construct_type_t *cons = obstack_alloc(&temp_obst, sizeof(cons->array));
- parsed_array_t *array = &cons->array;
- memset(array, 0, sizeof(*array));
- cons->kind = CONSTRUCT_ARRAY;
+ construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_ARRAY, sizeof(parsed_array_t));
+ parsed_array_t *const array = &cons->array;
- if (next_if(T_static))
- array->is_static = true;
+ bool is_static = next_if(T_static);
type_qualifiers_t type_qualifiers = parse_type_qualifiers();
- if (type_qualifiers != 0 && next_if(T_static))
- array->is_static = true;
+
+ if (!is_static)
+ is_static = next_if(T_static);
+
array->type_qualifiers = type_qualifiers;
+ array->is_static = is_static;
+ expression_t *size = NULL;
if (token.type == '*' && look_ahead(1)->type == ']') {
array->is_variable = true;
next_token();
} else if (token.type != ']') {
- expression_t *const size = parse_assignment_expression();
+ size = parse_assignment_expression();
/* §6.7.5.2:1 Array size must have integer type */
type_t *const orig_type = size->base.type;
mark_vars_read(size, NULL);
}
+ if (is_static && size == NULL)
+ errorf(HERE, "static array parameters require a size");
+
rem_anchor_token(']');
expect(']', end_error);
return cons;
}
+/* §6.7.5.3 */
static construct_type_t *parse_function_declarator(scope_t *scope)
{
type_t *type = allocate_type_zero(TYPE_FUNCTION);
parse_parameters(ftype, scope);
- construct_type_t *cons = obstack_alloc(&temp_obst, sizeof(cons->function));
- construct_function_type_t *function = &cons->function;
- memset(function, 0, sizeof(*function));
- cons->kind = CONSTRUCT_FUNCTION;
- function->function_type = type;
+ construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_FUNCTION, sizeof(construct_function_type_t));
+ cons->function.function_type = type;
return cons;
}
attribute_t *attributes;
} parse_declarator_env_t;
+/* §6.7.5 */
static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env)
{
/* construct a single linked list of construct_type_t's which describe
//variable_t *based = NULL; /* MS __based extension */
switch (token.type) {
case '&':
- if (!(c_mode & _CXX))
- errorf(HERE, "references are only available for C++");
type = parse_reference_declarator();
break;
if (env->must_be_abstract) {
errorf(HERE, "no identifier expected in typename");
} else {
- env->symbol = token.v.symbol;
+ env->symbol = token.symbol;
env->source_position = token.source_position;
}
next_token();
}
rem_anchor_token(')');
expect(')', end_error);
+ } else if (!env->may_be_abstract) {
+ errorf(HERE, "declarator must have a name");
+ goto error_out;
}
break;
default:
if (env->may_be_abstract)
break;
parse_error_expected("while parsing declarator", T_IDENTIFIER, '(', NULL);
+error_out:
eat_until_anchor();
return NULL;
}
array_type->array.size_expression = size_expression;
if (size_expression != NULL) {
- if (is_constant_expression(size_expression)) {
- long const size
- = fold_constant_to_int(size_expression);
- array_type->array.size = size;
- array_type->array.size_constant = true;
- /* §6.7.5.2:1 If the expression is a constant expression, it shall
- * have a value greater than zero. */
- if (size <= 0) {
- if (size < 0 || !GNU_MODE) {
- errorf(&size_expression->base.source_position,
- "size of array must be greater than zero");
- } else if (warning.other) {
- warningf(&size_expression->base.source_position,
- "zero length arrays are a GCC extension");
+ switch (is_constant_expression(size_expression)) {
+ case EXPR_CLASS_CONSTANT: {
+ long const size = fold_constant_to_int(size_expression);
+ array_type->array.size = size;
+ array_type->array.size_constant = true;
+ /* §6.7.5.2:1 If the expression is a constant expression, it shall
+ * have a value greater than zero. */
+ if (size <= 0) {
+ if (size < 0 || !GNU_MODE) {
+ errorf(&size_expression->base.source_position,
+ "size of array must be greater than zero");
+ } else if (warning.other) {
+ warningf(&size_expression->base.source_position,
+ "zero length arrays are a GCC extension");
+ }
}
+ break;
}
- } else {
- array_type->array.is_vla = true;
+
+ case EXPR_CLASS_VARIABLE:
+ array_type->array.is_vla = true;
+ break;
+
+ case EXPR_CLASS_ERROR:
+ break;
}
}
entity_t *entity;
if (specifiers->storage_class == STORAGE_CLASS_TYPEDEF) {
entity = allocate_entity_zero(ENTITY_TYPEDEF);
+ entity->base.namespc = NAMESPACE_NORMAL;
entity->base.symbol = env.symbol;
entity->base.source_position = env.source_position;
entity->typedefe.type = orig_type;
bool in_function_scope = current_function != NULL;
if (specifiers->thread_local || (
- specifiers->storage_class != STORAGE_CLASS_EXTERN &&
- specifiers->storage_class != STORAGE_CLASS_NONE &&
- (in_function_scope || specifiers->storage_class != STORAGE_CLASS_STATIC)
- )) {
+ specifiers->storage_class != STORAGE_CLASS_EXTERN &&
+ specifiers->storage_class != STORAGE_CLASS_NONE &&
+ (in_function_scope || specifiers->storage_class != STORAGE_CLASS_STATIC)
+ )) {
errorf(&env.source_position,
"invalid storage class for function '%Y'", env.symbol);
}
static bool is_error_entity(entity_t *const ent)
{
if (is_declaration(ent)) {
- return is_type_valid(skip_typeref(ent->declaration.type));
+ return !is_type_valid(skip_typeref(ent->declaration.type));
} else if (ent->kind == ENTITY_TYPEDEF) {
- return is_type_valid(skip_typeref(ent->typedefe.type));
+ return !is_type_valid(skip_typeref(ent->typedefe.type));
}
return false;
}
* record entities for the NAMESPACE_NORMAL, and produce error messages/warnings
* for various problems that occur for multiple definitions
*/
-static entity_t *record_entity(entity_t *entity, const bool is_definition)
+entity_t *record_entity(entity_t *entity, const bool is_definition)
{
const symbol_t *const symbol = entity->base.symbol;
const namespace_tag_t namespc = (namespace_tag_t)entity->base.namespc;
TYPE_QUALIFIERS
return true;
case T_IDENTIFIER:
- return is_typedef_symbol(token->v.symbol);
+ return is_typedef_symbol(token->symbol);
case T___extension__:
STORAGE_CLASSES
static int determine_truth(expression_t const* const cond)
{
return
- !is_constant_expression(cond) ? 0 :
- fold_constant_to_bool(cond) ? 1 :
+ is_constant_expression(cond) != EXPR_CLASS_CONSTANT ? 0 :
+ fold_constant_to_bool(cond) ? 1 :
-1;
}
case EXPR_REFERENCE:
case EXPR_REFERENCE_ENUM_VALUE:
- case EXPR_CONST:
- case EXPR_CHARACTER_CONSTANT:
- case EXPR_WIDE_CHARACTER_CONSTANT:
+ EXPR_LITERAL_CASES
case EXPR_STRING_LITERAL:
case EXPR_WIDE_STRING_LITERAL:
case EXPR_COMPOUND_LITERAL: // TODO descend into initialisers
if (!expression_returns(expr))
return;
- if (is_constant_expression(expr)) {
+ if (is_constant_expression(expr) == EXPR_CLASS_CONSTANT) {
long const val = fold_constant_to_int(expr);
case_label_statement_t * defaults = NULL;
for (case_label_statement_t *i = switchs->first_case; i != NULL; i = i->next) {
bit_size = get_type_size(base_type) * 8;
}
- if (is_constant_expression(size)) {
+ 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;
/* TODO: improve error message, user does probably not know what a
* storage class is...
*/
- errorf(HERE, "typename may not have a storage class");
+ errorf(HERE, "typename must not have a storage class");
}
type_t *result = parse_abstract_declarator(specifiers.type);
return create_invalid_expression();
}
+static type_t *get_string_type(void)
+{
+ return warning.write_strings ? type_const_char_ptr : type_char_ptr;
+}
+
+static type_t *get_wide_string_type(void)
+{
+ return warning.write_strings ? type_const_wchar_t_ptr : type_wchar_t_ptr;
+}
+
/**
* Parse a string constant.
*/
-static expression_t *parse_string_const(void)
+static expression_t *parse_string_literal(void)
{
- wide_string_t wres;
- if (token.type == T_STRING_LITERAL) {
- string_t res = token.v.string;
+ 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();
- while (token.type == T_STRING_LITERAL) {
- res = concat_strings(&res, &token.v.string);
- next_token();
- }
- if (token.type != T_WIDE_STRING_LITERAL) {
- expression_t *const cnst = allocate_expression_zero(EXPR_STRING_LITERAL);
- /* note: that we use type_char_ptr here, which is already the
- * automatic converted type. revert_automatic_type_conversion
- * will construct the array type */
- cnst->base.type = warning.write_strings ? type_const_char_ptr : type_char_ptr;
- cnst->string.value = res;
- return cnst;
- }
+ is_wide |= token.type == T_WIDE_STRING_LITERAL;
+ }
- wres = concat_string_wide_string(&res, &token.v.wide_string);
+ expression_t *literal;
+ if (is_wide) {
+ literal = allocate_expression_zero(EXPR_WIDE_STRING_LITERAL);
+ literal->base.type = get_wide_string_type();
} else {
- wres = token.v.wide_string;
+ literal = allocate_expression_zero(EXPR_STRING_LITERAL);
+ literal->base.type = get_string_type();
}
+ literal->base.source_position = begin;
+ literal->literal.value = res;
+
+ return literal;
+}
+
+/**
+ * Parse a boolean constant.
+ */
+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;
+
next_token();
+ return literal;
+}
- for (;;) {
- switch (token.type) {
- case T_WIDE_STRING_LITERAL:
- wres = concat_wide_strings(&wres, &token.v.wide_string);
- break;
+static void warn_traditional_suffix(void)
+{
+ if (!warning.traditional)
+ return;
+ warningf(&token.source_position, "traditional C rejects the '%Y' suffix",
+ token.symbol);
+}
- case T_STRING_LITERAL:
- wres = concat_wide_string_string(&wres, &token.v.string);
- break;
+static void check_integer_suffix(void)
+{
+ symbol_t *suffix = token.symbol;
+ if (suffix == NULL)
+ return;
- default: {
- expression_t *const cnst = allocate_expression_zero(EXPR_WIDE_STRING_LITERAL);
- cnst->base.type = warning.write_strings ? type_const_wchar_t_ptr : type_wchar_t_ptr;
- cnst->wide_string.value = wres;
- return cnst;
+ bool not_traditional = false;
+ const char *c = suffix->string;
+ if (*c == 'l' || *c == 'L') {
+ ++c;
+ if (*c == *(c-1)) {
+ not_traditional = true;
+ ++c;
+ if (*c == 'u' || *c == 'U') {
+ ++c;
+ }
+ } else if (*c == 'u' || *c == 'U') {
+ not_traditional = true;
+ ++c;
+ }
+ } else if (*c == 'u' || *c == 'U') {
+ not_traditional = true;
+ ++c;
+ if (*c == 'l' || *c == 'L') {
+ ++c;
+ if (*c == *(c-1)) {
+ ++c;
}
}
- next_token();
+ }
+ if (*c != '\0') {
+ errorf(&token.source_position,
+ "invalid suffix '%s' on integer constant", suffix->string);
+ } else if (not_traditional) {
+ warn_traditional_suffix();
}
}
-/**
- * Parse a boolean constant.
- */
-static expression_t *parse_bool_const(bool value)
+static type_t *check_floatingpoint_suffix(void)
{
- expression_t *cnst = allocate_expression_zero(EXPR_CONST);
- cnst->base.type = type_bool;
- cnst->conste.v.int_value = value;
+ symbol_t *suffix = token.symbol;
+ type_t *type = type_double;
+ if (suffix == NULL)
+ return type;
- next_token();
+ bool not_traditional = false;
+ const char *c = suffix->string;
+ 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.source_position,
+ "invalid suffix '%s' on floatingpoint constant", suffix->string);
+ } else if (not_traditional) {
+ warn_traditional_suffix();
+ }
- return cnst;
+ return type;
}
/**
* Parse an integer constant.
*/
-static expression_t *parse_int_const(void)
+static expression_t *parse_number_literal(void)
{
- expression_t *cnst = allocate_expression_zero(EXPR_CONST);
- cnst->base.type = token.datatype;
- cnst->conste.v.int_value = token.v.intvalue;
+ expression_kind_t kind;
+ type_t *type;
+ switch (token.type) {
+ 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;
next_token();
- return cnst;
+ /* 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;
}
/**
*/
static expression_t *parse_character_constant(void)
{
- expression_t *cnst = allocate_expression_zero(EXPR_CHARACTER_CONSTANT);
- cnst->base.type = token.datatype;
- cnst->conste.v.character = token.v.string;
+ 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;
- if (cnst->conste.v.character.size != 1) {
- if (!GNU_MODE) {
+ 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 if (warning.multichar) {
+ literal->base.type = type_int;
warningf(HERE, "multi-character character constant");
}
}
- next_token();
- return cnst;
+ next_token();
+ return literal;
}
/**
*/
static expression_t *parse_wide_character_constant(void)
{
- expression_t *cnst = allocate_expression_zero(EXPR_WIDE_CHARACTER_CONSTANT);
- cnst->base.type = token.datatype;
- cnst->conste.v.wide_character = token.v.wide_string;
+ 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;
- if (cnst->conste.v.wide_character.size != 1) {
- if (!GNU_MODE) {
- errorf(HERE, "more than 1 character in character constant");
- } else if (warning.multichar) {
- warningf(HERE, "multi-character character constant");
- }
+ size_t len = wstrlen(&literal->literal.value);
+ if (len != 1) {
+ warningf(HERE, "multi-character character constant");
}
- next_token();
-
- return cnst;
-}
-
-/**
- * Parse a float constant.
- */
-static expression_t *parse_float_const(void)
-{
- expression_t *cnst = allocate_expression_zero(EXPR_CONST);
- cnst->base.type = token.datatype;
- cnst->conste.v.float_value = token.v.floatvalue;
next_token();
-
- return cnst;
+ return literal;
}
static entity_t *create_implicit_function(symbol_t *symbol,
entity->declaration.declared_storage_class = STORAGE_CLASS_EXTERN;
entity->declaration.type = type;
entity->declaration.implicit = true;
+ entity->base.namespc = NAMESPACE_NORMAL;
entity->base.symbol = symbol;
entity->base.source_position = *source_position;
return entity;
}
-/**
- * Creates a return_type (func)(argument_type) function type if not
- * already exists.
- */
-static type_t *make_function_2_type(type_t *return_type, type_t *argument_type1,
- type_t *argument_type2)
-{
- function_parameter_t *const parameter2 = allocate_parameter(argument_type2);
- function_parameter_t *const parameter1 = allocate_parameter(argument_type1);
- parameter1->next = parameter2;
-
- type_t *type = allocate_type_zero(TYPE_FUNCTION);
- type->function.return_type = return_type;
- type->function.parameters = parameter1;
-
- return identify_new_type(type);
-}
-
-/**
- * Creates a return_type (func)(argument_type) function type if not
- * already exists.
- *
- * @param return_type the return type
- * @param argument_type the argument type
- */
-static type_t *make_function_1_type(type_t *return_type, type_t *argument_type)
-{
- function_parameter_t *const parameter = allocate_parameter(argument_type);
-
- type_t *type = allocate_type_zero(TYPE_FUNCTION);
- type->function.return_type = return_type;
- type->function.parameters = parameter;
-
- return identify_new_type(type);
-}
-
-/**
- * Creates a return_type (func)(argument_type, ...) function type if not
- * already exists.
- *
- * @param return_type the return type
- * @param argument_type the argument type
- */
-static type_t *make_function_1_type_variadic(type_t *return_type, type_t *argument_type)
-{
- function_parameter_t *const parameter = allocate_parameter(argument_type);
-
- type_t *type = allocate_type_zero(TYPE_FUNCTION);
- type->function.return_type = return_type;
- type->function.parameters = parameter;
- type->function.variadic = true;
-
- return identify_new_type(type);
-}
-
-/**
- * Creates a return_type (func)(void) function type if not
- * already exists.
- *
- * @param return_type the return type
- */
-static type_t *make_function_0_type(type_t *return_type)
-{
- type_t *type = allocate_type_zero(TYPE_FUNCTION);
- type->function.return_type = return_type;
- type->function.parameters = NULL;
-
- return identify_new_type(type);
-}
-
-/**
- * Creates a NO_RETURN return_type (func)(void) function type if not
- * already exists.
- *
- * @param return_type the return type
- */
-static type_t *make_function_0_type_noreturn(type_t *return_type)
-{
- type_t *type = allocate_type_zero(TYPE_FUNCTION);
- type->function.return_type = return_type;
- type->function.parameters = NULL;
- type->function.modifiers |= DM_NORETURN;
- return identify_new_type(type);
-}
-
/**
* Performs automatic type cast as described in §6.3.2.1.
*
type_t *revert_automatic_type_conversion(const expression_t *expression)
{
switch (expression->kind) {
- case EXPR_REFERENCE: {
- entity_t *entity = expression->reference.entity;
- if (is_declaration(entity)) {
- return entity->declaration.type;
- } else if (entity->kind == ENTITY_ENUM_VALUE) {
- return entity->enum_value.enum_type;
- } else {
- panic("no declaration or enum in reference");
- }
+ case EXPR_REFERENCE: {
+ entity_t *entity = expression->reference.entity;
+ if (is_declaration(entity)) {
+ return entity->declaration.type;
+ } else if (entity->kind == ENTITY_ENUM_VALUE) {
+ return entity->enum_value.enum_type;
+ } else {
+ panic("no declaration or enum in reference");
}
+ }
- case EXPR_SELECT: {
- 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);
- }
+ case EXPR_SELECT: {
+ 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);
+ }
- case EXPR_UNARY_DEREFERENCE: {
- const expression_t *const value = expression->unary.value;
- type_t *const type = skip_typeref(value->base.type);
- if (!is_type_pointer(type))
- return type_error_type;
- return type->pointer.points_to;
- }
+ case EXPR_UNARY_DEREFERENCE: {
+ const expression_t *const value = expression->unary.value;
+ type_t *const type = skip_typeref(value->base.type);
+ if (!is_type_pointer(type))
+ return type_error_type;
+ return type->pointer.points_to;
+ }
- case EXPR_ARRAY_ACCESS: {
- const expression_t *array_ref = expression->array_access.array_ref;
- type_t *type_left = skip_typeref(array_ref->base.type);
- if (!is_type_pointer(type_left))
- return type_error_type;
- return type_left->pointer.points_to;
- }
+ case EXPR_ARRAY_ACCESS: {
+ const expression_t *array_ref = expression->array_access.array_ref;
+ type_t *type_left = skip_typeref(array_ref->base.type);
+ if (!is_type_pointer(type_left))
+ return type_error_type;
+ return type_left->pointer.points_to;
+ }
- case EXPR_STRING_LITERAL: {
- size_t size = expression->string.value.size;
- return make_array_type(type_char, size, TYPE_QUALIFIER_NONE);
- }
+ 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 = expression->wide_string.value.size;
- return make_array_type(type_wchar_t, 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);
+ }
- case EXPR_COMPOUND_LITERAL:
- return expression->compound_literal.type;
+ case EXPR_COMPOUND_LITERAL:
+ return expression->compound_literal.type;
- default:
- return expression->base.type;
+ default:
+ break;
}
+ return expression->base.type;
}
/**
parse_error_expected("while parsing identifier", T_IDENTIFIER, NULL);
return create_error_entity(sym_anonymous, ENTITY_VARIABLE);
}
- symbol = token.v.symbol;
+ symbol = token.symbol;
pos = *HERE;
next_token();
expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST);
cast->base.source_position = source_position;
- expression_t *value = parse_sub_expression(PREC_CAST);
+ expression_t *value = parse_subexpression(PREC_CAST);
cast->base.type = type;
cast->unary.value = value;
TYPE_SPECIFIERS
return parse_cast();
case T_IDENTIFIER:
- if (is_typedef_symbol(token.v.symbol)) {
+ if (is_typedef_symbol(token.symbol)) {
return parse_cast();
}
}
T_IDENTIFIER, NULL);
return NULL;
}
- result->symbol = token.v.symbol;
+ result->symbol = token.symbol;
next_token();
designator_t *last_designator = result;
}
designator_t *designator = allocate_ast_zero(sizeof(result[0]));
designator->source_position = *HERE;
- designator->symbol = token.v.symbol;
+ designator->symbol = token.symbol;
next_token();
last_designator->next = designator;
parse_error_expected("while parsing label address", T_IDENTIFIER, NULL);
goto end_error;
}
- symbol_t *symbol = token.v.symbol;
+ symbol_t *symbol = token.symbol;
next_token();
label_t *label = get_label(symbol);
static expression_t *parse_noop_expression(void)
{
/* the result is a (int)0 */
- expression_t *cnst = allocate_expression_zero(EXPR_CONST);
- cnst->base.type = type_int;
- cnst->conste.v.int_value = 0;
- cnst->conste.is_ms_noop = true;
+ 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;
eat(T___noop);
expect(')', end_error);
end_error:
- return cnst;
+ return literal;
}
/**
static expression_t *parse_primary_expression(void)
{
switch (token.type) {
- case T_false: return parse_bool_const(false);
- case T_true: return parse_bool_const(true);
- case T_INTEGER: return parse_int_const();
- case T_CHARACTER_CONSTANT: return parse_character_constant();
- case T_WIDE_CHARACTER_CONSTANT: return parse_wide_character_constant();
- case T_FLOATINGPOINT: return parse_float_const();
- case T_STRING_LITERAL:
- case T_WIDE_STRING_LITERAL: return parse_string_const();
- 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___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___builtin_va_copy: return parse_va_copy();
- case T___builtin_isgreater:
- case T___builtin_isgreaterequal:
- case T___builtin_isless:
- case T___builtin_islessequal:
- case T___builtin_islessgreater:
- case T___builtin_isunordered: return parse_compare_builtin();
- case T___builtin_constant_p: return parse_builtin_constant();
- case T___builtin_types_compatible_p: return parse_builtin_types_compatible();
- case T__assume: return parse_assume();
- case T_ANDAND:
- if (GNU_MODE)
- return parse_label_address();
- break;
+ 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_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___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___builtin_va_copy: return parse_va_copy();
+ case T___builtin_isgreater:
+ case T___builtin_isgreaterequal:
+ case T___builtin_isless:
+ case T___builtin_islessequal:
+ case T___builtin_islessgreater:
+ case T___builtin_isunordered: return parse_compare_builtin();
+ case T___builtin_constant_p: return parse_builtin_constant();
+ case T___builtin_types_compatible_p: return parse_builtin_types_compatible();
+ case T__assume: return parse_assume();
+ case T_ANDAND:
+ if (GNU_MODE)
+ return parse_label_address();
+ break;
- case '(': return parse_parenthesized_expression();
- case T___noop: return parse_noop_expression();
+ case '(': return parse_parenthesized_expression();
+ case T___noop: return parse_noop_expression();
- /* Gracefully handle type names while parsing expressions. */
- case T_COLONCOLON:
+ /* Gracefully handle type names while parsing expressions. */
+ case T_COLONCOLON:
+ return parse_reference();
+ case T_IDENTIFIER:
+ if (!is_typedef_symbol(token.symbol)) {
return parse_reference();
- case T_IDENTIFIER:
- if (!is_typedef_symbol(token.v.symbol)) {
- return parse_reference();
- }
- /* FALLTHROUGH */
- TYPENAME_START {
- source_position_t const pos = *HERE;
- type_t const *const type = parse_typename();
- errorf(&pos, "encountered type '%T' while parsing expression", type);
- return create_invalid_expression();
}
+ /* FALLTHROUGH */
+ TYPENAME_START {
+ source_position_t const pos = *HERE;
+ type_t const *const type = parse_typename();
+ errorf(&pos, "encountered type '%T' while parsing expression", type);
+ return create_invalid_expression();
+ }
}
errorf(HERE, "unexpected token %K, expected an expression", &token);
+ eat_until_anchor();
return create_invalid_expression();
}
goto typeprop_expression;
}
} else {
- expression = parse_sub_expression(PREC_UNARY);
+ expression = parse_subexpression(PREC_UNARY);
typeprop_expression:
tp_expression->typeprop.tp_expression = expression;
tp_expression->typeprop.type = orig_type;
type_t const* const type = skip_typeref(orig_type);
- char const* const wrong_type =
- GNU_MODE && is_type_atomic(type, ATOMIC_TYPE_VOID) ? NULL :
- is_type_incomplete(type) ? "incomplete" :
- type->kind == TYPE_FUNCTION ? "function designator" :
- type->kind == TYPE_BITFIELD ? "bitfield" :
- NULL;
+ char const* wrong_type = NULL;
+ if (is_type_incomplete(type)) {
+ if (!is_type_atomic(type, ATOMIC_TYPE_VOID) || !GNU_MODE)
+ wrong_type = "incomplete";
+ } else if (type->kind == TYPE_FUNCTION) {
+ if (GNU_MODE) {
+ /* function types are allowed (and return 1) */
+ if (warning.other) {
+ char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
+ warningf(&tp_expression->base.source_position,
+ "%s expression with function argument returns invalid result", what);
+ }
+ } 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";
errorf(&tp_expression->base.source_position,
{
assert(token.type == '.' || token.type == T_MINUSGREATER);
bool select_left_arrow = (token.type == 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.v.symbol;
+ symbol_t *symbol = token.symbol;
next_token();
type_t *const orig_type = addr->base.type;
bool saw_error = false;
if (is_type_pointer(type)) {
if (!select_left_arrow) {
- errorf(HERE,
+ errorf(&pos,
"request for member '%Y' in something not a struct or union, but '%T'",
symbol, orig_type);
saw_error = true;
type_left = skip_typeref(type->pointer.points_to);
} else {
if (select_left_arrow && is_type_valid(type)) {
- errorf(HERE, "left hand side of '->' is not a pointer, but '%T'", orig_type);
+ errorf(&pos, "left hand side of '->' is not a pointer, but '%T'", orig_type);
saw_error = true;
}
type_left = type;
type_left->kind != TYPE_COMPOUND_UNION) {
if (is_type_valid(type_left) && !saw_error) {
- errorf(HERE,
+ errorf(&pos,
"request for member '%Y' in something not a struct or union, but '%T'",
symbol, type_left);
}
compound_t *compound = type_left->compound.compound;
if (!compound->complete) {
- errorf(HERE, "request for member '%Y' in incomplete type '%T'",
+ errorf(&pos, "request for member '%Y' in incomplete type '%T'",
symbol, type_left);
return create_invalid_expression();
}
type_qualifiers_t qualifiers = type_left->base.qualifiers;
- expression_t *result
- = find_create_select(HERE, addr, qualifiers, compound, symbol);
+ expression_t *result =
+ find_create_select(&pos, addr, qualifiers, compound, symbol);
if (result == NULL) {
- errorf(HERE, "'%T' has no member named '%Y'", orig_type, symbol);
+ errorf(&pos, "'%T' has no member named '%Y'", orig_type, symbol);
return create_invalid_expression();
}
/* argument must be constant */
call_argument_t *argument = call->arguments;
- if (! is_constant_expression(argument->expression)) {
+ 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_prefetch: {
+ 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",
+ call->function->reference.entity->base.symbol);
+ }
+ break;
+ case bk_gnu_builtin_prefetch:
/* second and third argument must be constant if existent */
+ if (call->arguments == NULL)
+ break;
call_argument_t *rw = call->arguments->next;
call_argument_t *locality = NULL;
if (rw != NULL) {
- if (! is_constant_expression(rw->expression)) {
+ 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);
locality = rw->next;
}
if (locality != NULL) {
- if (! is_constant_expression(locality->expression)) {
+ 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);
locality = rw->next;
}
break;
- }
default:
break;
}
/* do default promotion for other arguments */
for (; argument != NULL; argument = argument->next) {
type_t *type = argument->expression->base.type;
+ if (!is_type_object(skip_typeref(type))) {
+ errorf(&argument->expression->base.source_position,
+ "call argument '%E' must not be void", argument->expression);
+ }
type = get_default_promoted_type(type);
expect(':', end_error);
end_error:;
expression_t *false_expression =
- parse_sub_expression(c_mode & _CXX ? PREC_ASSIGNMENT : PREC_CONDITIONAL);
+ parse_subexpression(c_mode & _CXX ? PREC_ASSIGNMENT : PREC_CONDITIONAL);
type_t *const orig_true_type = true_expression->base.type;
type_t *const orig_false_type = false_expression->base.type;
} else if (is_type_arithmetic(true_type)
&& is_type_arithmetic(false_type)) {
result_type = semantic_arithmetic(true_type, false_type);
-
- true_expression = create_implicit_cast(true_expression, result_type);
- false_expression = create_implicit_cast(false_expression, result_type);
-
- conditional->true_expression = true_expression;
- conditional->false_expression = false_expression;
- conditional->base.type = result_type;
} else if (same_compound_type(true_type, false_type)) {
/* just take 1 of the 2 types */
result_type = true_type;
result_type = pointer_type;
} else {
if (is_type_valid(other_type)) {
- type_error_incompatible("while parsing conditional",
+ type_error_incompatible("while parsing conditional",
&expression->base.source_position, true_type, false_type);
}
result_type = type_error_type;
bool old_gcc_extension = in_gcc_extension;
in_gcc_extension = true;
- expression_t *expression = parse_sub_expression(PREC_UNARY);
+ expression_t *expression = parse_subexpression(PREC_UNARY);
in_gcc_extension = old_gcc_extension;
return expression;
}
end_error:;
}
- expression_t *const value = parse_sub_expression(PREC_CAST);
+ expression_t *const value = parse_subexpression(PREC_CAST);
result->unary.value = value;
type_t *const type = skip_typeref(value->base.type);
expression_t *unary_expression \
= allocate_expression_zero(unexpression_type); \
eat(token_type); \
- unary_expression->unary.value = parse_sub_expression(PREC_UNARY); \
+ unary_expression->unary.value = parse_subexpression(PREC_UNARY); \
\
sfunc(&unary_expression->unary); \
\
expression_t const *const right = expression->right;
/* The type of the right operand can be different for /= */
- if (is_type_integer(right->base.type) &&
- is_constant_expression(right) &&
+ if (is_type_integer(right->base.type) &&
+ is_constant_expression(right) == EXPR_CLASS_CONSTANT &&
!fold_constant_to_bool(right)) {
warningf(&expression->base.source_position, "division by zero");
}
type_left = promote_integer(type_left);
- if (is_constant_expression(right)) {
+ if (is_constant_expression(right) == EXPR_CLASS_CONSTANT) {
long count = fold_constant_to_int(right);
if (count < 0) {
warningf(&right->base.source_position,
expr = expr->unary.value;
}
- if (expr->kind == EXPR_STRING_LITERAL ||
- expr->kind == EXPR_WIDE_STRING_LITERAL) {
+ if (expr->kind == EXPR_STRING_LITERAL
+ || expr->kind == EXPR_WIDE_STRING_LITERAL) {
warningf(&expr->base.source_position,
"comparison with string literal results in unspecified behaviour");
}
static bool maybe_negative(expression_t const *const expr)
{
- return
- !is_constant_expression(expr) ||
- fold_constant_to_int(expr) < 0;
+ switch (is_constant_expression(expr)) {
+ case EXPR_CLASS_ERROR: return false;
+ case EXPR_CLASS_CONSTANT: return fold_constant_to_int(expr) < 0;
+ default: return true;
+ }
}
/**
case EXPR_INVALID: return true; /* do NOT warn */
case EXPR_REFERENCE: return false;
case EXPR_REFERENCE_ENUM_VALUE: return false;
+ case EXPR_LABEL_ADDRESS: return false;
+
/* suppress the warning for microsoft __noop operations */
- case EXPR_CONST: return expr->conste.is_ms_noop;
- case EXPR_CHARACTER_CONSTANT: return false;
- case EXPR_WIDE_CHARACTER_CONSTANT: return false;
+ 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_LABEL_ADDRESS: return false;
case EXPR_CALL: {
const call_expression_t *const call = &expr->call;
binexpr->binary.left = left; \
eat(token_type); \
\
- expression_t *right = parse_sub_expression(prec_r); \
+ expression_t *right = parse_subexpression(prec_r); \
\
binexpr->binary.right = right; \
sfunc(&binexpr->binary); \
CREATE_BINEXPR_PARSER(',', EXPR_BINARY_COMMA, PREC_ASSIGNMENT, semantic_comma)
-static expression_t *parse_sub_expression(precedence_t precedence)
+static expression_t *parse_subexpression(precedence_t precedence)
{
if (token.type < 0) {
return expected_expression_error();
*/
static expression_t *parse_expression(void)
{
- return parse_sub_expression(PREC_EXPRESSION);
+ return parse_subexpression(PREC_EXPRESSION);
}
/**
T_IDENTIFIER, NULL);
return NULL;
}
- argument->symbol = token.v.symbol;
+ argument->symbol = token.symbol;
expect(']', end_error);
}
"asm output argument is not an lvalue");
}
- if (argument->constraints.begin[0] == '+')
+ if (argument->constraints.begin[0] == '=')
+ determine_lhs_ent(expression, NULL);
+ else
mark_vars_read(expression, NULL);
} else {
mark_vars_read(expression, NULL);
expect('(', end_error);
add_anchor_token(')');
- 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();
+ add_anchor_token(':');
if (!next_if(':')) {
rem_anchor_token(':');
goto end_of_asm;
return create_invalid_statement();
}
+static statement_t *parse_label_inner_statement(char const *const label, bool const eat_empty_stmt)
+{
+ statement_t *inner_stmt;
+ switch (token.type) {
+ case '}':
+ errorf(HERE, "%s at end of compound statement", label);
+ inner_stmt = create_invalid_statement();
+ break;
+
+ case ';':
+ if (eat_empty_stmt) {
+ /* Eat an empty statement here, to avoid the warning about an empty
+ * statement after a label. label:; is commonly used to have a label
+ * before a closing brace. */
+ inner_stmt = create_empty_statement();
+ next_token();
+ break;
+ }
+ /* FALLTHROUGH */
+
+ default:
+ inner_stmt = parse_statement();
+ if (inner_stmt->kind == STATEMENT_DECLARATION) {
+ errorf(&inner_stmt->base.source_position, "declaration after %s", label);
+ }
+ break;
+ }
+ return inner_stmt;
+}
+
/**
* Parse a case statement.
*/
expression_t *const expression = parse_expression();
statement->case_label.expression = expression;
- if (!is_constant_expression(expression)) {
- /* This check does not prevent the error message in all cases of an
- * prior error while parsing the expression. At least it catches the
- * common case of a mistyped enum entry. */
- if (is_type_valid(skip_typeref(expression->base.type))) {
+ expression_classification_t const expr_class = is_constant_expression(expression);
+ if (expr_class != EXPR_CLASS_CONSTANT) {
+ if (expr_class != EXPR_CLASS_ERROR) {
errorf(pos, "case label does not reduce to an integer constant");
}
statement->case_label.is_bad = true;
if (next_if(T_DOTDOTDOT)) {
expression_t *const end_range = parse_expression();
statement->case_label.end_range = end_range;
- if (!is_constant_expression(end_range)) {
- /* This check does not prevent the error message in all cases of an
- * prior error while parsing the expression. At least it catches the
- * common case of a mistyped enum entry. */
- if (is_type_valid(skip_typeref(end_range->base.type))) {
+ expression_classification_t const end_class = is_constant_expression(end_range);
+ if (end_class != EXPR_CLASS_CONSTANT) {
+ if (end_class != EXPR_CLASS_ERROR) {
errorf(pos, "case range does not reduce to an integer constant");
}
statement->case_label.is_bad = true;
errorf(pos, "case label not within a switch statement");
}
- statement_t *const inner_stmt = parse_statement();
- statement->case_label.statement = inner_stmt;
- if (inner_stmt->kind == STATEMENT_DECLARATION) {
- errorf(&inner_stmt->base.source_position, "declaration after case label");
- }
+ statement->case_label.statement = parse_label_inner_statement("case label", false);
POP_PARENT;
return statement;
PUSH_PARENT(statement);
expect(':', end_error);
+end_error:
+
if (current_switch != NULL) {
const case_label_statement_t *def_label = current_switch->default_label;
if (def_label != NULL) {
"'default' label not within a switch statement");
}
- statement_t *const inner_stmt = parse_statement();
- statement->case_label.statement = inner_stmt;
- if (inner_stmt->kind == STATEMENT_DECLARATION) {
- errorf(&inner_stmt->base.source_position, "declaration after default label");
- }
+ statement->case_label.statement = parse_label_inner_statement("default label", false);
POP_PARENT;
return statement;
-end_error:
- POP_PARENT;
- return create_invalid_statement();
}
/**
static statement_t *parse_label_statement(void)
{
assert(token.type == T_IDENTIFIER);
- symbol_t *symbol = token.v.symbol;
+ symbol_t *symbol = token.symbol;
label_t *label = get_label(symbol);
statement_t *const statement = allocate_statement_zero(STATEMENT_LABEL);
eat(':');
- if (token.type == '}') {
- /* TODO only warn? */
- if (warning.other && false) {
- warningf(HERE, "label at end of compound statement");
- statement->label.statement = create_empty_statement();
- } else {
- errorf(HERE, "label at end of compound statement");
- statement->label.statement = create_invalid_statement();
- }
- } else if (token.type == ';') {
- /* Eat an empty statement here, to avoid the warning about an empty
- * statement after a label. label:; is commonly used to have a label
- * before a closing brace. */
- statement->label.statement = create_empty_statement();
- next_token();
- } else {
- statement_t *const inner_stmt = parse_statement();
- statement->label.statement = inner_stmt;
- if (inner_stmt->kind == STATEMENT_DECLARATION) {
- errorf(&inner_stmt->base.source_position, "declaration after label");
- }
- }
+ statement->label.statement = parse_label_inner_statement("label", true);
/* remember the labels in a list for later checking */
*label_anchor = &statement->label;
statement->gotos.expression = expression;
} else if (token.type == T_IDENTIFIER) {
- symbol_t *symbol = token.v.symbol;
+ symbol_t *symbol = token.symbol;
next_token();
statement->gotos.label = get_label(symbol);
} else {
else
parse_error_expected("while parsing goto", T_IDENTIFIER, NULL);
eat_until_anchor();
- goto end_error;
+ return create_invalid_statement();
}
/* remember the goto's in a list for later checking */
expect(';', end_error);
- return statement;
end_error:
- return create_invalid_statement();
+ return statement;
}
/**
eat(T___label__);
- entity_t *begin = NULL, *end = NULL;
-
+ entity_t *begin = NULL;
+ entity_t *end = NULL;
+ entity_t **anchor = &begin;
do {
if (token.type != T_IDENTIFIER) {
parse_error_expected("while parsing local label declaration",
T_IDENTIFIER, NULL);
goto end_error;
}
- symbol_t *symbol = token.v.symbol;
+ symbol_t *symbol = token.symbol;
entity_t *entity = get_entity(symbol, NAMESPACE_LABEL);
if (entity != NULL && entity->base.parent_scope == current_scope) {
errorf(HERE, "multiple definitions of '__label__ %Y' (previous definition %P)",
entity->base.source_position = token.source_position;
entity->base.symbol = symbol;
- if (end != NULL)
- end->base.next = entity;
- end = entity;
- if (begin == NULL)
- begin = entity;
+ *anchor = entity;
+ anchor = &entity->base.next;
+ end = entity;
environment_push(entity);
}
next_token();
} while (next_if(','));
- eat(';');
+ expect(';', end_error);
end_error:
statement->declaration.declarations_begin = begin;
statement->declaration.declarations_end = end;
symbol_t *symbol = NULL;
if (token.type == T_IDENTIFIER) {
- symbol = token.v.symbol;
+ symbol = token.symbol;
next_token();
entity = get_entity(symbol, NAMESPACE_NORMAL);
token_type_t la1_type = (token_type_t)look_ahead(1)->type;
if (la1_type == ':') {
statement = parse_label_statement();
- } else if (is_typedef_symbol(token.v.symbol)) {
+ } else if (is_typedef_symbol(token.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.v.symbol, NAMESPACE_NORMAL) != NULL)
- goto expression_statment;
- /* FALLTHROUGH */
-
+ if (get_entity(token.symbol, NAMESPACE_NORMAL) != NULL) {
+ default:
+ statement = parse_expression_statement();
+ } else {
DECLARATION_START
case T_IDENTIFIER:
- statement = parse_declaration_statement();
- break;
-
- default:
-expression_statment:
- statement = parse_expression_statement();
+ statement = parse_declaration_statement();
+ }
break;
}
}
incomplete_arrays = NULL;
}
-/**
- * create a builtin function.
- */
-static entity_t *create_builtin_function(builtin_kind_t kind, const char *name, type_t *function_type)
-{
- symbol_t *symbol = symbol_table_insert(name);
- entity_t *entity = allocate_entity_zero(ENTITY_FUNCTION);
- entity->declaration.storage_class = STORAGE_CLASS_EXTERN;
- entity->declaration.declared_storage_class = STORAGE_CLASS_EXTERN;
- entity->declaration.type = function_type;
- entity->declaration.implicit = true;
- entity->base.symbol = symbol;
- entity->base.source_position = builtin_source_position;
-
- entity->function.btk = kind;
-
- record_entity(entity, /*is_definition=*/false);
- return entity;
-}
-
-
-/**
- * Create predefined gnu builtins.
- */
-static void create_gnu_builtins(void)
-{
-#define GNU_BUILTIN(a, b) create_builtin_function(bk_gnu_builtin_##a, "__builtin_" #a, b)
-
- GNU_BUILTIN(alloca, make_function_1_type(type_void_ptr, type_size_t));
- GNU_BUILTIN(huge_val, make_function_0_type(type_double));
- GNU_BUILTIN(huge_valf, make_function_0_type(type_float));
- GNU_BUILTIN(huge_vall, make_function_0_type(type_long_double));
- GNU_BUILTIN(inf, make_function_0_type(type_double));
- GNU_BUILTIN(inff, make_function_0_type(type_float));
- GNU_BUILTIN(infl, make_function_0_type(type_long_double));
- GNU_BUILTIN(nan, make_function_1_type(type_double, type_char_ptr));
- GNU_BUILTIN(nanf, make_function_1_type(type_float, type_char_ptr));
- GNU_BUILTIN(nanl, make_function_1_type(type_long_double, type_char_ptr));
- GNU_BUILTIN(va_end, make_function_1_type(type_void, type_valist));
- GNU_BUILTIN(expect, make_function_2_type(type_long, type_long, type_long));
- GNU_BUILTIN(return_address, make_function_1_type(type_void_ptr, type_unsigned_int));
- GNU_BUILTIN(frame_address, make_function_1_type(type_void_ptr, type_unsigned_int));
- GNU_BUILTIN(ffs, make_function_1_type(type_int, type_unsigned_int));
- GNU_BUILTIN(clz, make_function_1_type(type_int, type_unsigned_int));
- GNU_BUILTIN(ctz, make_function_1_type(type_int, type_unsigned_int));
- GNU_BUILTIN(popcount, make_function_1_type(type_int, type_unsigned_int));
- GNU_BUILTIN(parity, make_function_1_type(type_int, type_unsigned_int));
- GNU_BUILTIN(prefetch, make_function_1_type_variadic(type_float, type_void_ptr));
- GNU_BUILTIN(trap, make_function_0_type_noreturn(type_void));
-
-#undef GNU_BUILTIN
-}
-
-/**
- * Create predefined MS intrinsics.
- */
-static void create_microsoft_intrinsics(void)
-{
-#define MS_BUILTIN(a, b) create_builtin_function(bk_ms##a, #a, b)
-
- /* intrinsics for all architectures */
- MS_BUILTIN(_rotl, make_function_2_type(type_unsigned_int, type_unsigned_int, type_int));
- MS_BUILTIN(_rotr, make_function_2_type(type_unsigned_int, type_unsigned_int, type_int));
- MS_BUILTIN(_rotl64, make_function_2_type(type_unsigned_int64, type_unsigned_int64, type_int));
- MS_BUILTIN(_rotr64, make_function_2_type(type_unsigned_int64, type_unsigned_int64, type_int));
- MS_BUILTIN(_byteswap_ushort, make_function_1_type(type_unsigned_short, type_unsigned_short));
- MS_BUILTIN(_byteswap_ulong, make_function_1_type(type_unsigned_long, type_unsigned_long));
- MS_BUILTIN(_byteswap_uint64, make_function_1_type(type_unsigned_int64, type_unsigned_int64));
-
- MS_BUILTIN(__debugbreak, make_function_0_type(type_void));
- MS_BUILTIN(_ReturnAddress, make_function_0_type(type_void_ptr));
- MS_BUILTIN(_AddressOfReturnAddress, make_function_0_type(type_void_ptr));
- MS_BUILTIN(__popcount, make_function_1_type(type_unsigned_int, type_unsigned_int));
-
- /* x86/x64 only */
- MS_BUILTIN(_enable, make_function_0_type(type_void));
- MS_BUILTIN(_disable, make_function_0_type(type_void));
- MS_BUILTIN(__inbyte, make_function_1_type(type_unsigned_char, type_unsigned_short));
- MS_BUILTIN(__inword, make_function_1_type(type_unsigned_short, type_unsigned_short));
- MS_BUILTIN(__indword, make_function_1_type(type_unsigned_long, type_unsigned_short));
- MS_BUILTIN(__outbyte, make_function_2_type(type_void, type_unsigned_short, type_unsigned_char));
- MS_BUILTIN(__outword, make_function_2_type(type_void, type_unsigned_short, type_unsigned_short));
- MS_BUILTIN(__outdword, make_function_2_type(type_void, type_unsigned_short, type_unsigned_long));
- MS_BUILTIN(__ud2, make_function_0_type_noreturn(type_void));
- MS_BUILTIN(_BitScanForward, make_function_2_type(type_unsigned_char, type_unsigned_long_ptr, type_unsigned_long));
- MS_BUILTIN(_BitScanReverse, make_function_2_type(type_unsigned_char, type_unsigned_long_ptr, type_unsigned_long));
- MS_BUILTIN(_InterlockedExchange, make_function_2_type(type_long, type_long_ptr, type_long));
- MS_BUILTIN(_InterlockedExchange64, make_function_2_type(type_int64, type_int64_ptr, type_int64));
-
- if (machine_size <= 32) {
- MS_BUILTIN(__readeflags, make_function_0_type(type_unsigned_int));
- MS_BUILTIN(__writeeflags, make_function_1_type(type_void, type_unsigned_int));
- } else {
- MS_BUILTIN(__readeflags, make_function_0_type(type_unsigned_int64));
- MS_BUILTIN(__writeeflags, make_function_1_type(type_void, type_unsigned_int64));
- }
-
-#undef MS_BUILTIN
-}
-
/**
* Initialize the parser.
*/