From 7528b6f9851936926b69a2e1604723cbefc102aa Mon Sep 17 00:00:00 2001
From: Loup Lobet <loup@darkstar.darkstar>
Date: Sun, 7 Jan 2024 18:31:04 +0100
Subject: [PATCH] Lab 7

---
 code/remaining/codegen.cc | 1082 ++++++++++++++++++++-----------------
 1 file changed, 599 insertions(+), 483 deletions(-)

diff --git a/code/remaining/codegen.cc b/code/remaining/codegen.cc
index 6eddcad..7711014 100755
--- a/code/remaining/codegen.cc
+++ b/code/remaining/codegen.cc
@@ -20,20 +20,20 @@ code_generator *code_gen = new code_generator("d.out");
 // Constructor.
 code_generator::code_generator(const string object_file_name)
 {
-    out.open(object_file_name);
+	out.open(object_file_name);
 
-    reg[RAX] = "rax";
-    reg[RCX] = "rcx";
-    reg[RDX] = "rdx";
+	reg[RAX] = "rax";
+	reg[RCX] = "rcx";
+	reg[RDX] = "rdx";
 }
 
 
 /* Destructor. */
 code_generator::~code_generator()
 {
-    // Make sure we close the outfile before exiting the compiler.
-    out << flush;
-    out.close();
+	// Make sure we close the outfile before exiting the compiler.
+	out << flush;
+	out.close();
 }
 
 
@@ -43,9 +43,9 @@ code_generator::~code_generator()
    the symbol for the environment for which code is being generated. */
 void code_generator::generate_assembler(quad_list *q, symbol *env)
 {
-    prologue(env);
-    expand(q);
-    epilogue(env);
+	prologue(env);
+	expand(q);
+	epilogue(env);
 }
 
 
@@ -54,7 +54,7 @@ void code_generator::generate_assembler(quad_list *q, symbol *env)
  */
 int code_generator::align(int frame_size)
 {
-    return ((frame_size + 7) / 8) * 8;
+	return ((frame_size + 7) / 8) * 8;
 }
 
 
@@ -63,44 +63,53 @@ int code_generator::align(int frame_size)
    function. */
 void code_generator::prologue(symbol *new_env)
 {
-    int ar_size;
-    int label_nr;
-    // Used to count parameters.
-    parameter_symbol *last_arg;
-
-    // Again, we need a safe downcast for a procedure/function.
-    // Note that since we have already generated quads for the entire block
-    // before we expand it to assembler, the size of the activation record
-    // is known here (ar_size).
-    if (new_env->tag == SYM_PROC) {
-        procedure_symbol *proc = new_env->get_procedure_symbol();
-        ar_size = align(proc->ar_size);
-        label_nr = proc->label_nr;
-        last_arg = proc->last_parameter;
-    } else if (new_env->tag == SYM_FUNC) {
-        function_symbol *func = new_env->get_function_symbol();
-        /* Make sure ar_size is a multiple of eight */
-        ar_size = align(func->ar_size);
-        label_nr = func->label_nr;
-        last_arg = func->last_parameter;
-    } else {
-        fatal("code_generator::prologue() called for non-proc/func");
-        return;
-    }
-
-    /* Print out the label number (a SYM_PROC/ SYM_FUNC attribute) */
-    out << "L" << label_nr << ":" << "\t\t\t" << "# " <<
-        /* Print out the function/procedure name */
-        sym_tab->pool_lookup(new_env->id) << endl;
-
-    if (assembler_trace) {
-        out << "\t" << "# PROLOGUE (" << short_symbols << new_env
-            << long_symbols << ")" << endl;
-    }
-
-    /* Your code here */
-
-    out << flush;
+	int ar_size;
+	int label_nr;
+	// Used to count parameters.
+	//parameter_symbol *last_arg;
+
+	block_level level;
+
+	// Again, we need a safe downcast for a procedure/function.
+	// Note that since we have already generated quads for the entire block
+	// before we expand it to assembler, the size of the activation record
+	// is known here (ar_size).
+	if (new_env->tag == SYM_PROC) {
+		procedure_symbol *proc = new_env->get_procedure_symbol();
+		ar_size = align(proc->ar_size);
+		label_nr = proc->label_nr;
+		//last_arg = proc->last_parameter;
+		level = proc->level;
+	} else if (new_env->tag == SYM_FUNC) {
+		function_symbol *func = new_env->get_function_symbol();
+		/* Make sure ar_size is a multiple of eight */
+		ar_size = align(func->ar_size);
+		label_nr = func->label_nr;
+		//last_arg = func->last_parameter;
+		level = func->level;
+	} else {
+		fatal("code_generator::prologue() called for non-proc/func");
+		return;
+	}
+
+	/* Print out the label number (a SYM_PROC/ SYM_FUNC attribute) */
+	out << "L" << label_nr << ":" << "\t\t\t" << "# " <<
+		/* Print out the function/procedure name */
+		sym_tab->pool_lookup(new_env->id) << endl;
+
+	if (assembler_trace) {
+		out << "\t" << "# PROLOGUE (" << short_symbols << new_env
+			<< long_symbols << ")" << endl;
+	}
+
+	out << "\t\t" << "push" << "\t" << "rbp\n";
+	out << "\t\t" << "mov" << "\t" << "rcx, rsp\n";
+	for (int i = 1; i <= level; i++)
+		out << "\t\t" << "push" << "\t" << "[rbp-" << i * STACK_WIDTH << "]\n";
+	out << "\t\t" << "push" << "\t" << "rcx\n";
+	out << "\t\t" << "mov" << "\t" << "rbp, rcx\n";
+	out << "\t\t" << "sub" << "\t" << "rsp, " << ar_size << "\n";
+	out << flush;
 }
 
 
@@ -108,14 +117,12 @@ void code_generator::prologue(symbol *new_env)
 /* This method generates assembler code for leaving a procedure or function. */
 void code_generator::epilogue(symbol *old_env)
 {
-    if (assembler_trace) {
-        out << "\t" << "# EPILOGUE (" << short_symbols << old_env
-            << long_symbols << ")" << endl;
-    }
-
-    /* Your code here */
-
-    out << flush;
+	if (assembler_trace) {
+		out << "\t" << "# EPILOGUE (" << short_symbols << old_env << long_symbols << ")\n";
+	}
+	out << "\t\t" << "leave" << "\t\n";
+	out << "\t\t" << "ret" << "\t\n";
+	out << flush;
 }
 
 
@@ -124,7 +131,16 @@ void code_generator::epilogue(symbol *old_env)
    array or a parameter. Note the pass-by-pointer arguments. */
 void code_generator::find(sym_index sym_p, int *level, int *offset)
 {
-    /* Your code here */
+	sym_type tag;
+	symbol *s;
+
+	s = sym_tab->get_symbol(sym_p);
+	*level = s->level;
+	tag = s->tag;
+	if (tag == SYM_VAR || tag == SYM_ARRAY)
+		*offset = -((*level + 1) * STACK_WIDTH + s->offset);
+	else if (tag == SYM_PARAM)
+		*offset = STACK_WIDTH * 2 + s->offset;
 }
 
 /*
@@ -132,19 +148,76 @@ void code_generator::find(sym_index sym_p, int *level, int *offset)
  */
 void code_generator::frame_address(int level, const register_type dest)
 {
-    /* Your code here */
+	out << "\t\t" << "mov" << "\t" << reg[dest] << ", [rbp-" << level * STACK_WIDTH << "]\n";
 }
 
 /* This function fetches the value of a variable or a constant into a
    register. */
 void code_generator::fetch(sym_index sym_p, register_type dest)
 {
-    /* Your code here */
+	long val;
+	int lvl, offset;
+	constant_symbol *cst;
+	symbol *sym;
+	sym_type tag;
+
+	sym = sym_tab->get_symbol(sym_p);
+	tag = sym->tag;
+	if (tag == SYM_PARAM) {
+		find(sym_p, &lvl, &offset);
+		frame_address(lvl, RCX);
+		out << "\t\t" << "mov" << "\t" << reg[dest] << ", [rcx";
+		if (offset > 0)
+			out << "+" << offset;
+		else if (offset < 0)
+			out << offset;
+		out << "]\n";
+	} else if (tag == SYM_VAR) {
+		find(sym_p, &lvl, &offset);
+		frame_address(lvl, RCX);
+		out << "\t\t" << "mov" << "\t" << reg[dest] << ", [rcx";
+		if (offset > 0)
+			out << "+" << offset;
+		else if (offset < 0)
+			out << offset;
+		out << "]\n";
+	} else if (tag == SYM_CONST) {
+		cst = sym->get_constant_symbol();
+		if (cst->type == real_type)
+			val = sym_tab->ieee(cst->const_value.rval);
+		else
+			val = cst->const_value.ival;
+		out << "\t\t" << "mov" << "\t" << reg[dest] << ", " << val << "\n";
+	}
 }
 
 void code_generator::fetch_float(sym_index sym_p)
 {
-    /* Your code here */
+	sym_type tag;
+	long val;
+	int lvl, offset;
+	constant_symbol *cst;
+	symbol *s;
+
+	s = sym_tab->get_symbol(sym_p);
+	tag = s->tag;
+	if (tag == SYM_CONST) {
+		cst = s->get_constant_symbol();
+		val = sym_tab->ieee(cst->const_value.rval);
+		out << "\t\t" << "mov" << "\t" << "rcx, " << val << "\n";
+		out << "\t\t" << "push" << "\t" << "rcx" << "\n";
+		out << "\t\t" << "fld" << "\t" << "qword ptr [rsp]\n";
+		out << "\t\t" << "add" << "\t" << "rsp, " << STACK_WIDTH << "\n";
+	} else {
+		find(sym_p, &lvl, &offset);
+		frame_address(lvl, RCX);
+		out << "\t\t" << "fld" << "\t" << "qword ptr [rcx";
+		if (offset > 0)
+			out << "+" << offset;
+		else if (offset < 0)
+			out << offset;
+		out << "]\n";
+	}
 }
 
 
@@ -152,441 +225,484 @@ void code_generator::fetch_float(sym_index sym_p)
 /* This function stores the value of a register into a variable. */
 void code_generator::store(register_type src, sym_index sym_p)
 {
-    /* Your code here */
+	int lvl, offset;
+
+	find(sym_p, &lvl, &offset);
+	frame_address(lvl, RCX);
+	out << "\t\t" << "mov" << "\t"  << "[rcx";
+	if (offset < 0)
+		out << offset;
+	else if (offset > 0)
+		out << "+" << offset;
+	out << "], " << reg[src] << "\n" ;
+
 }
 
 void code_generator::store_float(sym_index sym_p)
 {
-    /* Your code here */
+	int lvl, offset;
+
+	find(sym_p, &lvl, &offset);
+	frame_address(lvl, RCX);
+	out << "\t\t" << "fstp" << "\t"  << "qword ptr [rcx";
+	if (offset < 0)
+		out << offset;
+	else if (offset > 0)
+		out << "+" << offset;
+	out << "]\n";
 }
 
 
 /* This function fetches the base address of an array. */
 void code_generator::array_address(sym_index sym_p, register_type dest)
 {
-    /* Your code here */
+	int lvl, offset;
+
+	find(sym_p, &lvl, &offset);
+	frame_address(lvl, RCX);
+	if (offset > 0)
+		out << "\t\t" << "add" << "\t" << "rcx, " << offset << "\n";
+	else
+		out << "\t\t" << "sub" << "\t" << "rcx, " << -offset << "\n";
+	out << "\t\t" << "mov" << "\t" << reg[dest] << ", rcx\n";
+
 }
 
 /* This method expands a quad_list into assembler code, quad for quad. */
 void code_generator::expand(quad_list *q_list)
 {
-    long quad_nr = 0;       // Just to make debug output easier to read.
-    
-
-    // We use this iterator to loop through the quad list.
-    quad_list_iterator *ql_iterator = new quad_list_iterator(q_list);
-
-    quadruple *q = ql_iterator->get_current(); // This is the head of the list.
-
-    while (q != NULL) {
-        quad_nr++;
-
-        // We always do labels here so that a branch doesn't miss the
-        // trace code.
-        if (q->op_code == q_labl) {
-            out << "L" << q->int1 << ":" << endl;
-        }
-
-        // Debug output.
-        if (assembler_trace) {
-            out << "\t" << "# QUAD " << quad_nr << ": "
-                << short_symbols << q << long_symbols << endl;
-        }
-
-        // The main switch on quad type. This is where code is actually
-        // generated.
-        switch (q->op_code) {
-        case q_rload:
-        case q_iload:
-            out << "\t\t" << "mov" << "\t" << "rax, " << q->int1 << endl;
-            store(RAX, q->sym3);
-            break;
-
-        case q_inot: {
-            int label = sym_tab->get_next_label();
-            int label2 = sym_tab->get_next_label();
-
-            fetch(q->sym1, RAX);
-            out << "\t\t" << "cmp" << "\t" << "rax, 0" << endl;
-            out << "\t\t" << "je" << "\t" << "L" << label << endl;
-            // Not equal branch
-            out << "\t\t" << "mov" << "\t" << "rax, 0" << endl;
-            out << "\t\t" << "jmp" << "\t" << "L" << label2 << endl;
-            // Equal branch
-            out << "\t\t" << "L" << label << ":" << endl;
-            out << "\t\t" << "mov" << "\t" << "rax, 1" << endl;
-
-            out << "\t\t" << "L" << label2 << ":" <<  endl;
-            store(RAX, q->sym3);
-            break;
-        }
-        case q_ruminus:
-            fetch_float(q->sym1);
-            out << "\t\t" << "fchs" << endl;
-            store_float(q->sym3);
-            break;
-
-        case q_iuminus:
-            fetch(q->sym1, RAX);
-            out << "\t\t" << "neg" << "\t" << "rax" << endl;
-            store(RAX, q->sym3);
-            break;
-
-        case q_rplus:
-            fetch_float(q->sym1);
-            fetch_float(q->sym2);
-            out << "\t\t" << "faddp" << endl;
-            store_float(q->sym3);
-            break;
-
-        case q_iplus:
-            fetch(q->sym1, RAX);
-            fetch(q->sym2, RCX);
-            out << "\t\t" << "add" << "\t" << "rax, rcx" << endl;
-            store(RAX, q->sym3);
-            break;
-
-        case q_rminus:
-            fetch_float(q->sym1);
-            fetch_float(q->sym2);
-            out << "\t\t" << "fsubp" << endl;
-            store_float(q->sym3);
-            break;
-
-        case q_iminus:
-            fetch(q->sym1, RAX);
-            fetch(q->sym2, RCX);
-            out << "\t\t" << "sub" << "\t" << "rax, rcx" << endl;
-            store(RAX, q->sym3);
-            break;
-
-        case q_ior: {
-            int label = sym_tab->get_next_label();
-            int label2 = sym_tab->get_next_label();
-
-            fetch(q->sym1, RAX);
-            out << "\t\t" << "cmp" << "\t" << "rax, 0" << endl;
-            out << "\t\t" << "jne" << "\t" << "L" << label << endl;
-            fetch(q->sym2, RAX);
-            out << "\t\t" << "cmp" << "\t" << "rax, 0" << endl;
-            out << "\t\t" << "jne" << "\t" << "L" << label << endl;
-            // False branch
-            out << "\t\t" << "mov" << "\t" << "rax, 0" << endl;
-            out << "\t\t" << "jmp" << "\t" << "L" << label2 << endl;
-            // True branch
-            out << "\t\t" << "L" << label << ":" << endl;
-            out << "\t\t" << "mov" << "\t" << "rax, 1" << endl;
-
-            out << "\t\t" << "L" << label2 << ":" << endl;
-            store(RAX, q->sym3);
-            break;
-        }
-        case q_iand: {
-            int label = sym_tab->get_next_label();
-            int label2 = sym_tab->get_next_label();
-
-            fetch(q->sym1, RAX);
-            out << "\t\t" << "cmp" << "\t" << "rax, 0" << endl;
-            out << "\t\t" << "je" << "\t" << "L" << label << endl;
-            fetch(q->sym2, RAX);
-            out << "\t\t" << "cmp" << "\t" << "rax, 0" << endl;
-            out << "\t\t" << "je" << "\t" << "L" << label << endl;
-            // True branch
-            out << "\t\t" << "mov" << "\t" << "rax, 1" << endl;
-            out << "\t\t" << "jmp" << "\t" << "L" << label2 << endl;
-            // False branch
-            out << "\t\t" << "L" << label << ":" << endl;
-            out << "\t\t" << "mov" << "\t" << "rax, 0" << endl;
-
-            out << "\t\t" << "L" << label2 << ":" << endl;
-            store(RAX, q->sym3);
-            break;
-        }
-        case q_rmult:
-            fetch_float(q->sym1);
-            fetch_float(q->sym2);
-            out << "\t\t" << "fmulp" << endl;
-            store_float(q->sym3);
-            break;
-
-        case q_imult:
-            fetch(q->sym1, RAX);
-            fetch(q->sym2, RCX);
-            out << "\t\t" << "imul" << "\t" << "rax, rcx" << endl;
-            store(RAX, q->sym3);
-            break;
-
-        case q_rdivide:
-            fetch_float(q->sym1);
-            fetch_float(q->sym2);
-            out << "\t\t" << "fdivp" << endl;
-            store_float(q->sym3);
-            break;
-
-        case q_idivide:
-            fetch(q->sym1, RAX);
-            fetch(q->sym2, RCX);
-            out << "\t\t" << "cqo" << endl;
-            out << "\t\t" << "idiv" << "\t" << "rax, rcx" << endl;
-            store(RAX, q->sym3);
-            break;
-
-        case q_imod:
-            fetch(q->sym1, RAX);
-            fetch(q->sym2, RCX);
-            out << "\t\t" << "cqo" << endl;
-            out << "\t\t" << "idiv" << "\t" << "rax, rcx" << endl;
-            store(RDX, q->sym3);
-            break;
-
-        case q_req: {
-            int label = sym_tab->get_next_label();
-            int label2 = sym_tab->get_next_label();
-
-            fetch_float(q->sym1);
-            fetch_float(q->sym2);
-            out << "\t\t" << "fcomip" << "\t" << "ST(0), ST(1)" << endl;
-            // Clear the stack
-            out << "\t\t" << "fstp" << "\t" << "ST(0)" << endl;
-            out << "\t\t" << "je" << "\t" << "L" << label << endl;
-            // False branch
-            out << "\t\t" << "mov" << "\t" << "rax, 0" << endl;
-            out << "\t\t" << "jmp" << "\t" << "L" << label2 << endl;
-            // True branch
-            out << "\t\t" << "L" << label << ":" << endl;
-            out << "\t\t" << "mov" << "\t" << "rax, 1" << endl;
-
-            out << "\t\t" << "L" << label2 << ":" << endl;
-            store(RAX, q->sym3);
-            break;
-        }
-        case q_ieq: {
-            int label = sym_tab->get_next_label();
-            int label2 = sym_tab->get_next_label();
-
-            fetch(q->sym1, RAX);
-            fetch(q->sym2, RCX);
-            out << "\t\t" << "cmp" << "\t" << "rax, rcx" << endl;
-            out << "\t\t" << "je" << "\t" << "L" << label << endl;
-            // False branch
-            out << "\t\t" << "mov" << "\t" << "rax, 0" << endl;
-            out << "\t\t" << "jmp" << "\t" << "L" << label2 << endl;
-            // True branch
-            out << "\t\t" << "L" << label << ":" << endl;
-            out << "\t\t" << "mov" << "\t" << "rax, 1" << endl;
-
-            out << "\t\t" << "L" << label2 << ":" << endl;
-            store(RAX, q->sym3);
-            break;
-        }
-        case q_rne: {
-            int label = sym_tab->get_next_label();
-            int label2 = sym_tab->get_next_label();
-
-            fetch_float(q->sym1);
-            fetch_float(q->sym2);
-            out << "\t\t" << "fcomip" << "\t" << "ST(0), ST(1)" << endl;
-            // Clear the stack
-            out << "\t\t" << "fstp" << "\t" << "ST(0)" << endl;
-            out << "\t\t" << "jne" << "\t" << "L" << label << endl;
-            // False branch
-            out << "\t\t" << "mov" << "\t" << "rax, 0" << endl;
-            out << "\t\t" << "jmp" << "\t" << "L" << label2 << endl;
-            // True branch
-            out << "\t\t" << "L" << label << ":" << endl;
-            out << "\t\t" << "mov" << "\t" << "rax, 1" << endl;
-
-            out << "\t\t" << "L" << label2 << ":" << endl;
-            store(RAX, q->sym3);
-            break;
-        }
-        case q_ine: {
-            int label = sym_tab->get_next_label();
-            int label2 = sym_tab->get_next_label();
-
-            fetch(q->sym1, RAX);
-            fetch(q->sym2, RCX);
-            out << "\t\t" << "cmp" << "\t" << "rax, rcx" << endl;
-            out << "\t\t" << "jne" << "\t" << "L" << label << endl;
-            // False branch
-            out << "\t\t" << "mov" << "\t" << "rax, 0" << endl;
-            out << "\t\t" << "jmp" << "\t" << "L" << label2 << endl;
-            // True branch
-            out << "\t\t" << "L" << label << ":" << endl;
-            out << "\t\t" << "mov" << "\t" << "rax, 1" << endl;
-
-            out << "\t\t" << "L" << label2 << ":" << endl;
-            store(RAX, q->sym3);
-            break;
-        }
-        case q_rlt: {
-            int label = sym_tab->get_next_label();
-            int label2 = sym_tab->get_next_label();
-
-            // We need to push in reverse order for this to work
-            fetch_float(q->sym2);
-            fetch_float(q->sym1);
-            out << "\t\t" << "fcomip" << "\t" << "ST(0), ST(1)" << endl;
-            // Clear the stack
-            out << "\t\t" << "fstp" << "\t" << "ST(0)" << endl;
-            out << "\t\t" << "jb" << "\t" << "L" << label << endl;
-            // False branch
-            out << "\t\t" << "mov" << "\t" << "rax, 0" << endl;
-            out << "\t\t" << "jmp" << "\t" << "L" << label2 << endl;
-            // True branch
-            out << "\t\t" << "L" << label << ":" << endl;
-            out << "\t\t" << "mov" << "\t" << "rax, 1" << endl;
-
-            out << "\t\t" << "L" << label2 << ":" << endl;
-            store(RAX, q->sym3);
-            break;
-        }
-        case q_ilt: {
-            int label = sym_tab->get_next_label();
-            int label2 = sym_tab->get_next_label();
-
-            fetch(q->sym1, RAX);
-            fetch(q->sym2, RCX);
-            out << "\t\t" << "cmp" << "\t" << "rax, rcx" << endl;
-            out << "\t\t" << "jl" << "\t" << "L" << label << endl;
-            // False branch
-            out << "\t\t" << "mov" << "\t" << "rax, 0" << endl;
-            out << "\t\t" << "jmp" << "\t" << "L" << label2 << endl;
-            // True branch
-            out << "\t\t" << "L" << label << ":" << endl;
-            out << "\t\t" << "mov" << "\t" << "rax, 1" << endl;
-
-            out << "\t\t" << "L" << label2 << ":" << endl;
-            store(RAX, q->sym3);
-            break;
-        }
-        case q_rgt: {
-            int label = sym_tab->get_next_label();
-            int label2 = sym_tab->get_next_label();
-
-            // We need to push in reverse order for this to work
-            fetch_float(q->sym2);
-            fetch_float(q->sym1);
-            out << "\t\t" << "fcomip" << "\t" << "ST(0), ST(1)" << endl;
-            // Clear the stack
-            out << "\t\t" << "fstp" << "\t" << "ST(0)" << endl;
-            out << "\t\t" << "ja" << "\t" << "L" << label << endl;
-            // False branch
-            out << "\t\t" << "mov" << "\t" << "rax, 0" << endl;
-            out << "\t\t" << "jmp" << "\t" << "L" << label2 << endl;
-            // True branch
-            out << "\t\t" << "L" << label << ":" << endl;
-            out << "\t\t" << "mov" << "\t" << "rax, 1" << endl;
-
-            out << "\t\t" << "L" << label2 << ":" << endl;
-            store(RAX, q->sym3);
-            break;
-        }
-        case q_igt: {
-            int label = sym_tab->get_next_label();
-            int label2 = sym_tab->get_next_label();
-
-            fetch(q->sym1, RAX);
-            fetch(q->sym2, RCX);
-            out << "\t\t" << "cmp" << "\t" << "rax, rcx" << endl;
-            out << "\t\t" << "jg" << "\t" << "L" << label << endl;
-            // False branch
-            out << "\t\t" << "mov" << "\t" << "rax, 0" << endl;
-            out << "\t\t" << "jmp" << "\t" << "L" << label2 << endl;
-            // True branch
-            out << "\t\t" << "L" << label << ":" << endl;
-            out << "\t\t" << "mov" << "\t" << "rax, 1" << endl;
-
-            out << "\t\t" << "L" << label2 << ":" << endl;
-            store(RAX, q->sym3);
-            break;
-        }
-        case q_rstore:
-        case q_istore:
-            fetch(q->sym1, RAX);
-            fetch(q->sym3, RCX);
-            out << "\t\t" << "mov" << "\t" << "[rcx], rax" << endl;
-            break;
-
-        case q_rassign:
-        case q_iassign:
-            fetch(q->sym1, RAX);
-            store(RAX, q->sym3);
-            break;
-
-        case q_param:
-            /* Your code here */
-            break;
-
-        case q_call: {
-            /* Your code here */
-            break;
-        }
-        case q_rreturn:
-        case q_ireturn:
-            fetch(q->sym2, RAX);
-            out << "\t\t" << "jmp" << "\t" << "L" << q->int1 << endl;
-            break;
-
-        case q_lindex:
-            array_address(q->sym1, RAX);
-            fetch(q->sym2, RCX);
-            out << "\t\t" << "imul" << "\t" << "rcx, " << STACK_WIDTH << endl;
-            out << "\t\t" << "sub" << "\t" << "rax, rcx" << endl;
-            store(RAX, q->sym3);
-            break;
-
-        case q_rrindex:
-        case q_irindex:
-            array_address(q->sym1, RAX);
-            fetch(q->sym2, RCX);
-            out << "\t\t" << "imul" << "\t" << "rcx, " << STACK_WIDTH << endl;
-            out << "\t\t" << "sub" << "\t" << "rax, rcx" << endl;
-            out << "\t\t" << "mov" << "\t" << "rax, [rax]" << endl;
-            store(RAX, q->sym3);
-            break;
-
-        case q_itor: {
-            block_level level;      // Current scope level.
-            int offset;             // Offset within current activation record.
-
-            find(q->sym1, &level, &offset);
-            frame_address(level, RCX);
-            out << "\t\t" << "fild" << "\t" << "qword ptr [rcx";
-            if (offset >= 0) {
-                out << "+" << offset;
-            } else {
-                out << offset; // Implicit "-"
-            }
-            out << "]" << endl;
-            store_float(q->sym3);
-        }
-        break;
-
-        case q_jmp:
-            out << "\t\t" << "jmp" << "\t" << "L" << q->int1 << endl;
-            break;
-
-        case q_jmpf:
-            fetch(q->sym2, RAX);
-            out << "\t\t" << "cmp" << "\t" << "rax, 0" << endl;
-            out << "\t\t" << "je" << "\t" << "L" << q->int1 << endl;
-            break;
-
-        case q_labl:
-            // We handled this one above already.
-            break;
-
-        case q_nop:
-            // q_nop quads should never be generated.
-            fatal("code_generator::expand(): q_nop quadruple produced.");
-            return;
-        }
-
-        // Get the next quad from the list.
-        q = ql_iterator->get_next();
-    }
-
-    // Flush the generated code to file.
-    out << flush;
+	long quad_nr = 0;	  // Just to make debug output easier to read.
+	
+
+	// We use this iterator to loop through the quad list.
+	quad_list_iterator *ql_iterator = new quad_list_iterator(q_list);
+
+	quadruple *q = ql_iterator->get_current(); // This is the head of the list.
+
+	while (q != NULL) {
+		quad_nr++;
+
+		// We always do labels here so that a branch doesn't miss the
+		// trace code.
+		if (q->op_code == q_labl) {
+			out<< "L" << q->int1 << ":" << endl;
+		}
+
+		// Debug output.
+		if (assembler_trace) {
+			out<< "\t" << "# QUAD " << quad_nr << ": "
+				<< short_symbols << q << long_symbols << endl;
+		}
+
+		// The main switch on quad type. This is where code is actually
+		// generated.
+		switch (q->op_code) {
+		case q_rload:
+		case q_iload:
+			out<< "\t\t" << "mov" << "\t" << "rax, " << q->int1 << endl;
+			store(RAX, q->sym3);
+			break;
+
+		case q_inot: {
+			int label = sym_tab->get_next_label();
+			int label2 = sym_tab->get_next_label();
+
+			fetch(q->sym1, RAX);
+			out<< "\t\t" << "cmp" << "\t" << "rax, 0" << endl;
+			out<< "\t\t" << "je" << "\t" << "L" << label << endl;
+			// Not equal branch
+			out<< "\t\t" << "mov" << "\t" << "rax, 0" << endl;
+			out<< "\t\t" << "jmp" << "\t" << "L" << label2 << endl;
+			// Equal branch
+			out<< "\t\t" << "L" << label << ":" << endl;
+			out<< "\t\t" << "mov" << "\t" << "rax, 1" << endl;
+
+			out<< "\t\t" << "L" << label2 << ":" <<  endl;
+			store(RAX, q->sym3);
+			break;
+		}
+		case q_ruminus:
+			fetch_float(q->sym1);
+			out<< "\t\t" << "fchs" << endl;
+			store_float(q->sym3);
+			break;
+
+		case q_iuminus:
+			fetch(q->sym1, RAX);
+			out<< "\t\t" << "neg" << "\t" << "rax" << endl;
+			store(RAX, q->sym3);
+			break;
+
+		case q_rplus:
+			fetch_float(q->sym1);
+			fetch_float(q->sym2);
+			out<< "\t\t" << "faddp" << endl;
+			store_float(q->sym3);
+			break;
+
+		case q_iplus:
+			fetch(q->sym1, RAX);
+			fetch(q->sym2, RCX);
+			out<< "\t\t" << "add" << "\t" << "rax, rcx" << endl;
+			store(RAX, q->sym3);
+			break;
+
+		case q_rminus:
+			fetch_float(q->sym1);
+			fetch_float(q->sym2);
+			out<< "\t\t" << "fsubp" << endl;
+			store_float(q->sym3);
+			break;
+
+		case q_iminus:
+			fetch(q->sym1, RAX);
+			fetch(q->sym2, RCX);
+			out<< "\t\t" << "sub" << "\t" << "rax, rcx" << endl;
+			store(RAX, q->sym3);
+			break;
+
+		case q_ior: {
+			int label = sym_tab->get_next_label();
+			int label2 = sym_tab->get_next_label();
+
+			fetch(q->sym1, RAX);
+			out<< "\t\t" << "cmp" << "\t" << "rax, 0" << endl;
+			out<< "\t\t" << "jne" << "\t" << "L" << label << endl;
+			fetch(q->sym2, RAX);
+			out<< "\t\t" << "cmp" << "\t" << "rax, 0" << endl;
+			out<< "\t\t" << "jne" << "\t" << "L" << label << endl;
+			// False branch
+			out<< "\t\t" << "mov" << "\t" << "rax, 0" << endl;
+			out<< "\t\t" << "jmp" << "\t" << "L" << label2 << endl;
+			// True branch
+			out<< "\t\t" << "L" << label << ":" << endl;
+			out<< "\t\t" << "mov" << "\t" << "rax, 1" << endl;
+
+			out<< "\t\t" << "L" << label2 << ":" << endl;
+			store(RAX, q->sym3);
+			break;
+		}
+		case q_iand: {
+			int label = sym_tab->get_next_label();
+			int label2 = sym_tab->get_next_label();
+
+			fetch(q->sym1, RAX);
+			out<< "\t\t" << "cmp" << "\t" << "rax, 0" << endl;
+			out<< "\t\t" << "je" << "\t" << "L" << label << endl;
+			fetch(q->sym2, RAX);
+			out<< "\t\t" << "cmp" << "\t" << "rax, 0" << endl;
+			out<< "\t\t" << "je" << "\t" << "L" << label << endl;
+			// True branch
+			out<< "\t\t" << "mov" << "\t" << "rax, 1" << endl;
+			out<< "\t\t" << "jmp" << "\t" << "L" << label2 << endl;
+			// False branch
+			out<< "\t\t" << "L" << label << ":" << endl;
+			out<< "\t\t" << "mov" << "\t" << "rax, 0" << endl;
+
+			out<< "\t\t" << "L" << label2 << ":" << endl;
+			store(RAX, q->sym3);
+			break;
+		}
+		case q_rmult:
+			fetch_float(q->sym1);
+			fetch_float(q->sym2);
+			out<< "\t\t" << "fmulp" << endl;
+			store_float(q->sym3);
+			break;
+
+		case q_imult:
+			fetch(q->sym1, RAX);
+			fetch(q->sym2, RCX);
+			out<< "\t\t" << "imul" << "\t" << "rax, rcx" << endl;
+			store(RAX, q->sym3);
+			break;
+
+		case q_rdivide:
+			fetch_float(q->sym1);
+			fetch_float(q->sym2);
+			out<< "\t\t" << "fdivp" << endl;
+			store_float(q->sym3);
+			break;
+
+		case q_idivide:
+			fetch(q->sym1, RAX);
+			fetch(q->sym2, RCX);
+			out<< "\t\t" << "cqo" << endl;
+			out<< "\t\t" << "idiv" << "\t" << "rax, rcx" << endl;
+			store(RAX, q->sym3);
+			break;
+
+		case q_imod:
+			fetch(q->sym1, RAX);
+			fetch(q->sym2, RCX);
+			out<< "\t\t" << "cqo" << endl;
+			out<< "\t\t" << "idiv" << "\t" << "rax, rcx" << endl;
+			store(RDX, q->sym3);
+			break;
+
+		case q_req: {
+			int label = sym_tab->get_next_label();
+			int label2 = sym_tab->get_next_label();
+
+			fetch_float(q->sym1);
+			fetch_float(q->sym2);
+			out<< "\t\t" << "fcomip" << "\t" << "ST(0), ST(1)" << endl;
+			// Clear the stack
+			out<< "\t\t" << "fstp" << "\t" << "ST(0)" << endl;
+			out<< "\t\t" << "je" << "\t" << "L" << label << endl;
+			// False branch
+			out<< "\t\t" << "mov" << "\t" << "rax, 0" << endl;
+			out<< "\t\t" << "jmp" << "\t" << "L" << label2 << endl;
+			// True branch
+			out<< "\t\t" << "L" << label << ":" << endl;
+			out<< "\t\t" << "mov" << "\t" << "rax, 1" << endl;
+
+			out<< "\t\t" << "L" << label2 << ":" << endl;
+			store(RAX, q->sym3);
+			break;
+		}
+		case q_ieq: {
+			int label = sym_tab->get_next_label();
+			int label2 = sym_tab->get_next_label();
+
+			fetch(q->sym1, RAX);
+			fetch(q->sym2, RCX);
+			out<< "\t\t" << "cmp" << "\t" << "rax, rcx" << endl;
+			out<< "\t\t" << "je" << "\t" << "L" << label << endl;
+			// False branch
+			out<< "\t\t" << "mov" << "\t" << "rax, 0" << endl;
+			out<< "\t\t" << "jmp" << "\t" << "L" << label2 << endl;
+			// True branch
+			out<< "\t\t" << "L" << label << ":" << endl;
+			out<< "\t\t" << "mov" << "\t" << "rax, 1" << endl;
+
+			out<< "\t\t" << "L" << label2 << ":" << endl;
+			store(RAX, q->sym3);
+			break;
+		}
+		case q_rne: {
+			int label = sym_tab->get_next_label();
+			int label2 = sym_tab->get_next_label();
+
+			fetch_float(q->sym1);
+			fetch_float(q->sym2);
+			out<< "\t\t" << "fcomip" << "\t" << "ST(0), ST(1)" << endl;
+			// Clear the stack
+			out<< "\t\t" << "fstp" << "\t" << "ST(0)" << endl;
+			out<< "\t\t" << "jne" << "\t" << "L" << label << endl;
+			// False branch
+			out<< "\t\t" << "mov" << "\t" << "rax, 0" << endl;
+			out<< "\t\t" << "jmp" << "\t" << "L" << label2 << endl;
+			// True branch
+			out<< "\t\t" << "L" << label << ":" << endl;
+			out<< "\t\t" << "mov" << "\t" << "rax, 1" << endl;
+
+			out<< "\t\t" << "L" << label2 << ":" << endl;
+			store(RAX, q->sym3);
+			break;
+		}
+		case q_ine: {
+			int label = sym_tab->get_next_label();
+			int label2 = sym_tab->get_next_label();
+
+			fetch(q->sym1, RAX);
+			fetch(q->sym2, RCX);
+			out<< "\t\t" << "cmp" << "\t" << "rax, rcx" << endl;
+			out<< "\t\t" << "jne" << "\t" << "L" << label << endl;
+			// False branch
+			out<< "\t\t" << "mov" << "\t" << "rax, 0" << endl;
+			out<< "\t\t" << "jmp" << "\t" << "L" << label2 << endl;
+			// True branch
+			out<< "\t\t" << "L" << label << ":" << endl;
+			out<< "\t\t" << "mov" << "\t" << "rax, 1" << endl;
+
+			out<< "\t\t" << "L" << label2 << ":" << endl;
+			store(RAX, q->sym3);
+			break;
+		}
+		case q_rlt: {
+			int label = sym_tab->get_next_label();
+			int label2 = sym_tab->get_next_label();
+
+			// We need to push in reverse order for this to work
+			fetch_float(q->sym2);
+			fetch_float(q->sym1);
+			out<< "\t\t" << "fcomip" << "\t" << "ST(0), ST(1)" << endl;
+			// Clear the stack
+			out<< "\t\t" << "fstp" << "\t" << "ST(0)" << endl;
+			out<< "\t\t" << "jb" << "\t" << "L" << label << endl;
+			// False branch
+			out<< "\t\t" << "mov" << "\t" << "rax, 0" << endl;
+			out<< "\t\t" << "jmp" << "\t" << "L" << label2 << endl;
+			// True branch
+			out<< "\t\t" << "L" << label << ":" << endl;
+			out<< "\t\t" << "mov" << "\t" << "rax, 1" << endl;
+
+			out<< "\t\t" << "L" << label2 << ":" << endl;
+			store(RAX, q->sym3);
+			break;
+		}
+		case q_ilt: {
+			int label = sym_tab->get_next_label();
+			int label2 = sym_tab->get_next_label();
+
+			fetch(q->sym1, RAX);
+			fetch(q->sym2, RCX);
+			out<< "\t\t" << "cmp" << "\t" << "rax, rcx" << endl;
+			out<< "\t\t" << "jl" << "\t" << "L" << label << endl;
+			// False branch
+			out<< "\t\t" << "mov" << "\t" << "rax, 0" << endl;
+			out<< "\t\t" << "jmp" << "\t" << "L" << label2 << endl;
+			// True branch
+			out<< "\t\t" << "L" << label << ":" << endl;
+			out<< "\t\t" << "mov" << "\t" << "rax, 1" << endl;
+
+			out<< "\t\t" << "L" << label2 << ":" << endl;
+			store(RAX, q->sym3);
+			break;
+		}
+		case q_rgt: {
+			int label = sym_tab->get_next_label();
+			int label2 = sym_tab->get_next_label();
+
+			// We need to push in reverse order for this to work
+			fetch_float(q->sym2);
+			fetch_float(q->sym1);
+			out<< "\t\t" << "fcomip" << "\t" << "ST(0), ST(1)" << endl;
+			// Clear the stack
+			out<< "\t\t" << "fstp" << "\t" << "ST(0)" << endl;
+			out<< "\t\t" << "ja" << "\t" << "L" << label << endl;
+			// False branch
+			out<< "\t\t" << "mov" << "\t" << "rax, 0" << endl;
+			out<< "\t\t" << "jmp" << "\t" << "L" << label2 << endl;
+			// True branch
+			out<< "\t\t" << "L" << label << ":" << endl;
+			out << "\t\t" << "mov" << "\t" << "rax, 1" << endl;
+
+			out << "\t\t" << "L" << label2 << ":" << endl;
+			store(RAX, q->sym3);
+			break;
+		}
+		case q_igt: {
+			int label = sym_tab->get_next_label();
+			int label2 = sym_tab->get_next_label();
+
+			fetch(q->sym1, RAX);
+			fetch(q->sym2, RCX);
+			out << "\t\t" << "cmp" << "\t" << "rax, rcx" << endl;
+			out << "\t\t" << "jg" << "\t" << "L" << label << endl;
+			// False branch
+			out << "\t\t" << "mov" << "\t" << "rax, 0" << endl;
+			out << "\t\t" << "jmp" << "\t" << "L" << label2 << endl;
+			// True branch
+			out << "\t\t" << "L" << label << ":" << endl;
+			out << "\t\t" << "mov" << "\t" << "rax, 1" << endl;
+
+			out << "\t\t" << "L" << label2 << ":" << endl;
+			store(RAX, q->sym3);
+			break;
+		}
+		case q_rstore:
+		case q_istore:
+			fetch(q->sym1, RAX);
+			fetch(q->sym3, RCX);
+			out << "\t\t" << "mov" << "\t" << "[rcx], rax" << endl;
+			break;
+
+		case q_rassign:
+		case q_iassign:
+			fetch(q->sym1, RAX);
+			store(RAX, q->sym3);
+			break;
+
+		case q_param: {
+			/* Your code here */
+			fetch(q->sym1, RAX);
+			out << "\t\t" << "push" << "\t" << "rax\n";
+			break;
+		}
+
+		case q_call: {
+			/* Your code here */
+			sym_type tag = sym_tab->get_symbol_tag(q->sym1);
+			if (tag == SYM_FUNC) {
+				function_symbol *fun_s = sym_tab->get_symbol(q->sym1)->get_function_symbol();
+				out << "\t\t" << "call" << "\t" << "L" << fun_s->label_nr << "\n";
+				out << "\t\t" << "add" << "\t" << "rsp, " << q->int2*STACK_WIDTH << "\n";
+				store(RAX, q->sym3);
+			} else if (tag == SYM_PROC) {
+				procedure_symbol *para_s = sym_tab->get_symbol(q->sym1)->get_procedure_symbol();
+				out << "\t\t" << "call" << "\t" << "L" << para_s->label_nr << "\n";
+				out << "\t\t" << "add" << "\t" << "rsp, " << q->int2*STACK_WIDTH << "\n";
+			}
+			break;
+		}
+		case q_rreturn:
+		case q_ireturn:
+			fetch(q->sym2, RAX);
+			out << "\t\t" << "jmp" << "\t" << "L" << q->int1 << endl;
+			break;
+
+		case q_lindex:
+			array_address(q->sym1, RAX);
+			fetch(q->sym2, RCX);
+			out << "\t\t" << "imul" << "\t" << "rcx, " << STACK_WIDTH << endl;
+			out << "\t\t" << "sub" << "\t" << "rax, rcx" << endl;
+			store(RAX, q->sym3);
+			break;
+
+		case q_rrindex:
+		case q_irindex:
+			array_address(q->sym1, RAX);
+			fetch(q->sym2, RCX);
+			out << "\t\t" << "imul" << "\t" << "rcx, " << STACK_WIDTH << endl;
+			out << "\t\t" << "sub" << "\t" << "rax, rcx" << endl;
+			out << "\t\t" << "mov" << "\t" << "rax, [rax]" << endl;
+			store(RAX, q->sym3);
+			break;
+
+		case q_itor: {
+			block_level level;	 // Current scope level.
+			int offset;			// Offset within current activation record.
+
+			find(q->sym1, &level, &offset);
+			frame_address(level, RCX);
+			out << "\t\t" << "fild" << "\t" << "qword ptr [rcx";
+			if (offset >= 0) {
+				out << "+" << offset;
+			} else {
+				out << offset; // Implicit "-"
+			}
+			out << "]" << endl;
+			store_float(q->sym3);
+		}
+		break;
+
+		case q_jmp:
+			out << "\t\t" << "jmp" << "\t" << "L" << q->int1 << endl;
+			break;
+
+		case q_jmpf:
+			fetch(q->sym2, RAX);
+			out << "\t\t" << "cmp" << "\t" << "rax, 0" << endl;
+			out << "\t\t" << "je" << "\t" << "L" << q->int1 << endl;
+			break;
+
+		case q_labl:
+			// We handled this one above already.
+			break;
+
+		case q_nop:
+			// q_nop quads should never be generated.
+			fatal("code_generator::expand(): q_nop quadruple produced.");
+			return;
+		}
+
+		// Get the next quad from the list.
+		q = ql_iterator->get_next();
+	}
+
+	// Flush the generated code to file.
+	out << flush;
 }
+
-- 
GitLab