+static
+const char *parse_string_literals(void)
+{
+ assert(token.type == T_STRING_LITERAL);
+ const char *result = token.v.string;
+
+ next_token();
+
+ while(token.type == T_STRING_LITERAL) {
+ result = concat_strings(result, token.v.string);
+ next_token();
+ }
+
+ return result;
+}
+
+static
+void parse_attributes(void)
+{
+ while(1) {
+ switch(token.type) {
+ case T___attribute__:
+ next_token();
+
+ expect_void('(');
+ int depth = 1;
+ while(depth > 0) {
+ switch(token.type) {
+ case T_EOF:
+ parse_error("EOF while parsing attribute");
+ break;
+ case '(':
+ next_token();
+ depth++;
+ break;
+ case ')':
+ next_token();
+ depth--;
+ break;
+ default:
+ next_token();
+ }
+ }
+ break;
+ case T_asm:
+ next_token();
+ expect_void('(');
+ if(token.type != T_STRING_LITERAL) {
+ parse_error_expected("while parsing assembler attribute",
+ T_STRING_LITERAL);
+ eat_until(')');
+ break;
+ } else {
+ parse_string_literals();
+ }
+ expect_void(')');
+ break;
+ default:
+ goto attributes_finished;
+ }
+ }
+
+attributes_finished:
+ ;
+}
+