diff --git a/cc.h b/cc.h index 40f6577..ee73d69 100644 --- a/cc.h +++ b/cc.h @@ -25,14 +25,9 @@ // CONSTANT FALSE 0 #define TRUE 1 // CONSTANT TRUE 1 -// CONSTANT NULL 0 -// CONSTANT EXIT_FAILURE 1 -// CONSTANT EXIT_SUCCESS 0 -// CONSTANT stdin 0 -// CONSTANT stdout 1 -// CONSTANT stderr 2 void file_print(char* s, FILE* f); +int match(char* a, char* b); struct type { diff --git a/cc_core.c b/cc_core.c index f8a3ee9..30e7905 100644 --- a/cc_core.c +++ b/cc_core.c @@ -24,7 +24,9 @@ struct token_list* global_function_list; struct token_list* global_constant_list; /* What we are currently working on */ +struct token_list* break_locals; struct type* current_target; +char* break_target; /* Imported functions */ char* parse_string(char* string); @@ -37,14 +39,6 @@ struct token_list* emit(char *s, struct token_list* head) return t; } -struct token_list* double_emit(char* a, char* b, struct token_list* out, int flag) -{ - out = emit(a, out); - out = emit(b, out); - if(flag) out = emit("\n", out); - return out; -} - char* numerate_number(int a) { char* result = calloc(16, sizeof(char)); @@ -84,6 +78,66 @@ char* numerate_number(int a) return result; } +int match(char* a, char* b) +{ + int i = -1; + do + { + i = i + 1; + if(a[i] != b[i]) + { + return FALSE; + } + } while((0 != a[i]) && (0 !=b[i])); + return TRUE; +} + +char* postpend_char(char* s, char a) +{ + int i = 0; + while(0 != s[i]) + { + i = i + 1; + } + s[i] = a; + return s; +} + +char* prepend_char(char a, char* s) +{ + int hold = a; + int prev; + int i = 0; + do + { + prev = hold; + hold = s[i]; + s[i] = prev; + i = i + 1; + } while(0 != hold); + return s; +} + +char* prepend_string(char* add, char* base) +{ + char* ret = calloc(MAX_STRING, sizeof(char)); + int i = 0; + while(0 != add[i]) + { + ret[i] = add[i]; + i = i + 1; + } + + int j = 0; + while(0 != base[j]) + { + ret[i] = base[j]; + i = i + 1; + j = j + 1; + } + return ret; +} + struct token_list* sym_declare(char *s, struct type* t, struct token_list* list) { struct token_list* a = calloc(1, sizeof(struct token_list)); @@ -98,7 +152,7 @@ struct token_list* sym_lookup(char *s, struct token_list* symbol_list) struct token_list* i; for(i = symbol_list; NULL != i; i = i->next) { - if(0 == strcmp(s,i->s)) return i; + if(match(i->s, s)) return i; } return NULL; } @@ -135,7 +189,7 @@ struct token_list* sym_get_value(char *s, struct token_list* out, struct token_l struct token_list* a = sym_lookup(s, global_constant_list); if(NULL != a) { - out = double_emit("LOAD_IMMEDIATE_eax %", a->arguments->s, out, TRUE); return out; + out = emit(prepend_string("LOAD_IMMEDIATE_eax %", postpend_char(a->arguments->s, '\n')), out); return out; } a= sym_lookup(s, global_function_list); @@ -148,8 +202,8 @@ struct token_list* sym_get_value(char *s, struct token_list* out, struct token_l if(NULL != a) { current_target = a->type; - out = double_emit("LOAD_EFFECTIVE_ADDRESS %", numerate_number(stack_index(a, function)), out, FALSE); - if(strcmp(global_token->s, "=")) out = emit("LOAD_INTEGER\n", out); + out = emit(prepend_string("LOAD_EFFECTIVE_ADDRESS %", postpend_char(numerate_number(stack_index(a, function)), '\n')), out); + if(!match("=", global_token->s)) out = emit("LOAD_INTEGER\n", out); return out; } a = sym_lookup(s, function->arguments); @@ -157,8 +211,8 @@ struct token_list* sym_get_value(char *s, struct token_list* out, struct token_l if(NULL != a) { current_target = a->type; - out = double_emit("LOAD_EFFECTIVE_ADDRESS %", numerate_number(stack_index(a, function)), out, FALSE); - if(strcmp(global_token->s, "=")) out = emit("LOAD_INTEGER\n", out); + out = emit(prepend_string("LOAD_EFFECTIVE_ADDRESS %", postpend_char(numerate_number(stack_index(a, function)), '\n')), out); + if(!match("=", global_token->s)) out = emit("LOAD_INTEGER\n", out); return out; } @@ -166,8 +220,8 @@ struct token_list* sym_get_value(char *s, struct token_list* out, struct token_l if(NULL != a) { current_target = a->type; - out = double_emit("LOAD_IMMEDIATE_eax &GLOBAL_", s, out, TRUE); - if(strcmp(global_token->s, "=")) out = emit("LOAD_INTEGER\n", out); + out = emit(prepend_string("LOAD_IMMEDIATE_eax &GLOBAL_", postpend_char(s, '\n')), out); + if(!match("=", global_token->s)) out = emit("LOAD_INTEGER\n", out); return out; } @@ -178,7 +232,7 @@ struct token_list* sym_get_value(char *s, struct token_list* out, struct token_l void require_match(char* message, char* required) { - if(strcmp(global_token->s, required)) + if(!match(global_token->s, required)) { file_print(message, stderr); exit(EXIT_FAILURE); @@ -199,7 +253,7 @@ struct token_list* primary_expr(struct token_list* out, struct token_list* funct { if(('0' <= global_token->s[0]) & (global_token->s[0] <= '9')) { - out = double_emit("LOAD_IMMEDIATE_eax %", global_token->s, out, TRUE); + out = emit(prepend_string("LOAD_IMMEDIATE_eax %", postpend_char(global_token->s, '\n')), out); global_token = global_token->next; } else if((('a' <= global_token->s[0]) & (global_token->s[0] <= 'z')) | (('A' <= global_token->s[0]) & (global_token->s[0] <= 'Z'))) @@ -269,7 +323,7 @@ struct token_list* process_expression_list(struct token_list* out, struct token_ } else global_token = global_token->next; - out = double_emit("CALL_IMMEDIATE %FUNCTION_", func, out, TRUE); + out = emit(prepend_string("CALL_IMMEDIATE %FUNCTION_", postpend_char(func, '\n')), out); int i; for(i = function->temps - temp; 0 != i; i = i - 1) @@ -338,13 +392,13 @@ struct token_list* postfix_expr(struct token_list* out, struct token_list* funct /* Add support for Ints */ if( 1 != a->indirect->size) { - out = double_emit("SAL_eax_Immediate8 !", numerate_number(ceil_log2(a->indirect->size)), out, FALSE); + out = emit(prepend_string("SAL_eax_Immediate8 !", numerate_number(ceil_log2(a->indirect->size))), out); } out = emit("ADD_ebx_to_eax\n", out); current_target = target; - if(strcmp(global_token->next->s, "=")) + if(!match("=", global_token->next->s)) { if( 4 == a->indirect->size) { @@ -361,14 +415,14 @@ struct token_list* postfix_expr(struct token_list* out, struct token_list* funct { out = process_expression_list(out, function); } - else if(!strcmp("->", global_token->s)) + else if(match("->", global_token->s)) { out = emit("# looking up offset\n", out); global_token = global_token->next; struct type* i; for(i = current_target->members; NULL != i; i = i->members) { - if(!strcmp(i->name, global_token->s)) break; + if(match(i->name, global_token->s)) break; } if(NULL == i) { @@ -382,10 +436,10 @@ struct token_list* postfix_expr(struct token_list* out, struct token_list* funct if(0 != i->offset) { out = emit("# -> offset calculation\n", out); - out = double_emit("LOAD_IMMEDIATE_ebx %", numerate_number(i->offset), out, FALSE); + out = emit(prepend_string("LOAD_IMMEDIATE_ebx %", numerate_number(i->offset)), out); out = emit("ADD_ebx_to_eax\n", out); } - if(strcmp(global_token->next->s, "=")) + if(!match("=", global_token->next->s)) { out = emit("LOAD_INTEGER\n", out); } @@ -406,7 +460,7 @@ struct token_list* postfix_expr(struct token_list* out, struct token_list* funct struct type* type_name(); struct token_list* unary_expr(struct token_list* out, struct token_list* function) { - if(!strcmp("-", global_token->s)) + if(match("-", global_token->s)) { out = emit("LOAD_IMMEDIATE_eax %0\n", out); out = pre_recursion(out, function); @@ -414,7 +468,7 @@ struct token_list* unary_expr(struct token_list* out, struct token_list* functio out = post_recursion(out, function); out = emit("SUBTRACT_eax_from_ebx_into_ebx\nMOVE_ebx_to_eax\n", out); } - else if(!strcmp("!", global_token->s)) + else if(match("!", global_token->s)) { out = emit("LOAD_IMMEDIATE_eax %1\n", out); out = pre_recursion(out, function); @@ -422,14 +476,14 @@ struct token_list* unary_expr(struct token_list* out, struct token_list* functio out = post_recursion(out, function); out = emit("XOR_ebx_eax_into_eax\n", out); } - else if(!strcmp("sizeof", global_token->s)) + else if(match("sizeof", global_token->s)) { global_token = global_token->next; require_match("ERROR in unary_expr\nMissing (\n", "("); struct type* a = type_name(); require_match("ERROR in unary_expr\nMissing )\n", ")"); - out = double_emit("LOAD_IMMEDIATE_eax %", numerate_number(a->size), out, FALSE); + out = emit(prepend_string("LOAD_IMMEDIATE_eax %", numerate_number(a->size)), out); } else out = postfix_expr(out, function); @@ -451,35 +505,35 @@ struct token_list* additive_expr(struct token_list* out, struct token_list* func while(1) { - if(!strcmp("+", global_token->s)) + if(match("+", global_token->s)) { out = pre_recursion(out, function); out = unary_expr(out, function); out = post_recursion(out, function); out = emit("ADD_ebx_to_eax\n", out); } - else if(!strcmp("-", global_token->s)) + else if(match("-", global_token->s)) { out = pre_recursion(out, function); out = unary_expr(out, function); out = post_recursion(out, function); out = emit("SUBTRACT_eax_from_ebx_into_ebx\nMOVE_ebx_to_eax\n", out); } - else if(!strcmp("*", global_token->s)) + else if(match("*", global_token->s)) { out = pre_recursion(out, function); out = unary_expr(out, function); out = post_recursion(out, function); out = emit("MULTIPLY_eax_by_ebx_into_eax\n", out); } - else if(!strcmp("/", global_token->s)) + else if(match("/", global_token->s)) { out = pre_recursion(out, function); out = unary_expr(out, function); out = post_recursion(out, function); out = emit("DIVIDE_eax_by_ebx_into_eax\n", out); } - else if(!strcmp("%", global_token->s)) + else if(match("%", global_token->s)) { out = pre_recursion(out, function); out = unary_expr(out, function); @@ -502,22 +556,22 @@ struct token_list* shift_expr(struct token_list* out, struct token_list* functio while(1) { - if(!strcmp(global_token->s, "<<")) + if(match("<<", global_token->s)) { out = pre_recursion(out, function); out = additive_expr(out, function); out = post_recursion(out, function); - // Ugly hack to Work around flaw in x86 + /* Ugly hack to Work around flaw in x86 */ struct token_list* old = out->next; free(out); out = emit("COPY_eax_to_ecx\nPOP_eax\nSAL_eax_cl\n", old); } - else if(!strcmp(global_token->s, ">>")) + else if(match(">>", global_token->s)) { out = pre_recursion(out, function); out = additive_expr(out, function); out = post_recursion(out, function); - // Ugly hack to Work around flaw in x86 + /* Ugly hack to Work around flaw in x86 */ struct token_list* old = out->next; free(out); out = emit("COPY_eax_to_ecx\nPOP_eax\nSAR_eax_cl\n", old); @@ -543,28 +597,28 @@ struct token_list* relational_expr(struct token_list* out, struct token_list* fu while(1) { - if(!strcmp(global_token->s, "<")) + if(match("<", global_token->s)) { out = pre_recursion(out, function); out = shift_expr(out, function); out = post_recursion(out, function); out = emit("CMP\nSETL\nMOVEZBL\n", out); } - else if(!strcmp(global_token->s, "<=")) + else if(match("<=", global_token->s)) { out = pre_recursion(out, function); out = shift_expr(out, function); out = post_recursion(out, function); out = emit("CMP\nSETLE\nMOVEZBL\n", out); } - else if(!strcmp(global_token->s, ">=")) + else if(match(">=", global_token->s)) { out = pre_recursion(out, function); out = shift_expr(out, function); out = post_recursion(out, function); out = emit("CMP\nSETGE\nMOVEZBL\n", out); } - else if(!strcmp(global_token->s, ">")) + else if(match(">", global_token->s)) { out = pre_recursion(out, function); out = shift_expr(out, function); @@ -587,14 +641,14 @@ struct token_list* equality_expr(struct token_list* out, struct token_list* func while(1) { - if(!strcmp(global_token->s, "==")) + if(match("==", global_token->s)) { out = pre_recursion(out, function); out = relational_expr(out, function); out = post_recursion(out, function); out = emit("CMP\nSETE\nMOVEZBL\n", out); } - else if(!strcmp(global_token->s, "!=")) + else if(match("!=", global_token->s)) { out = pre_recursion(out, function); out = relational_expr(out, function); @@ -655,7 +709,7 @@ struct token_list* expression(struct token_list* out, struct token_list* functio if(global_token->s[0] == '=') { struct type* target = current_target; - int member = !strcmp(global_token->prev->s, "]"); + int member = match("]", global_token->prev->s); out = pre_recursion(out, function); out = expression(out, function); out = post_recursion(out, function); @@ -676,108 +730,12 @@ struct token_list* expression(struct token_list* out, struct token_list* functio return out; } -struct type* lookup_type(char* s) -{ - struct type* i; - for(i = global_types; NULL != i; i = i->next) - { - if(!strcmp(i->name, s)) - { - return i; - } - } - return NULL; -} - -struct type* type_name(); -void create_struct() -{ - int offset = 0; - struct type* head = calloc(1, sizeof(struct type)); - struct type* i = calloc(1, sizeof(struct type)); - head->name = global_token->s; - i->name = global_token->s; - head->indirect = i; - i->indirect = head; - head->next = global_types; - global_types = head; - global_token = global_token->next; - i->size = 4; - require_match("ERROR in create_struct\nMissing {\n", "{"); - struct type* last = NULL; - while('}' != global_token->s[0]) - { - struct type* member_type = type_name(); - i = calloc(1, sizeof(struct type)); - i->name = global_token->s; - i->members = last; - i->size = member_type->size; - i->type = member_type; - i->offset = offset; - offset = offset + member_type->size; - global_token = global_token->next; - require_match("ERROR in create_struct\nMissing ;\n", ";"); - last = i; - } - - global_token = global_token->next; - require_match("ERROR in create_struct\nMissing ;\n", ";"); - - head->size = offset; - head->members = last; - head->indirect->members = last; -} - - -/* - * type-name: - * char * - * int - * struct - * FILE - * void - */ -struct type* type_name() -{ - int structure = FALSE; - - if(!strcmp(global_token->s, "struct")) - { - structure = TRUE; - global_token = global_token->next; - } - - struct type* ret = lookup_type(global_token->s); - - if(NULL == ret && !structure) - { - file_print("Unknown type ", stderr); - file_print(global_token->s, stderr); - file_print("\n", stderr); - exit(EXIT_FAILURE); - } - else if(NULL == ret) - { - create_struct(); - return NULL; - } - - global_token = global_token->next; - - while(global_token->s[0] == '*') - { - ret = ret->indirect; - global_token = global_token->next; - } - - return ret; -} /* Process local variable */ struct token_list* collect_local(struct token_list* out, struct token_list* function) { struct type* type_size = type_name(); - out = double_emit("# Defining local ", global_token->s, out, TRUE); + out = emit(prepend_string("# Defining local ", prepend_string(global_token->s, "\n")), out); struct token_list* a = sym_declare(global_token->s, type_size, function->locals); function->locals = a; @@ -793,7 +751,7 @@ struct token_list* collect_local(struct token_list* out, struct token_list* func require_match("ERROR in collect_local\nMissing ;\n", ";"); - out = double_emit("PUSH_eax\t#", a->s, out, TRUE); + out = emit(prepend_string("PUSH_eax\t#", prepend_string(a->s, "\n")), out); return out; } @@ -806,26 +764,26 @@ struct token_list* process_if(struct token_list* out, struct token_list* functio char* number_string = numerate_number(if_count); if_count = if_count + 1; - out = double_emit("# IF_",number_string, out, FALSE); + out = emit(prepend_string("# IF_", number_string), out); global_token = global_token->next; require_match("ERROR in process_if\nMISSING (\n", "("); out = expression(out, function); - out = double_emit("TEST\nJUMP_EQ %ELSE_", number_string, out, FALSE); + out = emit(prepend_string("TEST\nJUMP_EQ %ELSE_", number_string), out); require_match("ERROR in process_if\nMISSING )\n", ")"); out = statement(out, function); - out = double_emit("JUMP %_END_IF_", number_string, out, FALSE); - out = double_emit(":ELSE_", number_string, out, FALSE); + out = emit(prepend_string("JUMP %_END_IF_", number_string), out); + out = emit(prepend_string(":ELSE_", number_string), out); - if(!strcmp(global_token->s, "else")) + if(match("else", global_token->s)) { global_token = global_token->next; out = statement(out, function); } - out = double_emit(":_END_IF_", number_string, out, FALSE); + out = emit(prepend_string(":_END_IF_", number_string), out); return out; } @@ -835,33 +793,41 @@ struct token_list* process_for(struct token_list* out, struct token_list* functi char* number_string = numerate_number(for_count); for_count = for_count + 1; - out = double_emit("# FOR_initialization_", number_string, out, FALSE); + char* nested_break = break_target; + struct token_list* nested_locals = break_locals; + break_locals = function->locals; + break_target = prepend_string("FOR_END_", number_string); + + out = emit(prepend_string("# FOR_initialization_", number_string), out); global_token = global_token->next; require_match("ERROR in process_for\nMISSING (\n", "("); out = expression(out, function); - out = double_emit(":FOR_", number_string, out , FALSE); + out = emit(prepend_string(":FOR_", number_string), out); require_match("ERROR in process_for\nMISSING ;1\n", ";"); out = expression(out, function); - out = double_emit("TEST\nJUMP_EQ %FOR_END_", number_string, out, FALSE); - out = double_emit("JUMP %FOR_THEN_", number_string, out, FALSE); - out = double_emit(":FOR_ITER_", number_string, out, FALSE); + out = emit(prepend_string("TEST\nJUMP_EQ %FOR_END_", number_string), out); + out = emit(prepend_string("JUMP %FOR_THEN_", number_string), out); + out = emit(prepend_string(":FOR_ITER_", number_string), out); require_match("ERROR in process_for\nMISSING ;2\n", ";"); out = expression(out, function); - out = double_emit("JUMP %FOR_", number_string, out, FALSE); - out = double_emit(":FOR_THEN_", number_string, out, FALSE); + out = emit(prepend_string("JUMP %FOR_", number_string), out); + out = emit(prepend_string(":FOR_THEN_", number_string), out); require_match("ERROR in process_for\nMISSING )\n", ")"); out = statement(out, function); - out = double_emit("JUMP %FOR_ITER_", number_string, out, FALSE); - out = double_emit(":FOR_END_", number_string, out, FALSE); + out = emit(prepend_string("JUMP %FOR_ITER_", number_string), out); + out = emit(prepend_string(":FOR_END_", number_string), out); + + break_target = nested_break; + break_locals = nested_locals; return out; } @@ -888,7 +854,12 @@ struct token_list* process_do(struct token_list* out, struct token_list* functio char* number_string = numerate_number(do_count); do_count = do_count + 1; - out = double_emit(":DO_", number_string, out, FALSE); + char* nested_break = break_target; + struct token_list* nested_locals = break_locals; + break_locals = function->locals; + break_target = prepend_string("DO_END_", number_string); + + out = emit(prepend_string(":DO_", number_string), out); global_token = global_token->next; out = statement(out, function); @@ -899,7 +870,11 @@ struct token_list* process_do(struct token_list* out, struct token_list* functio require_match("ERROR in process_do\nMISSING )\n", ")"); require_match("ERROR in process_do\nMISSING ;\n", ";"); - out = double_emit("TEST\nJUMP_NE %DO_", number_string, out, FALSE); + out = emit(prepend_string("TEST\nJUMP_NE %DO_", number_string), out); + out = emit(prepend_string(":DO_END_", number_string), out); + + break_locals = nested_locals; + break_target = nested_break; return out; } @@ -911,20 +886,29 @@ struct token_list* process_while(struct token_list* out, struct token_list* func char* number_string = numerate_number(while_count); while_count = while_count + 1; - out = double_emit(":WHILE_", number_string, out, FALSE); + char* nested_break = break_target; + struct token_list* nested_locals = break_locals; + break_locals = function->locals; + + break_target = prepend_string("END_WHILE_", number_string); + + out = emit(prepend_string(":WHILE_", number_string), out); global_token = global_token->next; require_match("ERROR in process_while\nMISSING (\n", "("); out = expression(out, function); - out = double_emit("TEST\nJUMP_EQ %END_WHILE_", number_string, out, FALSE); - out = double_emit("# THEN_while_", number_string, out, FALSE); + out = emit(prepend_string("TEST\nJUMP_EQ %END_WHILE_", number_string), out); + out = emit(prepend_string("# THEN_while_", number_string), out); require_match("ERROR in process_while\nMISSING )\n", ")"); out = statement(out, function); - out = double_emit("JUMP %WHILE_", number_string, out, FALSE); - out = double_emit(":END_WHILE_", number_string, out, FALSE); + out = emit(prepend_string("JUMP %WHILE_", number_string), out); + out = emit(prepend_string(":END_WHILE_", number_string), out); + + break_locals = nested_locals; + break_target = nested_break; return out; } @@ -950,7 +934,7 @@ struct token_list* recursive_statement(struct token_list* out, struct token_list global_token = global_token->next; struct token_list* frame = function->locals; - while(strcmp(global_token->s, "}")) + while(!match("}", global_token->s)) { out = statement(out, function); } @@ -962,7 +946,10 @@ struct token_list* recursive_statement(struct token_list* out, struct token_list struct token_list* i; for(i = function->locals; frame != i; i = i->next) { - out = emit( "POP_ebx\t# _recursive_statement_locals\n", out); + if(!match("RETURN\n", out->s)) + { + out = emit( "POP_ebx\t# _recursive_statement_locals\n", out); + } function->locals = function->locals->next; } } @@ -983,8 +970,11 @@ struct token_list* recursive_statement(struct token_list* out, struct token_list * goto label ; * label: * return ; + * break ; * expr ; */ + +struct type* lookup_type(char* s); struct token_list* statement(struct token_list* out, struct token_list* function) { if(global_token->s[0] == '{') @@ -997,41 +987,59 @@ struct token_list* statement(struct token_list* out, struct token_list* function out = emit("\t#C goto label\n", out); global_token = global_token->next; } - else if((NULL != lookup_type(global_token->s)) || !strcmp("struct", global_token->s)) + else if((NULL != lookup_type(global_token->s)) || match("struct", global_token->s)) { out = collect_local(out, function); } - else if(!strcmp(global_token->s, "if")) + else if(match("if", global_token->s)) { out = process_if(out, function); } - else if(!strcmp(global_token->s, "do")) + else if(match("do", global_token->s)) { out = process_do(out, function); } - else if(!strcmp(global_token->s, "while")) + else if(match("while", global_token->s)) { out = process_while(out, function); } - else if(!strcmp(global_token->s, "for")) + else if(match("for", global_token->s)) { out = process_for(out, function); } - else if(!strcmp(global_token->s, "asm")) + else if(match("asm", global_token->s)) { out = process_asm(out); } - else if(!strcmp("goto", global_token->s)) + else if(match("goto", global_token->s)) { global_token = global_token->next; - out = double_emit("JUMP %", global_token->s, out, TRUE); + out = emit(prepend_string("JUMP %", prepend_string(global_token->s, "\n")), out); global_token = global_token->next; require_match("ERROR in statement\nMissing ;\n", ";"); } - else if(!strcmp(global_token->s, "return")) + else if(match("return", global_token->s)) { out = return_result(out, function); } + else if(match("break", global_token->s)) + { + if(NULL == break_target) + { + file_print("Not inside of a loop or case statement", stderr); + exit(EXIT_FAILURE); + } + struct token_list* i = function->locals; + while(i != break_locals) + { + if(NULL == i) break; + out = emit("POP_ebx\t# break_cleanup_locals\n", out); + i = i->next; + } + global_token = global_token->next; + out = emit(prepend_string("JUMP %", prepend_string(break_target, "\n")), out); + require_match("ERROR in statement\nMissing ;\n", ";"); + } else { out = expression(out, function); @@ -1045,7 +1053,7 @@ void collect_arguments(struct token_list* function) { global_token = global_token->next; - while(strcmp(global_token->s, ")")) + while(!match(")", global_token->s)) { struct type* type_size = type_name(); if(global_token->s[0] == ')') @@ -1083,12 +1091,12 @@ struct token_list* declare_function(struct token_list* out, struct type* type) if(global_token->s[0] == ';') global_token = global_token->next; else { - out = double_emit("# Defining function ", essential, out, TRUE); - out = double_emit(":FUNCTION_", essential, out, TRUE); + out = emit(prepend_string("# Defining function ", prepend_string(essential, "\n")), out); + out = emit(prepend_string(":FUNCTION_", prepend_string(essential, "\n")), out); out = statement(out, func); /* Prevent duplicate RETURNS */ - if(strcmp(out->s, "RETURN\n")) + if(!match("RETURN\n", out->s)) { out = emit("RETURN\n", out); } @@ -1119,7 +1127,7 @@ struct token_list* program(struct token_list* out) while(NULL != global_token) { new_type: - if(!strcmp(global_token->s, "CONSTANT")) + if(match("CONSTANT", global_token->s)) { global_constant_list = sym_declare(global_token->next->s, NULL, global_constant_list); global_constant_list->arguments = global_token->next->next; @@ -1139,7 +1147,7 @@ new_type: global_symbol_list = sym_declare(global_token->prev->s, type_size, global_symbol_list); /* Ensure 4 bytes are allocated for the global */ - globals_list = double_emit(":GLOBAL_", global_token->prev->s, globals_list, TRUE); + globals_list = emit(prepend_string(":GLOBAL_", prepend_string(global_token->prev->s, "\n")), globals_list); globals_list = emit("NOP\n", globals_list); global_token = global_token->next; diff --git a/cc_types.c b/cc_types.c index 5883a0d..144dd45 100644 --- a/cc_types.c +++ b/cc_types.c @@ -58,7 +58,7 @@ void initialize_types() d->name = "FILE"; d->size = 4; d->type = d; - /* int* has the same properties as int */ + /* FILE* has the same properties as FILE */ d->indirect = d; /* Finalize type list */ @@ -66,3 +66,101 @@ void initialize_types() a->next = c; global_types->next = a; } + +struct type* lookup_type(char* s) +{ + struct type* i; + for(i = global_types; NULL != i; i = i->next) + { + if(match(i->name, s)) + { + return i; + } + } + return NULL; +} + +struct type* type_name(); +void require_match(char* message, char* required); +void create_struct() +{ + int offset = 0; + struct type* head = calloc(1, sizeof(struct type)); + struct type* i = calloc(1, sizeof(struct type)); + head->name = global_token->s; + i->name = global_token->s; + head->indirect = i; + i->indirect = head; + head->next = global_types; + global_types = head; + global_token = global_token->next; + i->size = 4; + require_match("ERROR in create_struct\nMissing {\n", "{"); + struct type* last = NULL; + while('}' != global_token->s[0]) + { + struct type* member_type = type_name(); + i = calloc(1, sizeof(struct type)); + i->name = global_token->s; + i->members = last; + i->size = member_type->size; + i->type = member_type; + i->offset = offset; + offset = offset + member_type->size; + global_token = global_token->next; + require_match("ERROR in create_struct\nMissing ;\n", ";"); + last = i; + } + + global_token = global_token->next; + require_match("ERROR in create_struct\nMissing ;\n", ";"); + + head->size = offset; + head->members = last; + head->indirect->members = last; +} + + +/* + * type-name: + * char * + * int + * struct + * FILE + * void + */ +struct type* type_name() +{ + int structure = FALSE; + + if(match("struct", global_token->s)) + { + structure = TRUE; + global_token = global_token->next; + } + + struct type* ret = lookup_type(global_token->s); + + if(NULL == ret && !structure) + { + file_print("Unknown type ", stderr); + file_print(global_token->s, stderr); + file_print("\n", stderr); + exit(EXIT_FAILURE); + } + else if(NULL == ret) + { + create_struct(); + return NULL; + } + + global_token = global_token->next; + + while(global_token->s[0] == '*') + { + ret = ret->indirect; + global_token = global_token->next; + } + + return ret; +} diff --git a/libc.c b/libc.c index 0a41ee8..b03eaa4 100644 --- a/libc.c +++ b/libc.c @@ -14,8 +14,59 @@ * You should have received a copy of the GNU General Public License * along with stage0. If not, see . */ -int fgetc(FILE*); -int* calloc(int, int); -void free(void*); -void exit(int); -int strcmp(char* a, char* b); + +#include "cc.h" +// CONSTANT NULL 0 +// CONSTANT EXIT_FAILURE 1 +// CONSTANT EXIT_SUCCESS 0 +// CONSTANT stdin 0 +// CONSTANT stdout 1 +// CONSTANT stderr 2 + +int fgetc(FILE* f); +void fputc(char s, FILE* f); +FILE* fopen(char* filename, char* mode); +int fclose(FILE* file); +void* malloc(int size) +{ + asm("STORE_eax_into_ESP_IMMEDIATE8 !4" + "PUSH_eax" + "LOAD_IMMEDIATE_eax %45" + "LOAD_IMMEDIATE_ebx %0" + "INT_80" + "POP_ebx" + "ADD_eax_to_ebx" + "PUSH_eax" + "PUSH_ebx" + "LOAD_IMMEDIATE_eax %45" + "INT_80" + "POP_ebx" + "CMP" + "POP_eax" + "JUMP_EQ8 !FUNCTION_malloc_Done" + "LOAD_IMMEDIATE_eax %-1" + ":FUNCTION_malloc_Done" + "RETURN"); +} +void* calloc(int count, int size) +{ + char* ret = malloc(count * size); + int i; + for(i = (count * size); i >= 0; i = i - 1) + { + ret[i] = 0; + } + return ret; +} + +void free(void* pointer) +{ + return; +} +void exit(int value) +{ + asm("POP_ebx" + "POP_ebx" + "LOAD_IMMEDIATE_eax %1" + "INT_80"); +} diff --git a/makefile b/makefile index 8992f74..6fb031f 100644 --- a/makefile +++ b/makefile @@ -27,6 +27,9 @@ clean: ./test/test08/cleanup.sh ./test/test09/cleanup.sh ./test/test10/cleanup.sh + ./test/test11/cleanup.sh + ./test/test12/cleanup.sh + ./test/test13/cleanup.sh ./test/test99/cleanup.sh # Directories @@ -37,7 +40,21 @@ results: mkdir -p test/results # tests -test: test00-binary test01-binary test02-binary test03-binary test04-binary test05-binary test06-binary test07-binary test08-binary test09-binary test10-binary test99-binary | results +test: test00-binary \ + test01-binary \ + test02-binary \ + test03-binary \ + test04-binary \ + test05-binary \ + test06-binary \ + test07-binary \ + test08-binary \ + test09-binary \ + test10-binary \ + test11-binary \ + test12-binary \ + test13-binary \ + test99-binary | results sha256sum -c test/test.answers test00-binary: M2-Planet | results @@ -73,6 +90,15 @@ test09-binary: M2-Planet | results test10-binary: M2-Planet | results test/test10/hello.sh +test11-binary: M2-Planet | results + test/test11/hello.sh + +test12-binary: M2-Planet | results + test/test12/hello.sh + +test13-binary: M2-Planet | results + test/test13/hello.sh + test99-binary: M2-Planet | results test/test99/hello.sh diff --git a/test/test.answers b/test/test.answers index 0566b3b..1322074 100644 --- a/test/test.answers +++ b/test/test.answers @@ -3,10 +3,13 @@ 3de3e1eabc6b808fbe172c7bb5a4e677a272fcbec7f73f2f896090051280d95a test/results/test02-binary 97c9a95f88b63cf318b8caae963abc899004dc17c9695d7f5a2b0f7d4cf7dcb8 test/results/test03-binary e20f8dbbfaf58b3706e7b445dcb63ee8ff071d0efb6bfc00c89ed9365d5555eb test/results/test04-binary -d427f256cbe716cd5b15d45072d4153e55e3529dd6a3b1dc6d429e540861c812 test/results/test05-binary -500dad424f01059c03a0fffada3ebc5bdb2b3b2a17813f89fed771b68690df71 test/results/test06-binary -67ba7b001b45aa551be1ddff605b856fc8b2d9159d1d95bda7592c71ab68f4f3 test/results/test07-binary -0d7709779c4d6acecb8fe3d2f384b2a03b4dd9a272924672c2111c4dafcaee45 test/results/test08-binary +e55762fc05b6fca351c0e49a3951810f7361d3516768bd2235ad29a0227564c5 test/results/test05-binary +9d26baf5537e489ba73c24feb229d863e356d4796a876f6dc773cc191bc0ce99 test/results/test06-binary +c3d09cbcb5d7be5e0cb97dd8592fe20d8ef6799eb4812dce44728d6f1771da48 test/results/test07-binary +d236657797c77ded168092a64629bf7f4ed4ff04dbda995ac3550bc3877c8e0e test/results/test08-binary 2832ac2466f13aa63f2ccafd1a132b82dbb8d421c9c81ffaa5adaee13cd1b00b test/results/test09-binary -ccded240b943e39dc32454cd61c07f7b1978da0f203a4a93ebb93625dcaa96af test/results/test10-binary -746ce0eeeec1b7b8fa6836c4d3cb916b25db62bbf525251cc4ca594dd7a66969 test/results/test99-binary +04e3f14f5f4dfa18a0674798c16bb0a64842a240576f0841dcb799a94ab8ca49 test/results/test10-binary +900d7467cc32fdce1c74289590a00a6fca4fba672e6179f78eed788c3f6b09d0 test/results/test11-binary +511b056ea02c6544fdbae3f878a0f4f4f4a7297301f4c199c0fa64807c67025e test/results/test12-binary +dfd63f9bb0704b56908b9c8c01bc741443012ef17d0425db3399f4f4000f6a86 test/results/test13-binary +44188322e8272196652061d1d0fa2b2403593f51ddd7aa896c8a199740c53d71 test/results/test99-binary diff --git a/test/test11/.gitignore b/test/test11/.gitignore new file mode 100644 index 0000000..0ce0949 --- /dev/null +++ b/test/test11/.gitignore @@ -0,0 +1,7 @@ +# Ignore the files created by script +*.M1 +*.hex2 +proof + +# A place to put a good run for comparison +actual.M1 diff --git a/test/test11/break-do.c b/test/test11/break-do.c new file mode 100644 index 0000000..11f2497 --- /dev/null +++ b/test/test11/break-do.c @@ -0,0 +1,54 @@ +/* Copyright (C) 2016 Jeremiah Orians + * This file is part of stage0. + * + * stage0 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * stage0 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with stage0. If not, see . + */ + +/* Validate that call statements behave correctly */ +int putchar(int); +void exit(int); + +int main() +{ + int i = 65; + do + { + putchar(i); + if(90 == i) + { + break; + } + i = i + 1; + } while (i <= 120); + + putchar(10); + i = 65; + do + { + int j = i; + do + { + if(70 == i) + { + break; + } + putchar(j); + j = j + 1; + } while (j <= 90); + putchar(10); + if(90 == i) break; + i = i + 1; + } while (i <= 120); + return 0; +} diff --git a/test/test11/cleanup.sh b/test/test11/cleanup.sh new file mode 100755 index 0000000..cc7c939 --- /dev/null +++ b/test/test11/cleanup.sh @@ -0,0 +1,5 @@ +#! /bin/sh +rm -f test/test11/break-do.M1 +rm -f test/test11/break-do.hex2 +rm -f test/test11/proof +exit 0 diff --git a/test/test11/hello.sh b/test/test11/hello.sh new file mode 100755 index 0000000..6eb094d --- /dev/null +++ b/test/test11/hello.sh @@ -0,0 +1,18 @@ +#! /bin/sh +set -ex +# Build the test +bin/M2-Planet -f test/test11/break-do.c -o test/test11/break-do.M1 || exit 1 +# Macro assemble with libc written in M1-Macro +M1 -f test/common_x86/x86_defs.M1 -f test/common_x86/libc.M1 -f test/test11/break-do.M1 --LittleEndian --Architecture 1 -o test/test11/break-do.hex2 || exit 2 +# Resolve all linkages +hex2 -f test/common_x86/ELF-i386.hex2 -f test/test11/break-do.hex2 --LittleEndian --Architecture 1 --BaseAddress 0x8048000 -o test/results/test11-binary --exec_enable || exit 3 + +# Ensure binary works if host machine supports test +if [ "$(get_machine)" = "x86_64" ] +then + # Verify that the resulting file works + ./test/results/test11-binary >| test/test11/proof || exit 4 + out=$(sha256sum -c test/test11/proof.answer) + [ "$out" = "test/test11/proof: OK" ] || exit 5 +fi +exit 0 diff --git a/test/test11/proof.answer b/test/test11/proof.answer new file mode 100644 index 0000000..e961eb4 --- /dev/null +++ b/test/test11/proof.answer @@ -0,0 +1 @@ +2bf4500a34a43cfc4f45e30c1a894b9ba1fb177a5257e05671d67e61408102d0 test/test11/proof diff --git a/test/test12/.gitignore b/test/test12/.gitignore new file mode 100644 index 0000000..0ce0949 --- /dev/null +++ b/test/test12/.gitignore @@ -0,0 +1,7 @@ +# Ignore the files created by script +*.M1 +*.hex2 +proof + +# A place to put a good run for comparison +actual.M1 diff --git a/test/test12/break-for.c b/test/test12/break-for.c new file mode 100644 index 0000000..70ff687 --- /dev/null +++ b/test/test12/break-for.c @@ -0,0 +1,51 @@ +/* Copyright (C) 2016 Jeremiah Orians + * This file is part of stage0. + * + * stage0 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * stage0 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with stage0. If not, see . + */ + +/* Validate that call statements behave correctly */ +int putchar(int); +void exit(int); + +int main() +{ + int i = 65; + for(i = 65; i <= 120; i = i + 1) + { + putchar(i); + if(90 == i) + { + break; + } + } + + putchar(10); + + for(i = 65; i <= 120; i = i + 1) + { + int j = i; + for(j = i; j <= 90; j = j + 1) + { + if(70 == i) + { + break; + } + putchar(j); + } + putchar(10); + if(90 == i) break; + } + return 0; +} diff --git a/test/test12/cleanup.sh b/test/test12/cleanup.sh new file mode 100755 index 0000000..db06454 --- /dev/null +++ b/test/test12/cleanup.sh @@ -0,0 +1,5 @@ +#! /bin/sh +rm -f test/test12/break-for.M1 +rm -f test/test12/break-for.hex2 +rm -f test/test12/proof +exit 0 diff --git a/test/test12/hello.sh b/test/test12/hello.sh new file mode 100755 index 0000000..d78246a --- /dev/null +++ b/test/test12/hello.sh @@ -0,0 +1,18 @@ +#! /bin/sh +set -ex +# Build the test +bin/M2-Planet -f test/test12/break-for.c -o test/test12/break-for.M1 || exit 1 +# Macro assemble with libc written in M1-Macro +M1 -f test/common_x86/x86_defs.M1 -f test/common_x86/libc.M1 -f test/test12/break-for.M1 --LittleEndian --Architecture 1 -o test/test12/break-for.hex2 || exit 2 +# Resolve all linkages +hex2 -f test/common_x86/ELF-i386.hex2 -f test/test12/break-for.hex2 --LittleEndian --Architecture 1 --BaseAddress 0x8048000 -o test/results/test12-binary --exec_enable || exit 3 + +# Ensure binary works if host machine supports test +if [ "$(get_machine)" = "x86_64" ] +then + # Verify that the resulting file works + ./test/results/test12-binary >| test/test12/proof || exit 4 + out=$(sha256sum -c test/test12/proof.answer) + [ "$out" = "test/test12/proof: OK" ] || exit 5 +fi +exit 0 diff --git a/test/test12/proof.answer b/test/test12/proof.answer new file mode 100644 index 0000000..04aecf7 --- /dev/null +++ b/test/test12/proof.answer @@ -0,0 +1 @@ +2bf4500a34a43cfc4f45e30c1a894b9ba1fb177a5257e05671d67e61408102d0 test/test12/proof diff --git a/test/test13/.gitignore b/test/test13/.gitignore new file mode 100644 index 0000000..0ce0949 --- /dev/null +++ b/test/test13/.gitignore @@ -0,0 +1,7 @@ +# Ignore the files created by script +*.M1 +*.hex2 +proof + +# A place to put a good run for comparison +actual.M1 diff --git a/test/test13/break-while.c b/test/test13/break-while.c new file mode 100644 index 0000000..d5ce5bd --- /dev/null +++ b/test/test13/break-while.c @@ -0,0 +1,54 @@ +/* Copyright (C) 2016 Jeremiah Orians + * This file is part of stage0. + * + * stage0 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * stage0 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with stage0. If not, see . + */ + +/* Validate that call statements behave correctly */ +int putchar(int); +void exit(int); + +int main() +{ + int i = 65; + while (i <= 120) + { + putchar(i); + if(90 == i) + { + break; + } + i = i + 1; + } + + putchar(10); + i = 65; + while (i <= 120) + { + int j = i; + while (j <= 90) + { + if(70 == i) + { + break; + } + putchar(j); + j = j + 1; + } + putchar(10); + if(90 == i) break; + i = i + 1; + } + return 0; +} diff --git a/test/test13/cleanup.sh b/test/test13/cleanup.sh new file mode 100755 index 0000000..fd91f70 --- /dev/null +++ b/test/test13/cleanup.sh @@ -0,0 +1,5 @@ +#! /bin/sh +rm -f test/test13/break-while.M1 +rm -f test/test13/break-while.hex2 +rm -f test/test13/proof +exit 0 diff --git a/test/test13/hello.sh b/test/test13/hello.sh new file mode 100755 index 0000000..76b26df --- /dev/null +++ b/test/test13/hello.sh @@ -0,0 +1,18 @@ +#! /bin/sh +set -ex +# Build the test +bin/M2-Planet -f test/test13/break-while.c -o test/test13/break-while.M1 || exit 1 +# Macro assemble with libc written in M1-Macro +M1 -f test/common_x86/x86_defs.M1 -f test/common_x86/libc.M1 -f test/test13/break-while.M1 --LittleEndian --Architecture 1 -o test/test13/break-while.hex2 || exit 2 +# Resolve all linkages +hex2 -f test/common_x86/ELF-i386.hex2 -f test/test13/break-while.hex2 --LittleEndian --Architecture 1 --BaseAddress 0x8048000 -o test/results/test13-binary --exec_enable || exit 3 + +# Ensure binary works if host machine supports test +if [ "$(get_machine)" = "x86_64" ] +then + # Verify that the resulting file works + ./test/results/test13-binary >| test/test13/proof || exit 4 + out=$(sha256sum -c test/test13/proof.answer) + [ "$out" = "test/test13/proof: OK" ] || exit 5 +fi +exit 0 diff --git a/test/test13/proof.answer b/test/test13/proof.answer new file mode 100644 index 0000000..3d8ece7 --- /dev/null +++ b/test/test13/proof.answer @@ -0,0 +1 @@ +2bf4500a34a43cfc4f45e30c1a894b9ba1fb177a5257e05671d67e61408102d0 test/test13/proof