add parsing of asm statements, avoid some statement casts
authorMatthias Braun <matze@braunis.de>
Tue, 27 Nov 2007 23:20:36 +0000 (23:20 +0000)
committerMatthias Braun <matze@braunis.de>
Tue, 27 Nov 2007 23:20:36 +0000 (23:20 +0000)
[r18560]

ast.c
ast.h
ast2firm.c
ast_t.h
parser.c
tokens.inc

diff --git a/ast.c b/ast.c
index e109754..8515e93 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -41,11 +41,10 @@ static void print_const(const const_expression_t *cnst)
        }
 }
 
-static void print_string_literal(
-               const string_literal_expression_t *string_literal)
+static void print_quoted_string(const char *string)
 {
        fputc('"', out);
-       for(const char *c = string_literal->value; *c != '\0'; ++c) {
+       for(const char *c = string; *c != '\0'; ++c) {
                switch(*c) {
                case '\"':  fputs("\\\"", out); break;
                case '\\':  fputs("\\\\", out); break;
@@ -69,6 +68,12 @@ static void print_string_literal(
        fputc('"', out);
 }
 
+static void print_string_literal(
+               const string_literal_expression_t *string_literal)
+{
+       print_quoted_string(string_literal->value);
+}
+
 static void print_call_expression(const call_expression_t *call)
 {
        print_expression(call->function);
@@ -454,23 +459,80 @@ static void print_for_statement(const for_statement_t *statement)
        print_statement(statement->body);
 }
 
+static void print_asm_constraints(asm_constraint_t *constraints)
+{
+       asm_constraint_t *constraint = constraints;
+       for( ; constraint != NULL; constraint = constraint->next) {
+               if(constraint != constraints)
+                       fputs(", ", out);
+
+               if(constraint->symbol) {
+                       fprintf(out, "[%s] ", constraint->symbol->string);
+               }
+               print_quoted_string(constraint->constraints);
+               fputs(" (", out);
+               print_expression(constraint->expression);
+               fputs(")", out);
+       }
+}
+
+static void print_asm_clobbers(asm_clobber_t *clobbers)
+{
+       asm_clobber_t *clobber = clobbers;
+       for( ; clobber != NULL; clobber = clobber->next) {
+               if(clobber != clobbers)
+                       fputs(", ", out);
+
+               print_quoted_string(clobber->clobber);
+       }
+}
+
+static void print_asm_statement(const asm_statement_t *statement)
+{
+       fputs("asm", out);
+       if(statement->is_volatile) {
+               fputs(" volatile", out);
+       }
+       fputs("(", out);
+       print_quoted_string(statement->asm_text);
+       if(statement->inputs == NULL && statement->outputs == NULL
+                       && statement->clobbers == NULL)
+               goto end_of_print_asm_statement;
+
+       fputs(" : ", out);
+       print_asm_constraints(statement->inputs);
+       if(statement->outputs == NULL && statement->clobbers == NULL)
+               goto end_of_print_asm_statement;
+
+       fputs(": ", out);
+       print_asm_constraints(statement->outputs);
+       if(statement->clobbers == NULL)
+               goto end_of_print_asm_statement;
+
+       fputs(": ", out);
+       print_asm_clobbers(statement->clobbers);
+
+end_of_print_asm_statement:
+       fputs(");\n", out);
+}
+
 void print_statement(const statement_t *statement)
 {
        switch(statement->type) {
        case STATEMENT_COMPOUND:
-               print_compound_statement((const compound_statement_t*) statement);
+               print_compound_statement(&statement->compound);
                break;
        case STATEMENT_RETURN:
-               print_return_statement((const return_statement_t*) statement);
+               print_return_statement(&statement->returns);
                break;
        case STATEMENT_EXPRESSION:
-               print_expression_statement((const expression_statement_t*) statement);
+               print_expression_statement(&statement->expression);
                break;
        case STATEMENT_LABEL:
-               print_label_statement((const label_statement_t*) statement);
+               print_label_statement(&statement->label);
                break;
        case STATEMENT_GOTO:
-               print_goto_statement((const goto_statement_t*) statement);
+               print_goto_statement(&statement->gotos);
                break;
        case STATEMENT_CONTINUE:
                fputs("continue;\n", out);
@@ -479,25 +541,28 @@ void print_statement(const statement_t *statement)
                fputs("break;\n", out);
                break;
        case STATEMENT_IF:
-               print_if_statement((const if_statement_t*) statement);
+               print_if_statement(&statement->ifs);
                break;
        case STATEMENT_SWITCH:
-               print_switch_statement((const switch_statement_t*) statement);
+               print_switch_statement(&statement->switchs);
                break;
        case STATEMENT_CASE_LABEL:
-               print_case_label((const case_label_statement_t*) statement);
+               print_case_label(&statement->case_label);
                break;
        case STATEMENT_DECLARATION:
-               print_declaration_statement((const declaration_statement_t*) statement);
+               print_declaration_statement(&statement->declaration);
                break;
        case STATEMENT_WHILE:
-               print_while_statement((const while_statement_t*) statement);
+               print_while_statement(&statement->whiles);
                break;
        case STATEMENT_DO_WHILE:
-               print_do_while_statement((const do_while_statement_t*) statement);
+               print_do_while_statement(&statement->do_while);
                break;
        case STATEMENT_FOR:
-               print_for_statement((const for_statement_t*) statement);
+               print_for_statement(&statement->fors);
+               break;
+       case STATEMENT_ASM:
+               print_asm_statement(&statement->asms);
                break;
        case STATEMENT_INVALID:
                fprintf(out, "*invalid statement*");
@@ -546,11 +611,11 @@ void print_initializer(const initializer_t *initializer)
 static void print_normal_declaration(const declaration_t *declaration)
 {
        print_storage_class(declaration->storage_class);
-       print_type_ext(declaration->type, declaration->symbol,
-                      &declaration->context);
        if(declaration->is_inline) {
                fputs("inline ", out);
        }
+       print_type_ext(declaration->type, declaration->symbol,
+                      &declaration->context);
 
        if(declaration->type->type == TYPE_FUNCTION) {
                if(declaration->init.statement != NULL) {
diff --git a/ast.h b/ast.h
index 2d95cc7..ad83e5f 100644 (file)
--- a/ast.h
+++ b/ast.h
@@ -50,6 +50,9 @@ typedef struct case_label_statement_t       case_label_statement_t;
 typedef struct while_statement_t            while_statement_t;
 typedef struct do_while_statement_t         do_while_statement_t;
 typedef struct for_statement_t              for_statement_t;
+typedef struct asm_constraint_t             asm_constraint_t;
+typedef struct asm_clobber_t                asm_clobber_t;
+typedef struct asm_statement_t              asm_statement_t;
 typedef union  statement_t                  statement_t;
 
 typedef struct translation_unit_t           translation_unit_t;
index ba2f523..b5f38db 100644 (file)
@@ -2614,6 +2614,8 @@ static void goto_to_firm(const goto_statement_t *statement)
 static void statement_to_firm(statement_t *statement)
 {
        switch(statement->type) {
+       case STATEMENT_INVALID:
+               panic("invalid statement found");
        case STATEMENT_COMPOUND:
                compound_statement_to_firm((compound_statement_t*) statement);
                return;
@@ -2656,7 +2658,7 @@ static void statement_to_firm(statement_t *statement)
        case STATEMENT_GOTO:
                goto_to_firm((goto_statement_t*) statement);
                return;
-       default:
+       case STATEMENT_ASM:
                break;
        }
        panic("Statement not implemented\n");
@@ -2745,6 +2747,7 @@ static int count_decls_in_stmts(const statement_t *stmt)
                                break;
                        }
 
+                       case STATEMENT_ASM:
                        case STATEMENT_BREAK:
                        case STATEMENT_CASE_LABEL:
                        case STATEMENT_CONTINUE:
diff --git a/ast_t.h b/ast_t.h
index 6a61564..3314400 100644 (file)
--- a/ast_t.h
+++ b/ast_t.h
@@ -320,7 +320,8 @@ typedef enum {
        STATEMENT_CASE_LABEL,
        STATEMENT_WHILE,
        STATEMENT_DO_WHILE,
-       STATEMENT_FOR
+       STATEMENT_FOR,
+       STATEMENT_ASM
 } statement_type_t;
 
 struct statement_base_t {
@@ -402,6 +403,27 @@ struct for_statement_t {
        context_t         context;
 };
 
+struct asm_constraint_t {
+       const char       *constraints;
+       expression_t     *expression;
+       symbol_t         *symbol;
+       asm_constraint_t *next;
+};
+
+struct asm_clobber_t {
+       const char    *clobber;
+       asm_clobber_t *next;
+};
+
+struct asm_statement_t {
+       statement_base_t  statement;
+       const char       *asm_text;
+       asm_constraint_t *inputs;
+       asm_constraint_t *outputs;
+       asm_clobber_t    *clobbers;
+       bool              is_volatile;
+};
+
 union statement_t {
        statement_type_t         type;
        statement_base_t         base;
@@ -417,6 +439,7 @@ union statement_t {
        while_statement_t        whiles;
        do_while_statement_t     do_while;
        for_statement_t          fors;
+       asm_statement_t          asms;
 };
 
 struct translation_unit_t {
index db94826..6e3c44b 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -112,6 +112,41 @@ static void *allocate_ast_zero(size_t size)
        return res;
 }
 
+static size_t get_statement_struct_size(statement_type_t type)
+{
+       static const size_t sizes[] = {
+               [STATEMENT_COMPOUND]    = sizeof(compound_statement_t),
+               [STATEMENT_RETURN]      = sizeof(return_statement_t),
+               [STATEMENT_DECLARATION] = sizeof(declaration_statement_t),
+               [STATEMENT_IF]          = sizeof(if_statement_t),
+               [STATEMENT_SWITCH]      = sizeof(switch_statement_t),
+               [STATEMENT_EXPRESSION]  = sizeof(expression_statement_t),
+               [STATEMENT_CONTINUE]    = sizeof(statement_base_t),
+               [STATEMENT_BREAK]       = sizeof(statement_base_t),
+               [STATEMENT_GOTO]        = sizeof(goto_statement_t),
+               [STATEMENT_LABEL]       = sizeof(label_statement_t),
+               [STATEMENT_CASE_LABEL]  = sizeof(case_label_statement_t),
+               [STATEMENT_WHILE]       = sizeof(while_statement_t),
+               [STATEMENT_DO_WHILE]    = sizeof(do_while_statement_t),
+               [STATEMENT_FOR]         = sizeof(for_statement_t),
+               [STATEMENT_ASM]         = sizeof(asm_statement_t)
+       };
+       assert(sizeof(sizes) / sizeof(sizes[0]) == STATEMENT_ASM + 1);
+       assert(type <= STATEMENT_ASM);
+       assert(sizes[type] != 0);
+       return sizes[type];
+}
+
+static statement_t *allocate_statement_zero(statement_type_t type)
+{
+       size_t       size = get_statement_struct_size(type);
+       statement_t *res  = allocate_ast_zero(size);
+
+       res->base.type = type;
+       return res;
+}
+
+
 static size_t get_expression_struct_size(expression_type_t type)
 {
        static const size_t sizes[] = {
@@ -4108,6 +4143,109 @@ static void init_expression_parsers(void)
                                                     T___builtin_classify_type, 25);
 }
 
+static asm_constraint_t *parse_asm_constraints(void)
+{
+       asm_constraint_t *result = NULL;
+       asm_constraint_t *last   = NULL;
+
+       while(token.type == T_STRING_LITERAL || token.type == '[') {
+               asm_constraint_t *constraint = allocate_ast_zero(sizeof(constraint[0]));
+               memset(constraint, 0, sizeof(constraint[0]));
+
+               if(token.type == '[') {
+                       eat('[');
+                       if(token.type != T_IDENTIFIER) {
+                               parse_error_expected("while parsing asm constraint",
+                                                    T_IDENTIFIER, 0);
+                               return NULL;
+                       }
+                       constraint->symbol = token.v.symbol;
+
+                       expect(']');
+               }
+
+               constraint->constraints = parse_string_literals();
+               expect('(');
+               constraint->expression = parse_expression();
+               expect(')');
+
+               if(last != NULL) {
+                       last->next = constraint;
+               } else {
+                       result = constraint;
+               }
+               last = constraint;
+
+               if(token.type != ',')
+                       break;
+               eat(',');
+       }
+
+       return result;
+}
+
+static asm_clobber_t *parse_asm_clobbers(void)
+{
+       asm_clobber_t *result = NULL;
+       asm_clobber_t *last   = NULL;
+
+       while(token.type == T_STRING_LITERAL) {
+               asm_clobber_t *clobber = allocate_ast_zero(sizeof(clobber[0]));
+               clobber->clobber       = parse_string_literals();
+
+               if(last != NULL) {
+                       last->next = clobber;
+               } else {
+                       result = clobber;
+               }
+               last = clobber;
+
+               if(token.type != ',')
+                       break;
+               eat(',');
+       }
+
+       return result;
+}
+
+static statement_t *parse_asm_statement(void)
+{
+       eat(T_asm);
+
+       statement_t *statement          = allocate_statement_zero(STATEMENT_ASM);
+       statement->base.source_position = token.source_position;
+
+       asm_statement_t *asm_statement = &statement->asms;
+
+       if(token.type == T_volatile) {
+               next_token();
+               asm_statement->is_volatile = true;
+       }
+
+       expect('(');
+       asm_statement->asm_text = parse_string_literals();
+
+       if(token.type != ':')
+               goto end_of_asm;
+       eat(':');
+
+       asm_statement->inputs = parse_asm_constraints();
+       if(token.type != ':')
+               goto end_of_asm;
+       eat(':');
+
+       asm_statement->outputs = parse_asm_constraints();
+       if(token.type != ':')
+               goto end_of_asm;
+       eat(':');
+
+       asm_statement->clobbers = parse_asm_clobbers();
+
+end_of_asm:
+       expect(')');
+       expect(';');
+       return statement;
+}
 
 static statement_t *parse_case_statement(void)
 {
@@ -4455,6 +4593,10 @@ static statement_t *parse_statement(void)
 
        /* declaration or statement */
        switch(token.type) {
+       case T_asm:
+               statement = parse_asm_statement();
+               break;
+
        case T_case:
                statement = parse_case_statement();
                break;
index 3090976..7288ba0 100644 (file)
@@ -37,7 +37,6 @@ S(typedef)
 S(union)
 S(unsigned)
 S(void)
-S(volatile)
 S(while)
 S(_Bool)
 S(_Complex)
@@ -68,6 +67,8 @@ T(restrict,         "__restrict",)
 T(_restrict,          "restrict", = T_restrict)
 T(asm,                     "asm",)
 T(__asm__,             "__asm__", = T_asm)
+T(volatile,           "volatile",)
+T(__volatile__,   "__volatile__", = T_volatile)
 T(inline,               "inline",)
 T(__inline,           "__inline", = T_inline)
 T(__inline__,       "__inline__", = T_inline)