unsigned parenthesis_count = 0;
unsigned brace_count = 0;
unsigned bracket_count = 0;
- int end_token = type;
- if (type == '(')
- end_token = ')';
- else if (type == '{')
- end_token = '}';
- else if (type == '[')
- end_token = ']';
+ int end_token;
+ switch (type) {
+ case '(': end_token = ')'; break;
+ case '{': end_token = '}'; break;
+ case '[': end_token = ']'; break;
+ default: end_token = type; break;
+ }
while(token.type != end_token ||
(parenthesis_count > 0 || brace_count > 0 || bracket_count > 0)) {
/* This isn't really correct, the backend should provide a list of machine
* specific modes (according to gcc philosophy that is...) */
const char *symbol_str = token.v.symbol->string;
- if(strcmp_underscore("QI", symbol_str) == 0) {
+ if (strcmp_underscore("QI", symbol_str) == 0 ||
+ strcmp_underscore("byte", symbol_str) == 0) {
attribute->u.akind = ATOMIC_TYPE_CHAR;
} else if (strcmp_underscore("HI", symbol_str) == 0) {
attribute->u.akind = ATOMIC_TYPE_SHORT;
- } else if(strcmp_underscore("SI", symbol_str) == 0) {
+ } else if (strcmp_underscore("SI", symbol_str) == 0
+ || strcmp_underscore("word", symbol_str) == 0
+ || strcmp_underscore("pointer", symbol_str) == 0) {
attribute->u.akind = ATOMIC_TYPE_INT;
- } else if(strcmp_underscore("DI", symbol_str) == 0) {
+ } else if (strcmp_underscore("DI", symbol_str) == 0) {
attribute->u.akind = ATOMIC_TYPE_LONGLONG;
} else {
warningf(HERE, "ignoring unknown mode '%s'", symbol_str);
switch(kind) {
case GNU_AK_CONST:
case GNU_AK_VOLATILE:
- case GNU_AK_CDECL:
- case GNU_AK_STDCALL:
- case GNU_AK_FASTCALL:
case GNU_AK_DEPRECATED:
case GNU_AK_NAKED:
case GNU_AK_MALLOC:
case GNU_AK_NOCOMMON:
case GNU_AK_SHARED:
case GNU_AK_NOTSHARED:
- case GNU_AK_USED:
case GNU_AK_UNUSED:
case GNU_AK_NO_INSTRUMENT_FUNCTION:
case GNU_AK_WARN_UNUSED_RESULT:
case GNU_AK_MAY_ALIAS:
case GNU_AK_MS_STRUCT:
case GNU_AK_GCC_STRUCT:
- check_no_argument(attribute, name);
- break;
-
- case GNU_AK_PURE:
- check_no_argument(attribute, name);
- modifiers |= DM_PURE;
- break;
-
- case GNU_AK_ALWAYS_INLINE:
- check_no_argument(attribute, name);
- modifiers |= DM_FORCEINLINE;
- break;
-
- case GNU_AK_DLLIMPORT:
- check_no_argument(attribute, name);
- modifiers |= DM_DLLIMPORT;
- break;
-
- case GNU_AK_DLLEXPORT:
- check_no_argument(attribute, name);
- modifiers |= DM_DLLEXPORT;
- break;
-
- case GNU_AK_PACKED:
- check_no_argument(attribute, name);
- modifiers |= DM_PACKED;
- break;
-
- case GNU_AK_NOINLINE:
- check_no_argument(attribute, name);
- modifiers |= DM_NOINLINE;
- break;
-
- case GNU_AK_NORETURN:
- check_no_argument(attribute, name);
- modifiers |= DM_NORETURN;
- break;
-
- case GNU_AK_NOTHROW:
- check_no_argument(attribute, name);
- modifiers |= DM_NOTHROW;
- break;
-
- case GNU_AK_TRANSPARENT_UNION:
- check_no_argument(attribute, name);
- modifiers |= DM_TRANSPARENT_UNION;
- break;
-
- case GNU_AK_CONSTRUCTOR:
- check_no_argument(attribute, name);
- modifiers |= DM_CONSTRUCTOR;
- break;
-
- case GNU_AK_DESTRUCTOR:
- check_no_argument(attribute, name);
- modifiers |= DM_DESTRUCTOR;
- break;
+ goto no_arg;
+
+ case GNU_AK_CDECL: modifiers |= DM_CDECL; goto no_arg;
+ case GNU_AK_FASTCALL: modifiers |= DM_FASTCALL; goto no_arg;
+ case GNU_AK_STDCALL: modifiers |= DM_STDCALL; goto no_arg;
+ case GNU_AK_USED: modifiers |= DM_USED; goto no_arg;
+ case GNU_AK_PURE: modifiers |= DM_PURE; goto no_arg;
+ case GNU_AK_ALWAYS_INLINE: modifiers |= DM_FORCEINLINE; goto no_arg;
+ case GNU_AK_DLLIMPORT: modifiers |= DM_DLLIMPORT; goto no_arg;
+ case GNU_AK_DLLEXPORT: modifiers |= DM_DLLEXPORT; goto no_arg;
+ case GNU_AK_PACKED: modifiers |= DM_PACKED; goto no_arg;
+ case GNU_AK_NOINLINE: modifiers |= DM_NOINLINE; goto no_arg;
+ case GNU_AK_NORETURN: modifiers |= DM_NORETURN; goto no_arg;
+ case GNU_AK_NOTHROW: modifiers |= DM_NOTHROW; goto no_arg;
+ case GNU_AK_TRANSPARENT_UNION: modifiers |= DM_TRANSPARENT_UNION; goto no_arg;
+ case GNU_AK_CONSTRUCTOR: modifiers |= DM_CONSTRUCTOR; goto no_arg;
+ case GNU_AK_DESTRUCTOR: modifiers |= DM_DESTRUCTOR; goto no_arg;
case GNU_AK_ALIGNED:
/* __align__ may be used without an argument */
case GNU_AK_LAST:
/* already handled */
break;
+
+no_arg:
+ check_no_argument(attribute, name);
}
}
if (attribute != NULL) {
switch(token.type) {
case T___attribute__:
modifiers |= parse_gnu_attribute(attributes);
- break;
+ continue;
case T_asm:
next_token();
parse_string_literals();
}
expect(')');
- break;
+ continue;
+
+ case T_cdecl: modifiers |= DM_CDECL; break;
+ case T__fastcall: modifiers |= DM_FASTCALL; break;
+ case T__stdcall: modifiers |= DM_STDCALL; break;
- case T_cdecl:
- case T__fastcall:
- case T__stdcall:
case T___thiscall:
/* TODO record modifier */
warningf(HERE, "Ignoring declaration modifier %K", &token);
- next_token();
break;
- default:
- goto attributes_finished;
+end_error:
+ default: return modifiers;
}
- }
-attributes_finished:
-end_error:
- return modifiers;
+ next_token();
+ }
}
static designator_t *parse_designation(void)
symbol = token.v.symbol;
next_token();
- if (is_struct) {
- declaration = get_declaration(symbol, NAMESPACE_STRUCT);
- } else {
- declaration = get_declaration(symbol, NAMESPACE_UNION);
+ namespace_t const namespc =
+ is_struct ? NAMESPACE_STRUCT : NAMESPACE_UNION;
+ declaration = get_declaration(symbol, namespc);
+ if (declaration != NULL) {
+ if (declaration->parent_scope != scope &&
+ (token.type == '{' || token.type == ';')) {
+ declaration = NULL;
+ } else if (declaration->init.complete &&
+ token.type == '{') {
+ assert(symbol != NULL);
+ errorf(HERE, "multiple definitions of '%s %Y' (previous definition at %P)",
+ is_struct ? "struct" : "union", symbol,
+ &declaration->source_position);
+ declaration->scope.declarations = NULL;
+ }
}
} else if (token.type != '{') {
if (is_struct) {
}
if (token.type == '{') {
- if (declaration->init.complete) {
- assert(symbol != NULL);
- errorf(HERE, "multiple definitions of '%s %Y' (previous definition at %P)",
- is_struct ? "struct" : "union", symbol,
- &declaration->source_position);
- declaration->scope.declarations = NULL;
- }
declaration->init.complete = true;
parse_compound_type_entries(declaration);
specifiers->source_position = token.source_position;
while(true) {
+ specifiers->modifiers
+ |= parse_attributes(&specifiers->gnu_attributes);
+ if (specifiers->modifiers & DM_TRANSPARENT_UNION)
+ modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION;
+
switch(token.type) {
/* storage class */
next_token();
break;
- case T___attribute__:
- specifiers->modifiers
- |= parse_attributes(&specifiers->gnu_attributes);
- if (specifiers->modifiers & DM_TRANSPARENT_UNION)
- modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION;
- break;
-
case T_IDENTIFIER: {
/* only parse identifier if we haven't found a type yet */
if (type != NULL || type_specifiers != 0)
return declarations;
}
+static type_t *automatic_type_conversion(type_t *orig_type);
+
static void semantic_parameter(declaration_t *declaration)
{
/* TODO: improve error messages */
}
type_t *const orig_type = declaration->type;
- type_t * type = skip_typeref(orig_type);
-
- /* Array as last part of a parameter type is just syntactic sugar. Turn it
- * into a pointer. § 6.7.5.3 (7) */
- if (is_type_array(type)) {
- type_t *const element_type = type->array.element_type;
-
- type = make_pointer_type(element_type, type->base.qualifiers);
-
- declaration->type = type;
- }
+ /* §6.7.5.3(7): Array as last part of a parameter type is just syntactic
+ * sugar. Turn it into a pointer.
+ * §6.7.5.3(8): A declaration of a parameter as ``function returning type''
+ * shall be adjusted to ``pointer to function returning type'', as in 6.3.2.1.
+ */
+ type_t *const type = automatic_type_conversion(orig_type);
+ declaration->type = type;
- if (is_type_incomplete(type)) {
+ if (is_type_incomplete(skip_typeref(type))) {
errorf(HERE, "incomplete type '%T' not allowed for parameter '%Y'",
orig_type, declaration->symbol);
}
return;
for (const declaration_t *decl = global_scope->declarations; decl != NULL; decl = decl->next) {
- if (decl->used || decl->storage_class != STORAGE_CLASS_STATIC)
+ if (decl->used ||
+ decl->modifiers & DM_USED ||
+ decl->storage_class != STORAGE_CLASS_STATIC)
continue;
type_t *const type = decl->type;
}
}
+static void parse_global_asm(void)
+{
+ eat(T_asm);
+ expect('(');
+
+ statement_t *statement = allocate_statement_zero(STATEMENT_ASM);
+ statement->base.source_position = token.source_position;
+ statement->asms.asm_text = parse_string_literals();
+ statement->base.next = unit->global_asm;
+ unit->global_asm = statement;
+
+ expect(')');
+ expect(';');
+
+end_error:;
+}
+
/**
* Parse a translation unit.
*/
static void parse_translation_unit(void)
{
while(token.type != T_EOF) {
- if (token.type == ';') {
- /* TODO error in strict mode */
- warningf(HERE, "stray ';' outside of function");
- next_token();
- } else {
- parse_external_declaration();
+ switch (token.type) {
+ case ';':
+ /* TODO error in strict mode */
+ warningf(HERE, "stray ';' outside of function");
+ next_token();
+ break;
+
+ case T_asm:
+ parse_global_asm();
+ break;
+
+ default:
+ parse_external_declaration();
+ break;
}
}
}