Now we are really parsing the attribute rather than build the expression tree first. Signed-Off-By: Christopher Li <sparse@xxxxxxxxxxx> Index: sparse/parse.h =================================================================== Index: sparse/symbol.c =================================================================== Index: sparse/parse.c =================================================================== --- sparse.orig/parse.c 2007-03-07 01:18:31.000000000 -0800 +++ sparse/parse.c 2007-03-07 02:16:09.000000000 -0800 @@ -55,8 +55,19 @@ static struct token *parse_do_statement( static struct token *parse_goto_statement(struct token *token, struct statement *stmt); static struct token *parse_context_statement(struct token *token, struct statement *stmt); static struct token *parse_range_statement(struct token *token, struct statement *stmt); -static struct token *parse_asm(struct token *token, struct statement *stmt); +static struct token *parse_asm_statement(struct token *token, struct statement *stmt); static struct token *toplevel_asm_declaration(struct token *token, struct symbol_list **list); +static struct token *parse_asm_declarator(struct token *token, struct ctype *ctype); + + +static struct token *attribute_packed(struct token *token, struct symbol *attr, struct ctype *ctype); +static struct token *attribute_modifier(struct token *token, struct symbol *attr, struct ctype *ctype); +static struct token *attribute_address_space(struct token *token, struct symbol *attr, struct ctype *ctype); +static struct token *attribute_aligned(struct token *token, struct symbol *attr, struct ctype *ctype); +static struct token *attribute_mode(struct token *token, struct symbol *attr, struct ctype *ctype); +static struct token *attribute_context(struct token *token, struct symbol *attr, struct ctype *ctype); +static struct token *attribute_transparent_union(struct token *token, struct symbol *attr, struct ctype *ctype); +static struct token *ignore_attribute(struct token *token, struct symbol *attr, struct ctype *ctype); static struct symbol_op modifier_op = { @@ -134,7 +145,7 @@ static struct symbol_op goto_op = { .statement = parse_goto_statement, }; -static struct symbol_op context_op = { +static struct symbol_op __context___op = { .statement = parse_context_statement, }; @@ -143,10 +154,48 @@ static struct symbol_op range_op = { }; static struct symbol_op asm_op = { - .statement = parse_asm, + .type = KW_ASM, + .declarator = parse_asm_declarator, + .statement = parse_asm_statement, .toplevel = toplevel_asm_declaration, }; +static struct symbol_op packed_op = { + .attribute = attribute_packed, +}; + +static struct symbol_op aligned_op = { + .attribute = attribute_aligned, +}; + +static struct symbol_op attr_mod_op = { + .attribute = attribute_modifier, +}; + +static struct symbol_op address_space_op = { + .attribute = attribute_address_space, +}; + +static struct symbol_op mode_op = { + .attribute = attribute_mode, +}; + +static struct symbol_op context_op = { + .attribute = attribute_context, +}; + +static struct symbol_op transparent_union_op = { + .attribute = attribute_transparent_union, +}; + +static struct symbol_op ignore_attr_op = { + .attribute = ignore_attribute, +}; + +static struct symbol_op mode_spec_op = { + .type = KW_MODE, +}; + static struct init_keyword { const char *name; enum namespace ns; @@ -196,12 +245,83 @@ static struct init_keyword { { "while", NS_KEYWORD, .op = &while_op }, { "do", NS_KEYWORD, .op = &do_op }, { "goto", NS_KEYWORD, .op = &goto_op }, - { "__context__",NS_KEYWORD, .op = &context_op }, + { "__context__",NS_KEYWORD, .op = &__context___op }, { "__range__", NS_KEYWORD, .op = &range_op }, { "asm", NS_KEYWORD, .op = &asm_op }, { "__asm", NS_KEYWORD, .op = &asm_op }, { "__asm__", NS_KEYWORD, .op = &asm_op }, + /* Attribute */ + { "packed", NS_KEYWORD, .op = &packed_op }, + { "__packed__", NS_KEYWORD, .op = &packed_op }, + { "aligned", NS_KEYWORD, .op = &aligned_op }, + { "__aligned__",NS_KEYWORD, .op = &aligned_op }, + { "nocast", NS_KEYWORD, MOD_NOCAST, .op = &attr_mod_op }, + { "noderef", NS_KEYWORD, MOD_NODEREF, .op = &attr_mod_op }, + { "safe", NS_KEYWORD, MOD_SAFE, .op = &attr_mod_op }, + { "force", NS_KEYWORD, MOD_FORCE, .op = &attr_mod_op }, + { "bitwise", NS_KEYWORD, MOD_BITWISE, .op = &attr_mod_op }, + { "__bitwise__",NS_KEYWORD, MOD_BITWISE, .op = &attr_mod_op }, + { "address_space",NS_KEYWORD, .op = &address_space_op }, + { "mode", NS_KEYWORD, .op = &mode_op }, + { "context", NS_KEYWORD, .op = &context_op }, + { "__transparent_union__", NS_KEYWORD, .op = &transparent_union_op }, + + { "__mode__", NS_KEYWORD, .op = &mode_op }, + { "QI", NS_KEYWORD, MOD_CHAR, .op = &mode_spec_op }, + { "__QI__", NS_KEYWORD, MOD_CHAR, .op = &mode_spec_op }, + { "HI", NS_KEYWORD, MOD_SHORT, .op = &mode_spec_op }, + { "__HI__", NS_KEYWORD, MOD_SHORT, .op = &mode_spec_op }, + { "SI", NS_KEYWORD, .op = &mode_spec_op }, + { "__SI__", NS_KEYWORD, .op = &mode_spec_op }, + { "DI", NS_KEYWORD, MOD_LONGLONG, .op = &mode_spec_op }, + { "__DI__", NS_KEYWORD, MOD_LONGLONG, .op = &mode_spec_op }, + { "word", NS_KEYWORD, MOD_LONG, .op = &mode_spec_op }, + { "__word__", NS_KEYWORD, MOD_LONG, .op = &mode_spec_op }, + + /* Ignored attributes */ + { "nothrow", NS_KEYWORD, .op = &ignore_attr_op }, + { "__nothrow", NS_KEYWORD, .op = &ignore_attr_op }, + { "__nothrow__", NS_KEYWORD, .op = &ignore_attr_op }, + { "__malloc__", NS_KEYWORD, .op = &ignore_attr_op }, + { "nonnull", NS_KEYWORD, .op = &ignore_attr_op }, + { "__nonnull", NS_KEYWORD, .op = &ignore_attr_op }, + { "__nonnull__", NS_KEYWORD, .op = &ignore_attr_op }, + { "format", NS_KEYWORD, .op = &ignore_attr_op }, + { "__format__", NS_KEYWORD, .op = &ignore_attr_op }, + { "__format_arg__", NS_KEYWORD, .op = &ignore_attr_op }, + { "section", NS_KEYWORD, .op = &ignore_attr_op }, + { "__section__",NS_KEYWORD, .op = &ignore_attr_op }, + { "unused", NS_KEYWORD, .op = &ignore_attr_op }, + { "__unused__", NS_KEYWORD, .op = &ignore_attr_op }, + { "const", NS_KEYWORD, .op = &ignore_attr_op }, + { "__const", NS_KEYWORD, .op = &ignore_attr_op }, + { "__const__", NS_KEYWORD, .op = &ignore_attr_op }, + { "noreturn", NS_KEYWORD, .op = &ignore_attr_op }, + { "__noreturn__", NS_KEYWORD, .op = &ignore_attr_op }, + { "no_instrument_function", NS_KEYWORD, .op = &ignore_attr_op }, + { "__no_instrument_function__", NS_KEYWORD, .op = &ignore_attr_op }, + { "sentinel", NS_KEYWORD, .op = &ignore_attr_op }, + { "__sentinel__", NS_KEYWORD, .op = &ignore_attr_op }, + { "regparm", NS_KEYWORD, .op = &ignore_attr_op }, + { "weak", NS_KEYWORD, .op = &ignore_attr_op }, + { "__weak__", NS_KEYWORD, .op = &ignore_attr_op }, + { "alias", NS_KEYWORD, .op = &ignore_attr_op }, + { "__alias__", NS_KEYWORD, .op = &ignore_attr_op }, + { "pure", NS_KEYWORD, .op = &ignore_attr_op }, + { "__pure__", NS_KEYWORD, .op = &ignore_attr_op }, + { "always_inline", NS_KEYWORD, .op = &ignore_attr_op }, + { "syscall_linkage", NS_KEYWORD, .op = &ignore_attr_op }, + { "visibility", NS_KEYWORD, .op = &ignore_attr_op }, + { "__visibility__", NS_KEYWORD, .op = &ignore_attr_op }, + { "deprecated", NS_KEYWORD, .op = &ignore_attr_op }, + { "__deprecated__", NS_KEYWORD, .op = &ignore_attr_op }, + { "noinline", NS_KEYWORD, .op = &ignore_attr_op }, + { "__used__", NS_KEYWORD, .op = &ignore_attr_op }, + { "warn_unused_result", NS_KEYWORD, .op = &ignore_attr_op }, + { "__warn_unused_result__", NS_KEYWORD, .op = &ignore_attr_op }, + { "model", NS_KEYWORD, .op = &ignore_attr_op }, + { "__model__", NS_KEYWORD, .op = &ignore_attr_op }, }; void init_parser(int stream) @@ -621,180 +741,124 @@ static struct token *typeof_specifier(st return expect(token, ')', "after typeof"); } -static const char * handle_attribute(struct ctype *ctype, struct ident *attribute, struct expression *expr) +static struct token *ignore_attribute(struct token *token, struct symbol *attr, struct ctype *ctype) { - if (attribute == &packed_ident || - attribute == &__packed___ident) { - ctype->alignment = 1; - return NULL; - } - if (attribute == &aligned_ident || - attribute == &__aligned___ident) { - int alignment = max_alignment; + struct expression *expr = NULL; + if (match_op(token, '(')) + token = parens_expression(token, &expr, "in attribute"); + return token; +} + +static struct token *attribute_packed(struct token *token, struct symbol *attr, struct ctype *ctype) +{ + ctype->alignment = 1; + return token; +} + +static struct token *attribute_aligned(struct token *token, struct symbol *attr, struct ctype *ctype) +{ + int alignment = max_alignment; + struct expression *expr = NULL; + + if (match_op(token, '(')) { + token = parens_expression(token, &expr, "in attribute"); if (expr) alignment = get_expression_value(expr); - ctype->alignment = alignment; - return NULL; } - if (attribute == &nocast_ident) { - ctype->modifiers |= MOD_NOCAST; - return NULL; - } - if (attribute == &noderef_ident) { - ctype->modifiers |= MOD_NODEREF; - return NULL; - } - if (attribute == &safe_ident) { - ctype->modifiers |= MOD_SAFE; - return NULL; - } - if (attribute == &force_ident) { - ctype->modifiers |= MOD_FORCE; - return NULL; - } - if (attribute == &bitwise_ident || - attribute == &__bitwise___ident) { - if (Wbitwise) - ctype->modifiers |= MOD_BITWISE; - return NULL; - } - if (attribute == &address_space_ident) { - if (!expr) - return "expected address space number"; + ctype->alignment = alignment; + return token; +} + +static struct token *attribute_modifier(struct token *token, struct symbol *attr, struct ctype *ctype) +{ + ctype->modifiers |= attr->ctype.modifiers; + return token; +} + +static struct token *attribute_address_space(struct token *token, struct symbol *attr, struct ctype *ctype) +{ + struct expression *expr = NULL; + token = expect(token, '(', "after address_space attribute"); + token = conditional_expression(token, &expr); + if (expr) ctype->as = get_expression_value(expr); - return NULL; - } - if (attribute == &context_ident) { - if (expr && expr->type == EXPR_COMMA) { - struct context *context = alloc_context(); - if(expr->left->type == EXPR_COMMA) { - context->context = expr->left->left; - context->in = get_expression_value( - expr->left->right); - } else { - context->context = NULL; - context->in = get_expression_value(expr->left); - } - context->out = get_expression_value(expr->right); - add_ptr_list(&ctype->contexts, context); - return NULL; - } - return "expected context input/output values"; - } - if (attribute == &mode_ident || - attribute == &__mode___ident) { - if (expr && expr->type == EXPR_SYMBOL) { - struct ident *ident = expr->symbol_name; + token = expect(token, ')', "after address_space attribute"); + return token; +} - /* - * Match against __QI__/__HI__/__SI__/__DI__ - * - * FIXME! This is broken - we don't actually get - * the type information updated properly at this - * stage for some reason. - */ - if (ident == &__QI___ident || - ident == &QI_ident) { - ctype->modifiers |= MOD_CHAR; - return NULL; - } - if (ident == &__HI___ident || - ident == &HI_ident) { - ctype->modifiers |= MOD_SHORT; - return NULL; - } - if (ident == &__SI___ident || - ident == &SI_ident) { - /* Nothing? */ - return NULL; - } - if (ident == &__DI___ident || - ident == &DI_ident) { - ctype->modifiers |= MOD_LONGLONG; - return NULL; - } - if (ident == &__word___ident || - ident == &word_ident) { - ctype->modifiers |= MOD_LONG; - return NULL; - } - return "unknown mode attribute"; +static struct token *attribute_mode(struct token *token, struct symbol *attr, struct ctype *ctype) +{ + token = expect(token, '(', "after mode attribute"); + if (token_type(token) == TOKEN_IDENT) { + struct symbol *mode = lookup_keyword(token->ident, NS_KEYWORD); + if (mode && mode->op->type == KW_MODE) + ctype->modifiers |= mode->ctype.modifiers; + else + sparse_error(token->pos, "unknown mode attribute %s\n", show_ident(token->ident)); + token = token->next; + } else + sparse_error(token->pos, "expect attribute mode symbol\n"); + token = expect(token, ')', "after mode attribute"); + return token; +} + +static struct token *attribute_context(struct token *token, struct symbol *attr, struct ctype *ctype) +{ + struct context *context = alloc_context(); + int argc = 0; + + token = expect(token, '(', "after context attribute"); + while (!match_op(token, ')')) { + struct expression *expr = NULL; + token = conditional_expression(token, &expr); + if (!expr) + break; + switch(++argc) { + case 1: + context->context = expr; + break; + case 2: + context->in = get_expression_value(expr); + break; + case 3: + context->out = get_expression_value(expr); + break; } - return "expected attribute mode symbol"; + if (!match_op(token, ',')) + break; + token = token->next; } - - /* Throw away for now.. */ - if (attribute == &__transparent_union___ident) { - if (Wtransparent_union) - return "ignoring attribute __transparent_union__"; - return NULL; + + if (argc == 1) { + context->in = get_expression_value(context->context); + context->context = NULL; } - if (attribute == ¬hrow_ident || - attribute == &__nothrow_ident || - attribute == &__nothrow___ident) - return NULL; - if (attribute == &__malloc___ident) - return NULL; - if (attribute == &nonnull_ident || - attribute == &__nonnull_ident || - attribute == &__nonnull___ident) - return NULL; - if (attribute == &format_ident || - attribute == &__format___ident || - attribute == &__format_arg___ident) - return NULL; - if (attribute == §ion_ident || - attribute == &__section___ident) - return NULL; - if (attribute == &unused_ident || - attribute == &__unused___ident) - return NULL; - if (attribute == &const_ident || - attribute == &__const_ident || - attribute == &__const___ident) - return NULL; - if (attribute == &noreturn_ident || - attribute == &__noreturn___ident) - return NULL; - if (attribute == &no_instrument_function_ident || - attribute == &__no_instrument_function___ident) - return NULL; - if (attribute == &sentinel_ident || - attribute == &__sentinel___ident) - return NULL; - if (attribute == ®parm_ident) - return NULL; - if (attribute == &weak_ident || - attribute == &__weak___ident) - return NULL; - if (attribute == &alias_ident || - attribute == &__alias___ident) - return NULL; - if (attribute == &pure_ident || - attribute == &__pure___ident) - return NULL; - if (attribute == &always_inline_ident) - return NULL; - if (attribute == &syscall_linkage_ident) - return NULL; - if (attribute == &visibility_ident || - attribute == &__visibility___ident) - return NULL; - if (attribute == &deprecated_ident || - attribute == &__deprecated___ident) - return NULL; - if (attribute == &noinline_ident) - return NULL; - if (attribute == &__used___ident) - return NULL; - if (attribute == &warn_unused_result_ident || - attribute == &__warn_unused_result___ident) - return NULL; - if (attribute == &model_ident || - attribute == &__model___ident) - return NULL; - return "unknown attribute"; + if (argc) + add_ptr_list(&ctype->contexts, context); + else + sparse_error(token->pos, "expected context input/output values"); + + token = expect(token, ')', "after context attribute"); + return token; +} + +static struct token *attribute_transparent_union(struct token *token, struct symbol *attr, struct ctype *ctype) +{ + if (Wtransparent_union) + sparse_error(token->pos, "ignoring attribute __transparent_union__"); + return token; +} + +static struct token *recover_unknown_attribute(struct token *token) +{ + struct expression *expr = NULL; + + sparse_error(token->pos, "attribute '%s': unknown attribute", show_ident(token->ident)); + token = token->next; + if (match_op(token, '(')) + token = parens_expression(token, &expr, "in attribute"); + return token; } static struct token *attribute_specifier(struct token *token, struct ctype *ctype) @@ -804,9 +868,8 @@ static struct token *attribute_specifier token = expect(token, '(', "after attribute"); for (;;) { - const char *error_str; struct ident *attribute_name; - struct expression *attribute_expr; + struct symbol *attr; if (eof_token(token)) break; @@ -815,13 +878,12 @@ static struct token *attribute_specifier if (token_type(token) != TOKEN_IDENT) break; attribute_name = token->ident; - token = token->next; - attribute_expr = NULL; - if (match_op(token, '(')) - token = parens_expression(token, &attribute_expr, "in attribute"); - error_str = handle_attribute(ctype, attribute_name, attribute_expr); - if (error_str) - sparse_error(token->pos, "attribute '%s': %s", show_ident(attribute_name), error_str); + attr = lookup_keyword(attribute_name, NS_KEYWORD); + if (attr && attr->op->attribute) + token = attr->op->attribute(token->next, attr, ctype); + else + token = recover_unknown_attribute(token); + if (!match_op(token, ',')) break; token = token->next; @@ -1030,23 +1092,18 @@ static struct token *declarator(struct t static struct token *handle_attributes(struct token *token, struct ctype *ctype) { + struct symbol *keyword; for (;;) { + struct ctype thistype = { 0, }; if (token_type(token) != TOKEN_IDENT) break; - if (match_idents(token, &__attribute___ident, &__attribute_ident, NULL)) { - struct ctype thistype = { 0, }; - token = attribute_specifier(token->next, &thistype); - apply_ctype(token->pos, &thistype, ctype); - continue; - } - if (match_idents(token, &asm_ident, &__asm_ident, &__asm___ident, NULL)) { - struct expression *expr; - token = expect(token->next, '(', "after asm"); - token = parse_expression(token->next, &expr); - token = expect(token, ')', "after asm"); - continue; - } - break; + keyword = lookup_keyword(token->ident, NS_KEYWORD | NS_TYPEDEF); + if (!keyword || keyword->type != SYM_KEYWORD) + break; + if (!(keyword->op->type & (KW_ATTRIBUTE | KW_ASM))) + break; + token = keyword->op->declarator(token->next, &thistype); + apply_ctype(token->pos, &thistype, ctype); } return token; } @@ -1294,7 +1351,7 @@ static struct token *parse_asm_clobbers( return token; } -static struct token *parse_asm(struct token *token, struct statement *stmt) +static struct token *parse_asm_statement(struct token *token, struct statement *stmt) { token = token->next; stmt->type = STMT_ASM; @@ -1313,6 +1370,15 @@ static struct token *parse_asm(struct to return expect(token, ';', "at end of asm-statement"); } +static struct token *parse_asm_declarator(struct token *token, struct ctype *ctype) +{ + struct expression *expr; + token = expect(token, '(', "after asm"); + token = parse_expression(token->next, &expr); + token = expect(token, ')', "after asm"); + return token; +} + /* Make a statement out of an expression */ static struct statement *make_statement(struct expression *expr) { @@ -1964,7 +2030,7 @@ static struct token *toplevel_asm_declar stmt = alloc_statement(token->pos, STMT_NONE); fn->stmt = stmt; - token = parse_asm(token, stmt); + token = parse_asm_statement(token, stmt); add_symbol(list, anon); return token; Index: sparse/symbol.h =================================================================== --- sparse.orig/symbol.h 2007-03-07 01:18:31.000000000 -0800 +++ sparse/symbol.h 2007-03-07 01:18:31.000000000 -0800 @@ -65,6 +65,8 @@ enum keyword { KW_ATTRIBUTE = 1 << 3, KW_TYPEOF = 1 << 4, KW_STATEMENT = 1 << 5, + KW_ASM = 1 << 6, + KW_MODE = 1 << 7, }; struct context { @@ -94,6 +96,7 @@ struct symbol_op { struct token *(*declarator)(struct token *token, struct ctype *ctype); struct token *(*statement)(struct token *token, struct statement *stmt); struct token *(*toplevel)(struct token *token, struct symbol_list **list); + struct token *(*attribute)(struct token *token, struct symbol *attr, struct ctype *ctype); }; extern int expand_safe_p(struct expression *expr, int cost); Index: sparse/lib.c =================================================================== Index: sparse/ident-list.h =================================================================== - To unsubscribe from this list: send the line "unsubscribe linux-sparse" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html