#define PUSH_EXTENSION() \
(void)0; \
bool const old_gcc_extension = in_gcc_extension; \
- while (next_if(T___extension__)) { \
+ while (accept(T___extension__)) { \
in_gcc_extension = true; \
} \
do {} while (0)
next_token();
}
-static inline bool next_if(token_kind_t const kind)
+/**
+ * Consume the current token, if it is of the expected kind.
+ *
+ * @param kind The kind of token to consume.
+ * @return Whether the token was consumed.
+ */
+static inline bool accept(token_kind_t const kind)
{
if (token.kind == kind) {
eat(kind);
static void eat_block(void)
{
eat_until_matching_token('{');
- next_if('}');
+ accept('}');
}
/**
/* append argument */
*anchor = argument;
anchor = &argument->next;
- } while (next_if(','));
+ } while (accept(','));
expect(')');
return first;
}
next_token();
/* parse arguments */
- if (next_if('('))
+ if (accept('('))
attribute->a.arguments = parse_attribute_arguments();
return attribute;
*anchor = attribute;
anchor = &attribute->next;
}
- } while (next_if(','));
+ } while (accept(','));
rem_anchor_token(',');
rem_anchor_token(')');
bool additional_warning_displayed = false;
while (braces > 0) {
- next_if(',');
+ accept(',');
if (token.kind != '}') {
if (!additional_warning_displayed) {
warningf(WARN_OTHER, HERE, "additional elements in scalar initializer");
*/
static void skip_initializers(void)
{
- next_if('{');
+ accept('{');
while (token.kind != '}') {
if (token.kind == T_EOF)
if (expression->kind == EXPR_STRING_LITERAL && outer_type != NULL) {
result = initializer_from_expression(outer_type, expression);
if (result != NULL) {
- next_if(',');
+ accept(',');
if (token.kind != '}') {
warningf(WARN_OTHER, HERE, "excessive elements in initializer for type '%T'", outer_type);
}
ARR_APP1(initializer_t*, initializers, sub);
error_parse_next:
- if (!next_if(','))
+ if (!accept(','))
break;
if (token.kind == '}') {
break;
entity->enum_value.enum_type = enum_type;
rem_anchor_token('=');
- if (next_if('=')) {
+ if (accept('=')) {
expression_t *value = parse_constant_expression();
value = create_implicit_cast(value, enum_type);
}
record_entity(entity, false);
- } while (next_if(',') && token.kind != '}');
+ } while (accept(',') && token.kind != '}');
rem_anchor_token(',');
rem_anchor_token('}');
symbol_t *const sym = expect_identifier("while parsing property declspec", NULL);
if (prop != NULL)
*prop = sym ? sym : sym_anonymous;
- } while (next_if(','));
+ } while (accept(','));
rem_anchor_token(',');
rem_anchor_token(')');
static attribute_t *parse_microsoft_extended_decl_modifier_single(void)
{
attribute_kind_t kind = ATTRIBUTE_UNKNOWN;
- if (next_if(T_restrict)) {
+ if (accept(T_restrict)) {
kind = ATTRIBUTE_MS_RESTRICT;
} else if (token.kind == T_IDENTIFIER) {
char const *const name = token.base.symbol->string;
}
/* parse arguments */
- if (next_if('('))
+ if (accept('('))
attribute->a.arguments = parse_attribute_arguments();
return attribute;
*anchor = attribute;
anchor = &attribute->next;
- } while (next_if(','));
+ } while (accept(','));
}
rem_anchor_token(')');
expect(')');
if (scope != NULL)
append_entity(scope, entity);
- } while (next_if(',') && token.kind == T_IDENTIFIER);
+ } while (accept(',') && token.kind == T_IDENTIFIER);
}
static entity_t *parse_parameter(void)
default:
goto parameters_finished;
}
- } while (next_if(','));
+ } while (accept(','));
parameters_finished:
rem_anchor_token(',');
}
eat('[');
add_anchor_token(']');
- bool is_static = next_if(T_static);
+ bool is_static = accept(T_static);
type_qualifiers_t type_qualifiers = parse_type_qualifiers();
if (!is_static)
- is_static = next_if(T_static);
+ is_static = accept(T_static);
array->type_qualifiers = type_qualifiers;
array->is_static = is_static;
check_variable_type_complete(entity);
- if (!next_if(','))
+ if (!accept(','))
break;
add_anchor_token('=');
append_entity(&compound->members, entity);
}
}
- } while (next_if(','));
+ } while (accept(','));
rem_anchor_token(',');
rem_anchor_token(';');
expect(';');
source_position_t pos;
const scope_t *lookup_scope = NULL;
- if (next_if(T_COLONCOLON))
+ if (accept(T_COLONCOLON))
lookup_scope = &unit->scope;
entity_t *entity;
/* lookup entity */
entity = lookup_entity(lookup_scope, symbol, NAMESPACE_NORMAL);
- if (!next_if(T_COLONCOLON))
+ if (!accept(T_COLONCOLON))
break;
switch (entity->kind) {
symbol, get_entity_kind_name(entity->kind));
/* skip further qualifications */
- while (next_if(T_IDENTIFIER) && next_if(T_COLONCOLON)) {}
+ while (accept(T_IDENTIFIER) && accept(T_COLONCOLON)) {}
return create_error_entity(sym_anonymous, ENTITY_VARIABLE);
}
designator_t *last_designator = result;
while (true) {
- if (next_if('.')) {
+ if (accept('.')) {
designator_t *const designator = allocate_ast_zero(sizeof(result[0]));
designator->symbol = expect_identifier("while parsing member designator", &designator->source_position);
if (!designator->symbol)
last_designator = designator;
continue;
}
- if (next_if('[')) {
+ if (accept('[')) {
add_anchor_token(']');
designator_t *designator = allocate_ast_zero(sizeof(result[0]));
designator->source_position = *HERE;
if (token.kind != ')') do {
(void)parse_assignment_expression();
- } while (next_if(','));
+ } while (accept(','));
rem_anchor_token(',');
rem_anchor_token(')');
check_idx:
res_type = automatic_type_conversion(res_type);
if (!is_type_integer(idx_type)) {
- errorf(&idx->base.source_position, "array subscript must have integer type");
+ if (is_type_valid(idx_type))
+ errorf(&idx->base.source_position, "array subscript must have integer type");
} else if (is_type_atomic(idx_type, ATOMIC_TYPE_CHAR)) {
source_position_t const *const pos = &idx->base.source_position;
warningf(WARN_CHAR_SUBSCRIPTS, pos, "array subscript has char type");
*anchor = argument;
anchor = &argument->next;
- } while (next_if(','));
+ } while (accept(','));
}
rem_anchor_token(',');
rem_anchor_token(')');
eat(T_delete);
- if (next_if('[')) {
+ if (accept('[')) {
result->kind = EXPR_UNARY_DELETE_ARRAY;
expect(']');
}
/**
* Parse a asm statement arguments specification.
*/
-static asm_argument_t *parse_asm_arguments(bool is_out)
+static void parse_asm_arguments(asm_argument_t **anchor, bool const is_out)
{
- asm_argument_t *result = NULL;
- asm_argument_t **anchor = &result;
+ if (token.kind == T_STRING_LITERAL || token.kind == '[') {
+ add_anchor_token(',');
+ do {
+ asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0]));
- while (token.kind == T_STRING_LITERAL || token.kind == '[') {
- asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0]));
+ add_anchor_token(')');
+ add_anchor_token('(');
+ add_anchor_token(T_STRING_LITERAL);
- if (next_if('[')) {
- add_anchor_token(']');
- argument->symbol = expect_identifier("while parsing asm argument", NULL);
- rem_anchor_token(']');
- expect(']');
- if (!argument->symbol)
- return NULL;
- }
-
- argument->constraints = parse_string_literals("asm argument");
- add_anchor_token(')');
- expect('(');
- expression_t *expression = parse_expression();
- rem_anchor_token(')');
- if (is_out) {
- /* Ugly GCC stuff: Allow lvalue casts. Skip casts, when they do not
- * change size or type representation (e.g. int -> long is ok, but
- * int -> float is not) */
- if (expression->kind == EXPR_UNARY_CAST) {
- type_t *const type = expression->base.type;
- type_kind_t const kind = type->kind;
- if (kind == TYPE_ATOMIC || kind == TYPE_POINTER) {
- unsigned flags;
- unsigned size;
- if (kind == TYPE_ATOMIC) {
- atomic_type_kind_t const akind = type->atomic.akind;
- flags = get_atomic_type_flags(akind) & ~ATOMIC_TYPE_FLAG_SIGNED;
- size = get_atomic_type_size(akind);
- } else {
- flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC;
- size = get_type_size(type_void_ptr);
- }
+ if (accept('[')) {
+ add_anchor_token(']');
+ argument->symbol = expect_identifier("while parsing asm argument", NULL);
+ rem_anchor_token(']');
+ expect(']');
+ }
- do {
- expression_t *const value = expression->unary.value;
- type_t *const value_type = value->base.type;
- type_kind_t const value_kind = value_type->kind;
-
- unsigned value_flags;
- unsigned value_size;
- if (value_kind == TYPE_ATOMIC) {
- atomic_type_kind_t const value_akind = value_type->atomic.akind;
- value_flags = get_atomic_type_flags(value_akind) & ~ATOMIC_TYPE_FLAG_SIGNED;
- value_size = get_atomic_type_size(value_akind);
- } else if (value_kind == TYPE_POINTER) {
- value_flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC;
- value_size = get_type_size(type_void_ptr);
+ rem_anchor_token(T_STRING_LITERAL);
+ argument->constraints = parse_string_literals("asm argument");
+ rem_anchor_token('(');
+ expect('(');
+ expression_t *expression = parse_expression();
+ if (is_out) {
+ /* Ugly GCC stuff: Allow lvalue casts. Skip casts, when they do not
+ * change size or type representation (e.g. int -> long is ok, but
+ * int -> float is not) */
+ if (expression->kind == EXPR_UNARY_CAST) {
+ type_t *const type = expression->base.type;
+ type_kind_t const kind = type->kind;
+ if (kind == TYPE_ATOMIC || kind == TYPE_POINTER) {
+ unsigned flags;
+ unsigned size;
+ if (kind == TYPE_ATOMIC) {
+ atomic_type_kind_t const akind = type->atomic.akind;
+ flags = get_atomic_type_flags(akind) & ~ATOMIC_TYPE_FLAG_SIGNED;
+ size = get_atomic_type_size(akind);
} else {
- break;
+ flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC;
+ size = get_type_size(type_void_ptr);
}
- if (value_flags != flags || value_size != size)
- break;
+ do {
+ expression_t *const value = expression->unary.value;
+ type_t *const value_type = value->base.type;
+ type_kind_t const value_kind = value_type->kind;
+
+ unsigned value_flags;
+ unsigned value_size;
+ if (value_kind == TYPE_ATOMIC) {
+ atomic_type_kind_t const value_akind = value_type->atomic.akind;
+ value_flags = get_atomic_type_flags(value_akind) & ~ATOMIC_TYPE_FLAG_SIGNED;
+ value_size = get_atomic_type_size(value_akind);
+ } else if (value_kind == TYPE_POINTER) {
+ value_flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC;
+ value_size = get_type_size(type_void_ptr);
+ } else {
+ break;
+ }
+
+ if (value_flags != flags || value_size != size)
+ break;
- expression = value;
- } while (expression->kind == EXPR_UNARY_CAST);
+ expression = value;
+ } while (expression->kind == EXPR_UNARY_CAST);
+ }
}
- }
- if (!is_lvalue(expression)) {
- errorf(&expression->base.source_position,
- "asm output argument is not an lvalue");
- }
+ if (!is_lvalue(expression))
+ errorf(&expression->base.source_position, "asm output argument is not an lvalue");
- if (argument->constraints.begin[0] == '=')
- determine_lhs_ent(expression, NULL);
- else
+ if (argument->constraints.begin[0] == '=')
+ determine_lhs_ent(expression, NULL);
+ else
+ mark_vars_read(expression, NULL);
+ } else {
mark_vars_read(expression, NULL);
- } else {
- mark_vars_read(expression, NULL);
- }
- argument->expression = expression;
- expect(')');
-
- set_address_taken(expression, true);
+ }
+ argument->expression = expression;
+ rem_anchor_token(')');
+ expect(')');
- *anchor = argument;
- anchor = &argument->next;
+ set_address_taken(expression, true);
- if (!next_if(','))
- break;
+ *anchor = argument;
+ anchor = &argument->next;
+ } while (accept(','));
+ rem_anchor_token(',');
}
-
- return result;
}
/**
* Parse a asm statement clobber specification.
*/
-static asm_clobber_t *parse_asm_clobbers(void)
+static void parse_asm_clobbers(asm_clobber_t **anchor)
{
- asm_clobber_t *result = NULL;
- asm_clobber_t **anchor = &result;
+ if (token.kind == T_STRING_LITERAL) {
+ add_anchor_token(',');
+ do {
+ asm_clobber_t *clobber = allocate_ast_zero(sizeof(clobber[0]));
+ clobber->clobber = parse_string_literals(NULL);
- while (token.kind == T_STRING_LITERAL) {
- asm_clobber_t *clobber = allocate_ast_zero(sizeof(clobber[0]));
- clobber->clobber = parse_string_literals(NULL);
+ *anchor = clobber;
+ anchor = &clobber->next;
+ } while (accept(','));
+ rem_anchor_token(',');
+ }
+}
- *anchor = clobber;
- anchor = &clobber->next;
+static void parse_asm_labels(asm_label_t **anchor)
+{
+ if (token.kind == T_IDENTIFIER) {
+ add_anchor_token(',');
+ do {
+ label_t *const label = get_label("while parsing 'asm goto' labels");
+ if (label) {
+ asm_label_t *const asm_label = allocate_ast_zero(sizeof(*asm_label));
+ asm_label->label = label;
- if (!next_if(','))
- break;
+ *anchor = asm_label;
+ anchor = &asm_label->next;
+ }
+ } while (accept(','));
+ rem_anchor_token(',');
}
-
- return result;
}
/**
add_anchor_token(':');
add_anchor_token(T_STRING_LITERAL);
- if (next_if(T_volatile))
+ if (accept(T_volatile))
asm_statement->is_volatile = true;
+ bool const asm_goto = accept(T_goto);
+
expect('(');
rem_anchor_token(T_STRING_LITERAL);
asm_statement->asm_text = parse_string_literals("asm statement");
- if (next_if(':'))
- asm_statement->outputs = parse_asm_arguments(true);
-
- if (next_if(':'))
- asm_statement->inputs = parse_asm_arguments(false);
+ if (accept(':')) parse_asm_arguments(&asm_statement->outputs, true);
+ if (accept(':')) parse_asm_arguments(&asm_statement->inputs, false);
+ if (accept(':')) parse_asm_clobbers( &asm_statement->clobbers);
rem_anchor_token(':');
- if (next_if(':'))
- asm_statement->clobbers = parse_asm_clobbers();
+ if (accept(':')) {
+ if (!asm_goto)
+ warningf(WARN_OTHER, &statement->base.source_position, "assembler statement with labels should be 'asm goto'");
+ parse_asm_labels(&asm_statement->labels);
+ if (asm_statement->labels)
+ errorf(&statement->base.source_position, "'asm goto' not supported");
+ } else {
+ if (asm_goto)
+ warningf(WARN_OTHER, &statement->base.source_position, "'asm goto' without labels");
+ }
rem_anchor_token(')');
expect(')');
}
if (GNU_MODE) {
- if (next_if(T_DOTDOTDOT)) {
+ if (accept(T_DOTDOTDOT)) {
expression_t *end_range = parse_expression();
expression_type = expression->base.type;
skipped = skip_typeref(expression_type);
"suggest braces around empty body in an ‘if’ statement");
}
- if (next_if(T_else)) {
+ if (accept(T_else)) {
statement->ifs.false_statement = parse_inner_statement();
if (statement->ifs.false_statement->kind == STATEMENT_EMPTY) {
PUSH_EXTENSION();
- if (next_if(';')) {
+ if (accept(';')) {
} else if (is_declaration_specifier(&token)) {
parse_declaration(record_entity, DECL_FLAGS_NONE);
} else {
POP_PARENT();
- if (next_if(T___except)) {
+ if (accept(T___except)) {
expression_t *const expr = parse_condition();
type_t * type = skip_typeref(expr->base.type);
if (is_type_integer(type)) {
type = type_error_type;
}
statement->ms_try.except_expression = create_implicit_cast(expr, type);
- } else if (!next_if(T__finally)) {
+ } else if (!accept(T__finally)) {
parse_error_expected("while parsing __try statement", T___except, T___finally, NULL);
}
statement->ms_try.final_statement = parse_compound_statement(false);
environment_push(entity);
}
}
- } while (next_if(','));
+ } while (accept(','));
rem_anchor_token(',');
rem_anchor_token(';');
expect(';');
}
current_linkage = new_linkage;
- if (next_if('{')) {
+ if (accept('{')) {
parse_externals();
expect('}');
} else {