#include #define ASM(opcode, args...) puts("\t"#opcode"\t"#args) #define LABEL(label) printf("_%s:\n", (char*)label) /**Generate table of strings in a rodata section. */ void generate_stringtable ( void ); /**Declare global variables in a bss section */ void generate_global_variables ( void ); /**Generate function entry code * @param function symbol table entry of function */ void generate_function ( symbol_t *function ); /**Generate code for a node in the AST, to be called recursively from * generate_function * @param node root node of current code block */ static void generate_node ( node_t *node ); /**Initializes program (already implemented) */ void generate_main ( symbol_t *first ); #define MIN(a,b) (((a)<(b)) ? (a):(b)) static const char *record[6] = { "%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9" }; static uint64_t fetch_symbols(tlhash_t* symbol_table, symbol_t*** symbol_list); void generate_program ( void ) { /* TODO: Emit assembly instructions for functions, function calls, * print statements and expressions. * The provided function 'generate_main' creates a program entry point * for the function symbol it is given as argument. */ // TODO: Implement // - Generate code for all functions // - Generate main (function already implemented) by assigning either the // function named main or the first function of the source file if no // main exists. generate_stringtable(); generate_global_variables(); symbol_t **global_list; uint64_t no_globals = fetch_symbols(global_names, &global_list); for (uint64_t g = 0; g < no_globals; g++) { if (global_list[g]->type == SYM_FUNCTION) generate_function(global_list[g]); } } void generate_stringtable ( void ) { /* These can be used to emit numbers, strings and a run-time * error msg. from main */ puts("# DATA SECTION"); puts(".data"); puts(".intout:\t.asciz \"\%ld \""); puts(".strout:\t.asciz \"\%s \""); puts(".errout:\t.asciz \"Wrong number of arguments\""); for (uint64_t s = 0; s < stringc; s++) { printf(".STR%03ld:\t.asciz %s\n", s, string_list[s]); } putchar('\n'); } void generate_global_variables ( void ) { symbol_t **global_list; uint64_t no_globals = fetch_symbols(global_names, &global_list); puts("# GLOBAL VARIABLES"); puts(".bss"); puts(".align 8"); for (uint64_t g = 0; g < no_globals; g++) { if (global_list[g]->type == SYM_GLOBAL_VAR) printf(".%s:\n", global_list[g]->name); } putchar('\n'); free(global_list); } void generate_function ( symbol_t *function ) { // TODO: Generate code for declaring and entering function, then generate its body node_t *func_root = function->node; LABEL(function->name); ASM(pushq, %rbp); ASM(movq, %rsp, %rbp); putchar('\n'); } void generate_node ( node_t *node ) { // TODO: Generate code corresponding to node } /**Generates the main function with argument parsing and calling of our * main function (first, if no function is named main) * @param first Symbol table entry of our main function */ void generate_main ( symbol_t *first ) { puts ( ".globl main" ); puts ( ".section .text" ); puts ( "main:" ); puts ( "\tpushq %rbp" ); puts ( "\tmovq %rsp, %rbp" ); printf ( "\tsubq\t$1,%%rdi\n" ); printf ( "\tcmpq\t$%zu,%%rdi\n", first->nparms ); printf ( "\tjne\tABORT\n" ); printf ( "\tcmpq\t$0,%%rdi\n" ); printf ( "\tjz\tSKIP_ARGS\n" ); printf ( "\tmovq\t%%rdi,%%rcx\n" ); printf ( "\taddq $%zu, %%rsi\n", 8*first->nparms ); printf ( "PARSE_ARGV:\n" ); printf ( "\tpushq %%rcx\n" ); printf ( "\tpushq %%rsi\n" ); printf ( "\tmovq\t(%%rsi),%%rdi\n" ); printf ( "\tmovq\t$0,%%rsi\n" ); printf ( "\tmovq\t$10,%%rdx\n" ); printf ( "\tcall\tstrtol\n" ); /* Now a new argument is an integer in rax */ printf ( "\tpopq %%rsi\n" ); printf ( "\tpopq %%rcx\n" ); printf ( "\tpushq %%rax\n" ); printf ( "\tsubq $8, %%rsi\n" ); printf ( "\tloop PARSE_ARGV\n" ); /* Now the arguments are in order on stack */ for ( int arg=0; argnparms); arg++ ) printf ( "\tpopq\t%s\n", record[arg] ); printf ( "SKIP_ARGS:\n" ); printf ( "\tcall\t_%s\n", first->name ); printf ( "\tjmp\tEND\n" ); printf ( "ABORT:\n" ); printf ( "\tmovq\t$.errout, %%rdi\n" ); printf ( "\tcall puts\n" ); printf ( "END:\n" ); puts ( "\tmovq %rax, %rdi" ); puts ( "\tcall exit" ); } static uint64_t fetch_symbols(tlhash_t* symbol_table, symbol_t*** symbol_list) { uint64_t no_symbols = tlhash_size(symbol_table); *symbol_list = malloc(no_symbols * sizeof(symbol_t)); tlhash_values(symbol_table, (void **)*symbol_list ); return no_symbols; }