+ int i;
+ for(i = 0; i < GNU_AK_LAST; ++i) {
+ if(strcmp_underscore(gnu_attribute_names[i], name) == 0)
+ break;
+ }
+ gnu_attribute_kind_t kind = (gnu_attribute_kind_t)i;
+
+ attribute = NULL;
+ if(kind == GNU_AK_LAST) {
+ if(warning.attribute)
+ warningf(HERE, "'%s' attribute directive ignored", name);
+
+ /* skip possible arguments */
+ if(token.type == '(') {
+ eat_until_matching_token(')');
+ }
+ } else {
+ /* check for arguments */
+ attribute = allocate_gnu_attribute(kind);
+ if(token.type == '(') {
+ next_token();
+ if(token.type == ')') {
+ /* empty args are allowed */
+ next_token();
+ } else
+ attribute->have_arguments = true;
+ }
+
+ 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_WEAK:
+ case GNU_AK_COMMON:
+ 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_LONGCALL:
+ case GNU_AK_SHORTCALL:
+ case GNU_AK_LONG_CALL:
+ case GNU_AK_SHORT_CALL:
+ case GNU_AK_FUNCTION_VECTOR:
+ case GNU_AK_INTERRUPT_HANDLER:
+ case GNU_AK_NMI_HANDLER:
+ case GNU_AK_NESTING:
+ case GNU_AK_NEAR:
+ case GNU_AK_FAR:
+ case GNU_AK_SIGNAL:
+ case GNU_AK_EIGTHBIT_DATA:
+ case GNU_AK_TINY_DATA:
+ case GNU_AK_SAVEALL:
+ case GNU_AK_FLATTEN:
+ case GNU_AK_SSEREGPARM:
+ case GNU_AK_EXTERNALLY_VISIBLE:
+ case GNU_AK_RETURN_TWICE:
+ 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;
+
+ case GNU_AK_ALIGNED:
+ case GNU_AK_FORMAT_ARG:
+ case GNU_AK_REGPARM:
+ case GNU_AK_TRAP_EXIT:
+ if(!attribute->have_arguments) {
+ /* should have arguments */
+ errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
+ attribute->invalid = true;
+ } else
+ parse_gnu_attribute_const_arg(attribute);
+ break;
+ case GNU_AK_ALIAS:
+ case GNU_AK_SECTION:
+ case GNU_AK_SP_SWITCH:
+ if(!attribute->have_arguments) {
+ /* should have arguments */
+ errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
+ attribute->invalid = true;
+ } else
+ parse_gnu_attribute_string_arg(attribute, &attribute->u.string);
+ break;
+ case GNU_AK_FORMAT:
+ if(!attribute->have_arguments) {
+ /* should have arguments */
+ errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
+ attribute->invalid = true;
+ } else
+ parse_gnu_attribute_format_args(attribute);
+ break;
+ case GNU_AK_WEAKREF:
+ /* may have one string argument */
+ if(attribute->have_arguments)
+ parse_gnu_attribute_string_arg(attribute, &attribute->u.string);
+ break;
+ case GNU_AK_NONNULL:
+ if(attribute->have_arguments)
+ parse_gnu_attribute_const_arg_list(attribute);
+ break;
+ case GNU_AK_TLS_MODEL:
+ if(!attribute->have_arguments) {
+ /* should have arguments */
+ errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
+ } else
+ parse_gnu_attribute_tls_model_arg(attribute);
+ break;
+ case GNU_AK_VISIBILITY:
+ if(!attribute->have_arguments) {
+ /* should have arguments */
+ errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
+ } else
+ parse_gnu_attribute_visibility_arg(attribute);
+ break;
+ case GNU_AK_MODEL:
+ if(!attribute->have_arguments) {
+ /* should have arguments */
+ errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
+ } else {
+ parse_gnu_attribute_model_arg(attribute);
+ }
+ break;
+ case GNU_AK_MODE:
+ if(!attribute->have_arguments) {
+ /* should have arguments */
+ errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
+ } else {
+ parse_gnu_attribute_mode_arg(attribute);
+ }
+ break;
+ case GNU_AK_INTERRUPT:
+ /* may have one string argument */
+ if(attribute->have_arguments)
+ parse_gnu_attribute_interrupt_arg(attribute);
+ break;
+ case GNU_AK_SENTINEL:
+ /* may have one string argument */
+ if(attribute->have_arguments)
+ parse_gnu_attribute_const_arg(attribute);
+ break;
+ case GNU_AK_LAST:
+ /* already handled */
+ break;
+ }
+ }
+ if(attribute != NULL) {
+ if(last != NULL) {
+ last->next = attribute;
+ last = attribute;
+ } else {
+ head = last = attribute;
+ }
+ }
+
+ if(token.type != ',')
+ break;
+ next_token();