Introduce keyword driven attribute parsing
Christopher Li
maintainerPATCH 5/5 Introduce keyword driven attribute parsing
Now we are really parsing the attribute rather than build the expression tree first.
Signed-off-by Christopher Li <[email protected]>
Index: sparse/parse.h
===================================================================
Index: sparse/symbol.c
===================================================================
parse.c +259 -193
@@ -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(streturn 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_specifierif (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 tstatic 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 toreturn 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;
symbol.h +3 -0
@@ -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
===================================================================