From 5b68086fd32ceb374e5b0efbaaa802ec512c3e1b Mon Sep 17 00:00:00 2001
From: Ting-Wei Lan <lantw44@gmail.com>
Date: Thu, 31 Dec 2015 14:14:31 +0800
Subject: Generate fp offsets for local variables

---
 src/code-generation.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 99 insertions(+), 1 deletion(-)

(limited to 'src/code-generation.c')

diff --git a/src/code-generation.c b/src/code-generation.c
index bba70c9..8d3a44d 100644
--- a/src/code-generation.c
+++ b/src/code-generation.c
@@ -5,6 +5,7 @@
 #include "code-generation.h"
 
 #include <assert.h>
+#include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
 
@@ -68,8 +69,105 @@ static void generate_global_variable(CcmmcAst *global_decl, CcmmcState *state)
     }
 }
 
-static void generate_function(CcmmcAst *funcion, CcmmcState *state)
+static void generate_block(
+    CcmmcAst *block, CcmmcState *state, uint64_t current_offset);
+static uint64_t generate_statement(
+    CcmmcAst *stmt, CcmmcState *state, uint64_t current_offset)
 {
+    if (stmt->type_node == CCMMC_AST_NODE_NUL)
+        return current_offset;
+    if (stmt->type_node == CCMMC_AST_NODE_BLOCK) {
+        generate_block(stmt, state, current_offset);
+        return current_offset;
+    }
+
+    assert(stmt->type_node == CCMMC_AST_NODE_STMT);
+    switch(stmt->value_stmt.kind) {
+        case CCMMC_KIND_STMT_WHILE:
+            current_offset = generate_statement(stmt->child->right_sibling,
+                state, current_offset);
+            break;
+        case CCMMC_KIND_STMT_FOR:
+            break;
+        case CCMMC_KIND_STMT_ASSIGN:
+            break;
+        case CCMMC_KIND_STMT_IF:
+            current_offset = generate_statement(stmt->child->right_sibling,
+                state, current_offset);
+            break;
+        case CCMMC_KIND_STMT_FUNCTION_CALL:
+            break;
+        case CCMMC_KIND_STMT_RETURN:
+            break;
+        default:
+            assert(false);
+    }
+
+    return current_offset;
+}
+
+static uint64_t generate_local_variable(
+    CcmmcAst *local_decl, CcmmcState *state, uint64_t current_offset)
+{
+    for (CcmmcAst *var_decl = local_decl->child->right_sibling;
+         var_decl != NULL; var_decl = var_decl->right_sibling) {
+        CcmmcSymbol *var_sym = ccmmc_symbol_table_retrieve(state->table,
+            var_decl->value_id.name);
+        switch (var_decl->value_id.kind) {
+            case CCMMC_KIND_ID_NORMAL:
+                current_offset += 4;
+                var_sym->attr.addr = current_offset;
+                break;
+            case CCMMC_KIND_ID_ARRAY: {
+                size_t total_elements = 1;
+                assert(var_sym->type.array_dimension > 0);
+                for (size_t i = 0; i < var_sym->type.array_dimension; i++)
+                    total_elements *= var_sym->type.array_size[i];
+                current_offset += total_elements * 4;
+                var_sym->attr.addr = current_offset;
+                } break;
+            case CCMMC_KIND_ID_WITH_INIT: {
+                current_offset += 4;
+                var_sym->attr.addr = current_offset;
+                } break;
+            default:
+                assert(false);
+        }
+    }
+    return current_offset;
+}
+
+static void generate_block(
+    CcmmcAst *block, CcmmcState *state, uint64_t current_offset)
+{
+    ccmmc_symbol_table_reopen_scope(state->table);
+
+    CcmmcAst *child = block->child;
+    uint64_t orig_offset = current_offset;
+    if (child != NULL && child->type_node == CCMMC_AST_NODE_VARIABLE_DECL_LIST) {
+        for (CcmmcAst *local = child->child; local != NULL; local = local->right_sibling)
+            current_offset = generate_local_variable(local, state, current_offset);
+        fprintf(state->asm_output,
+            "\tsub\tsp, sp, #%" PRIu64 "\n", current_offset - orig_offset);
+        child = child->right_sibling;
+    }
+    if (child != NULL && child->type_node == CCMMC_AST_NODE_STMT_LIST) {
+        for (CcmmcAst *stmt = child->child; stmt != NULL; stmt = stmt->right_sibling)
+            current_offset = generate_statement(stmt, state, current_offset);
+    }
+    if (current_offset != orig_offset)
+        fprintf(state->asm_output,
+            "\tadd\tsp, sp, #%" PRIu64 "\n", current_offset - orig_offset);
+
+    ccmmc_symbol_table_close_scope(state->table);
+}
+
+static void generate_function(CcmmcAst *function, CcmmcState *state)
+{
+    fputs("\t.text\n\t.align\t2\n", state->asm_output);
+    CcmmcAst *param_node = function->child->right_sibling->right_sibling;
+    CcmmcAst *block_node = param_node->right_sibling;
+    generate_block(block_node, state, 0);
 }
 
 static void generate_program(CcmmcState *state)
-- 
cgit