void codegen_emit(AST_expr *expr, int parent_numArgs, FILE *outputFile) { int i, label1, label2, n; Environment *closureEnvironment; switch(expr->type) { case Sequence: for (i=0; i<expr->numBody; i++) codegen_emit(expr->body[i], parent_numArgs, outputFile); break; case Constant: switch (expr->value->type) { case Numconst: if (expr->value->value >= 32768) {fprintf(stderr, "ERROR 24: Integer constant too large"); exit(EXIT_FAILURE);} fprintf(outputFile, "\tLDI CRSh, %i\n\tLDI CRSl, %i\n", (expr->value->value >> 8) & 127, expr->value->value & 255); break; case Booleanconst: if (expr->value->value == 0) fprintf(outputFile, "\tLDI CRSh, 254\n\tLDI CRSl, 0\n"); if (expr->value->value == 1) fprintf(outputFile, "\tLDI CRSh, 255\n\tLDI CRSl, 0\n"); break; case Charconst: fprintf(outputFile, "\tLDI CRSh, 224\n\tLDI CRSl, %i\n", expr->value->value); break; case Stringconst: // similar to primcall vector case n = strlen(expr->value->strvalue); fprintf(outputFile, "\tLDI GP1, lo8(%i)\n\tLDI GP2, hi8(%i)\n\tST X+, GP1\n\tST X+, GP2\n", n, n); for (i=0; i<n; i++) { fprintf(outputFile, "\tLDI CRSh, 224\n\tLDI CRSl, %i\n\tST X+, CRSl\n\tST X+, CRSh\n", expr->value->strvalue[i]); } fprintf(outputFile, "\tMOV CRSl, HFPl\n\tMOV CRSh, HFPh\n\tSBIW CRSl, %i\n\tORI CRSh, 160\n", 2+2*n); break; case Emptylistconst: fprintf(outputFile, "\tLDI CRSh, 232\n\tLDI CRSl, 0\n"); break; } break; case Branch: label1 = if_end_unique++; label2 = if_conseq_unique++; codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tCPSE CRSh, falseReg\n\tJMP if_conseq%i\n", label2); if (expr->numBody == 3) codegen_emit(expr->body[2], parent_numArgs, outputFile); fprintf(outputFile, "\tJMP if_end%i\nif_conseq%i:\n", label1, label2); codegen_emit(expr->body[1], parent_numArgs, outputFile); fprintf(outputFile, "if_end%i:\n", label1); break; case And: label1 = and_end_unique++; for (i=0; i<expr->numBody-1; i++) { codegen_emit(expr->body[i], parent_numArgs, outputFile); fprintf(outputFile, "\tCPSE CRSh, falseReg\n\tRJMP 1f\n\tJMP and_end%i\n1:", label1); } codegen_emit(expr->body[expr->numBody-1], parent_numArgs, outputFile); fprintf(outputFile, "and_end%i:\n", label1); break; case Or: label1 = or_end_unique++; for (i=0; i<expr->numBody-1; i++) { codegen_emit(expr->body[i], parent_numArgs, outputFile); fprintf(outputFile, "\tCPSE CRSh, falseReg\n\tJMP or_end%i\n", label1); } codegen_emit(expr->body[expr->numBody-1], parent_numArgs, outputFile); fprintf(outputFile, "or_end%i:\n", label1); break; case Variable: switch(expr->varRefType) { case Local: fprintf(outputFile, "\tLDD CRSh, Z+%i\n\tLDD CRSl, Z+%i\n", 2*(parent_numArgs - expr->varRefIndex) - 1, 2*(parent_numArgs - expr->varRefIndex)); break; case Free: fprintf(outputFile, "\tMOVW CRSl, CCPl\n"); for (i=1; i < expr->varRefHop; i++) // traverse the closure-chain fprintf(outputFile, "\tLDD GP1, Y+3\n\tLDD CRSh, Y+4\n\tMOV CRSl, GP1\n"); fprintf(outputFile, "\tLDD GP1, Y+%i\n\tLDD CRSh, Y+%i\n\tMOV CRSl, GP1\n", (2 * expr->varRefIndex) + 5, (2 * expr->varRefIndex) + 6); break; case Global: if (opt_aggressive) { //int realAddress = globalEnv->realAddress[expr->varRefIndex]; //fprintf(outputFile, "\tLDS CRSh, RAM + %i\n\tLDS CRSl, RAM + %i\n", (2 * realAddress), 1 + (2 * realAddress)); fprintf(outputFile, "\tLDS CRSh, _global_%i+1\n\tLDS CRSl, _global_%i\n", globalEnv->realAddress[expr->varRefIndex], globalEnv->realAddress[expr->varRefIndex]); } else { //fprintf(outputFile, "\tLDS CRSh, RAM + %i\n\tLDS CRSl, RAM + %i\n", (2 * expr->varRefIndex), 1 + (2 * expr->varRefIndex)); fprintf(outputFile, "\tLDS CRSh, _global_%i+1\n\tLDS CRSl, _global_%i\n", expr->varRefIndex, expr->varRefIndex); } break; } break; case Definition: if (expr->numBody < 1) { // Nothing to do return; } case Assignment: switch(expr->varRefType) { case Local: codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tSTD Z+%i, CRSh\n\tSTD Z+%i, CRSl\n", 2*(parent_numArgs - expr->varRefIndex) - 1, 2*(parent_numArgs - expr->varRefIndex)); break; case Free: codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tMOVW GP1, CRSl\n\tMOVW CRSl, CCPl\n"); for (i=1; i < expr->varRefHop; i++) // traverse the closure-chain fprintf(outputFile, "\tLDD GP3, Y+3\n\tLDD CRSh, Y+4\n\tMOV CRSl, GP3\n"); fprintf(outputFile, "\tSTD Y+%i, GP1\n\tSTD Y+%i, GP2\n", (2 * expr->varRefIndex) + 5, (2 * expr->varRefIndex) + 6); break; case Global: if (opt_aggressive) { if (globalEnv->realAddress[expr->varRefIndex] >= 0) { //int realAddress = globalEnv->realAddress[expr->varRefIndex]; codegen_emit(expr->body[0], parent_numArgs, outputFile); //fprintf(outputFile, "\tSTS RAM + %i, CRSh\n\tSTS RAM + %i, CRSl\n", (2 * realAddress), 1 + (2 * realAddress)); fprintf(outputFile, "\tSTS _global_%i+1, CRSh\n\tSTS _global_%i, CRSl\n", globalEnv->realAddress[expr->varRefIndex], globalEnv->realAddress[expr->varRefIndex]); } } else { codegen_emit(expr->body[0], parent_numArgs, outputFile); //fprintf(outputFile, "\tSTS RAM + %i, CRSh\n\tSTS RAM + %i, CRSl\n", (2 * expr->varRefIndex), 1 + (2 * expr->varRefIndex)); fprintf(outputFile, "\tSTS _global_%i+1, CRSh\n\tSTS _global_%i, CRSl\n", expr->varRefIndex, expr->varRefIndex); } break; } break; case ProcCall: label1 = proc_ret_unique++; fprintf(outputFile, "\tPUSH AFPh\n\tPUSH AFPl\n\tPUSH CCPh\n\tPUSH CCPl\n\tLDI GP1, hi8(pm(proc_ret%i))\n\tPUSH GP1\n\tLDI GP1, lo8(pm(proc_ret%i))\n\tPUSH GP1\n", label1, label1); for (i=0; i<expr->numBody; i++) { codegen_emit(expr->body[i], parent_numArgs, outputFile); fprintf(outputFile, "\tPUSH CRSl\n\tPUSH CRSh\n"); } codegen_emit(expr->proc, parent_numArgs, outputFile); fprintf(outputFile, "\tIN AFPl, SPl\n\tIN AFPh, SPh\n"); if (expr->proc->type == Lambda && expr->proc->stack_allocate) fprintf(outputFile, "\tADIW AFPl, %i\n", (expr->proc->closure->numBinds * 2) + 5); fprintf(outputFile, "\tMOVW GP5, AFPl\n"); fprintf(outputFile, "\tLDI PCR, %i\n\tJMP proc_call\nproc_ret%i:\n\tPOP CCPl\n\tPOP CCPh\n\tPOP AFPl\n\tPOP AFPh\n", expr->numBody, label1); break; case TailCall: for (i=0; i<expr->numBody; i++) { codegen_emit(expr->body[i], parent_numArgs, outputFile); fprintf(outputFile, "\tPUSH CRSl\n\tPUSH CRSh\n"); } codegen_emit(expr->proc, parent_numArgs, outputFile); fprintf(outputFile, "\tIN GP3, SPl\n"); fprintf(outputFile, "\tIN GP4, SPh\n"); if (parent_numArgs > 0) fprintf(outputFile, "\tADIW AFPl, %i\n", 2*parent_numArgs); fprintf(outputFile, "\tOUT SPl, AFPl\n"); fprintf(outputFile, "\tOUT SPh, AFPh\n"); if (expr->numBody > 0) fprintf(outputFile, "\tSBIW AFPl, %i\n", 2*expr->numBody); fprintf(outputFile, "\tMOVW GP5, AFPl\n"); fprintf(outputFile, "\tMOVW AFPl, GP3\n"); if (expr->proc->type == Lambda && expr->proc->stack_allocate) fprintf(outputFile, "\tADIW AFPl, %i\n", (expr->proc->closure->numBinds * 2) + 5); if (expr->numBody > 0) fprintf(outputFile, "\tADIW AFPl, %i\n", 2*expr->numBody); fprintf(outputFile, "1:\tCP AFPl, GP3\n"); fprintf(outputFile, "\tCPC AFPh, GP4\n"); fprintf(outputFile, "\tBREQ 2f\n"); fprintf(outputFile, "\tLD GP1, Z\n"); fprintf(outputFile, "\tSBIW AFPl, 1\n"); fprintf(outputFile, "\tPUSH GP1\n"); fprintf(outputFile, "\tRJMP 1b\n"); fprintf(outputFile, "2:\tLDI PCR, %i\n", expr->numBody); if (expr->proc->type == Lambda && expr->proc->stack_allocate) fprintf(outputFile, "\tIN CRSh, SPh\n\tIN CRSl, SPl\n\tADIW CRSl, 1\n\tORI CRSh, 192\n"); fprintf(outputFile, "\tJMP proc_call\n"); break; case Lambda: label1 = proc_entry_unique++; label2 = proc_after_unique++; closureEnvironment = expr->closure; if (expr->stack_allocate) { //fprintf(stderr, "stack allocating..."); fprintf(outputFile, "\tMOVW GP3, HFPl\n\tIN HFPl, SPl\n\tIN HFPh, SPh\n\tSBIW HFPl, %i\n\tOUT SPl, HFPl\n\tOUT SPh, HFPh\n\tADIW HFPl, 1\n", (closureEnvironment->numBinds * 2) + 5); } fprintf(outputFile, "\tLDI GP1,%i\n\tST X+, GP1;HFP\n\tLDI GP1, hi8(pm(proc_entry%i))\n\tST X+, GP1\n\tLDI GP1, lo8(pm(proc_entry%i))\n\tST X+, GP1\n", expr->numFormals, label1, label1); // Set up the closure chain: fprintf(outputFile, "\tST X+, CCPl\n\tST X+, CCPh\n"); for (i=0; i<closureEnvironment->numBinds; i++) { if (closureEnvironment->lexicalAddrV[i] == 1) { fprintf(outputFile, "\tLDD CRSh, Z+%i\n\tLDD CRSl, Z+%i\n", 2*(parent_numArgs - closureEnvironment->lexicalAddrH[i]) - 1, 2*(parent_numArgs - closureEnvironment->lexicalAddrH[i])); fprintf(outputFile, "\tST X+, CRSl\n\tST X+, CRSh\n"); } else { // erm. something's gone wrong? } } char* lambdaname = "Anonymous"; if (expr->variable != NULL) lambdaname = expr->variable; fprintf(outputFile, "\tMOVW CRSl, HFPl\n\tSBIW CRSl, %i\n\tORI CRSh, 192\n", (closureEnvironment->numBinds * 2) + 5); if (expr->stack_allocate) { fprintf(outputFile, "\tMOVW HFPl, GP3\n"); } fprintf(outputFile, "\tJMP proc_after%i\nproc_entry%i: ; %s\n\tMOVW AFPl, GP5\n", label2, label1, lambdaname); for (i=0; i<expr->numBody; i++) codegen_emit(expr->body[i], expr->numFormals, outputFile); if (expr->body[expr->numBody-1]->type != TailCall) fprintf(outputFile, "\tADIW AFPl, %i\n\tOUT SPl, AFPl\n\tOUT SPh, AFPh\n\tPOP AFPl\n\tPOP AFPh\n\tIJMP\n", 2 * expr->numFormals); fprintf(outputFile, "proc_after%i:\n", label2); break; case OtherFundemental: if (strcmp(expr->primproc, "list") == 0) { for (i=0; i<expr->numBody; i++) { codegen_emit(expr->body[i], parent_numArgs, outputFile); fprintf(outputFile, "\tPUSH CRSh\n\tPUSH CRSl\n"); } fprintf(outputFile, "\tLDI CRSh, 232\n\tLDI CRSl, 0\n"); for (i=0; i<expr->numBody; i++) { fprintf(outputFile, "\tPOP GP1\n\tPOP GP2\n\tCALL inline_cons\n"); } } else if (strcmp(expr->primproc, "vector") == 0) { // Here we do some static analysis, in order to select the faster vector-building routine // whenever possible: bool all_const = true; for (i=0; i<expr->numBody; i++) { if (expr->body[i]->type != Constant) all_const = false; } if (all_const) { fprintf(outputFile, "\tLDI GP1, lo8(%i)\n\tLDI GP2, hi8(%i)\n\tST X+, GP1\n\tST X+, GP2\n", expr->numBody, expr->numBody); for (i=0; i<expr->numBody; i++) { codegen_emit(expr->body[i], parent_numArgs, outputFile); fprintf(outputFile, "\tST X+, CRSl\n\tST X+, CRSh\n"); } fprintf(outputFile, "\tMOVW CRSl, HFPl\n\tSUBI CRSl, lo8(%i)\n\tSBCI CRSh, hi8(%i)\n\tORI CRSh, 160\n", 2+2*expr->numBody, 2+2*expr->numBody); } else { for (i=expr->numBody-1; i>=0; i--) { codegen_emit(expr->body[i], parent_numArgs, outputFile); fprintf(outputFile, "\tPUSH CRSh\n\tPUSH CRSl\n"); } fprintf(outputFile, "\tLDI GP1, lo8(%i)\n\tLDI GP2, hi8(%i)\n\tST X+, GP1\n\tST X+, GP2\n", expr->numBody, expr->numBody); for (i=0; i<expr->numBody; i++) { fprintf(outputFile, "\tPOP CRSl\n\tPOP CRSh\n"); fprintf(outputFile, "\tST X+, CRSl\n\tST X+, CRSh\n"); } fprintf(outputFile, "\tMOVW CRSl, HFPl\n\tSUBI CRSl, lo8(%i)\n\tSBCI CRSh, hi8(%i)\n\tORI CRSh, 160\n", 2+2*expr->numBody, 2+2*expr->numBody); } } else if (strcmp(expr->primproc, "free!") == 0) { fprintf(outputFile, "\tPUSH HFPh\n\tPUSH HFPl\n"); for (i=0; i<expr->numBody; i++) { codegen_emit(expr->body[i], parent_numArgs, outputFile); } fprintf(outputFile, "\tPOP HFPl\n\tPOP HFPh\n"); } else if (strcmp(expr->primproc, "@if-model") == 0 && expr->numBody == 2) { if (strcmp(expr->body[0]->value->strvalue, model) == 0) { codegen_emit(expr->body[1], parent_numArgs, outputFile); } } else if (strcmp(expr->primproc, "call-c-func") == 0 && expr->numBody > 0 && expr->numBody <= 10) { fprintf(outputFile, "\tCALL before_c_func\n"); //load args into (24:25) -> (8:9) descending l:h for (i=1; i<expr->numBody; i++) { codegen_emit(expr->body[i], parent_numArgs, outputFile); fprintf(outputFile, "\tMOV r%i, CRSl\n\tMOV r%i, CRSh\n", 26 - (i * 2), 27 - (i * 2)); } fprintf(outputFile, "\tCALL %s\n\tCALL after_c_func\n", expr->body[0]->value->strvalue); } else if (strcmp(expr->primproc, "include-asm") == 0 && expr->numBody == 1) { fprintf(outputFile, ".include \"%s\"\n", expr->body[0]->value->strvalue); } else if (strcmp(expr->primproc, "asm") == 0) { for (i=0; i<expr->numBody; i++) { fprintf(outputFile, "\t%s\n", expr->body[i]->value->strvalue); } } break; case PrimCall: if ((strcmp(expr->primproc, "=") == 0 || strcmp(expr->primproc, "eq?") == 0) && expr->numBody == 2) { codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tPUSH CRSl\n\tPUSH CRSh\n"); codegen_emit(expr->body[1], parent_numArgs, outputFile); fprintf(outputFile, "\tPOP GP2\n\tPOP GP1\n\tCP GP2, CRSh\n\tBRNE 1f\n\tLDI CRSh, trueHigh\n\tCPSE GP1, CRSl\n\t1:LDI CRSh, falseHigh\n\tCLR CRSl\n"); } else if (strcmp(expr->primproc, "zero?") == 0 && expr->numBody == 1) { codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tMOVW GP1, CRSl\n\tCP zeroReg, CRSh\n\tBRNE 1f\n\tLDI CRSh, trueHigh\n\tCPSE zeroReg, CRSl\n\t1:LDI CRSh, falseHigh\n\tCLR CRSl\n"); } else if (strcmp(expr->primproc, "¬") == 0 && expr->numBody == 1) { // A quick, binary-valid not: codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tLDI GP1, 1\n\tEOR CRSh, GP1\n"); } else if (strcmp(expr->primproc, "not") == 0 && expr->numBody == 1) { // the (false? ...) version of not: codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tMOVW GP1, CRSl\n\tCP falseReg, CRSh\n\tBRNE 1f\n\tLDI CRSh, trueHigh\n\tCPSE zeroReg, CRSl\n\t1:LDI CRSh, falseHigh\n\tCLR CRSl\n"); } else if (strcmp(expr->primproc, "+") == 0 && expr->numBody == 2) { codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tSBRC CRSh, 7\n\tJMP error_notnum\n\tPUSH CRSh\n\tPUSH CRSl\n"); codegen_emit(expr->body[1], parent_numArgs, outputFile); fprintf(outputFile, "\tSBRC CRSh, 7\n\tJMP error_notnum\n\tPOP GP1\n\tPOP GP2\n\tADD CRSl, GP1\n\tADC CRSh, GP2\n"); } else if (strcmp(expr->primproc, "-") == 0 && expr->numBody == 2) { codegen_emit(expr->body[1], parent_numArgs, outputFile); fprintf(outputFile, "\tSBRC CRSh, 7\n\tJMP error_notnum\n\tPUSH CRSh\n\tPUSH CRSl\n"); codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tSBRC CRSh, 7\n\tJMP error_notnum\n\tPOP GP1\n\tPOP GP2\n\tSUB CRSl, GP1\n\tSBC CRSh, GP2\n"); } else if (strcmp(expr->primproc, "*") == 0 && expr->numBody == 2) { codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tSBRC CRSh, 7\n\tJMP error_notnum\n\tPUSH CRSh\n\tPUSH CRSl\n"); codegen_emit(expr->body[1], parent_numArgs, outputFile); fprintf(outputFile, "\tSBRC CRSh, 7\n\tJMP error_notnum\n\tPOP GP1\n\tPOP GP2\n\tMOV GP3, CRSh\n\tMOV GP4, CRSl\n\tMUL GP1, GP4\n\tMOV CRSl, MLX1\n\tMOV CRSh, MLX2\n\tMUL GP2, GP4\n\tADD CRSh, MLX1\n\tMUL GP1, GP3\n\tADD CRSh, MLX1\n"); } else if (strcmp(expr->primproc, "div") == 0 && expr->numBody == 2) { codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tSBRC CRSh, 7\n\tJMP error_notnum\n\tPUSH CRSh\n\tPUSH CRSl\n"); codegen_emit(expr->body[1], parent_numArgs, outputFile); fprintf(outputFile, "\tSBRC CRSh, 7\n\tJMP error_notnum\n\tPOP GP1\n\tPOP GP2\n\tCALL inline_div\n"); } else if (strcmp(expr->primproc, "mod") == 0 && expr->numBody == 2) { codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tSBRC CRSh, 7\n\tJMP error_notnum\n\tPUSH CRSh\n\tPUSH CRSl\n"); codegen_emit(expr->body[1], parent_numArgs, outputFile); fprintf(outputFile, "\tSBRC CRSh, 7\n\tJMP error_notnum\n\tPOP GP1\n\tPOP GP2\n\tCALL inline_div\n"); fprintf(outputFile, "\tADD GP1, GP3\n\tADC GP2, GP4\n\tMOVW CRSl, GP1\n"); } else if (strcmp(expr->primproc, "stacksize") == 0 && expr->numBody == 0) { fprintf(outputFile, "\tIN GP1, SPl\n\tIN GP2, SPh\n\tLDI CRSl, lo8(__stack)\n\tLDI CRSh, hi8(__stack)\n\tSUB CRSl, GP1\n\tSBC CRSh, GP2\n"); } else if (strcmp(expr->primproc, "heapsize") == 0 && expr->numBody == 0) { fprintf(outputFile, "\tMOVW CRSl, HFPl\n\tSUBI CRSl, lo8(_end)\n\tSBCI CRSh, hi8(_end)\n"); } else if (strcmp(expr->primproc, "error") == 0 && expr->numBody == 0) { fprintf(outputFile, "\tJMP error_custom\n"); } else if (strcmp(expr->primproc, "assert") == 0 && expr->numBody == 1) { codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tSER GP1\n\tCPSE CRSh, GP1\n\tJMP error_custom\n"); } else if (strcmp(expr->primproc, "number?") == 0 && expr->numBody == 1) { codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tROL CRSh\n\tROL CRSh\n\tANDI CRSh, 1\n\tCOM CRSh\n\tCLR CRSl\n"); } else if (strcmp(expr->primproc, "pair?") == 0 && expr->numBody == 1) { codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tORI CRSh, 31\n\tLDI GP1, 159\n\tCPSE CRSh, GP1\n\tCBR CRSh, 1\n\tORI CRSh, 224\n\tCLR CRSl\n"); } else if (strcmp(expr->primproc, "procedure?") == 0 && expr->numBody == 1) { codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tORI CRSh, 31\n\tLDI GP1, 223\n\tCPSE CRSh, GP1\n\tCBR CRSh, 1\n\tORI CRSh, 224\n\tCLR CRSl\n"); } else if (strcmp(expr->primproc, "char?") == 0 && expr->numBody == 1) { codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tORI CRSh, 7\n\tLDI GP1, 231\n\tCPSE CRSh, GP1\n\tCBR CRSh, 1\n\tORI CRSh, 248\n\tCLR CRSl\n"); } else if (strcmp(expr->primproc, "boolean?") == 0 && expr->numBody == 1) { codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tORI CRSh, 7\n\tLDI GP1, 255\n\tCPSE CRSh, GP1\n\tCBR CRSh, 1\n\tORI CRSh, 248\n\tCLR CRSl\n"); } else if (strcmp(expr->primproc, "null?") == 0 && expr->numBody == 1) { codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tORI CRSh, 7\n\tLDI GP1, 239\n\tCPSE CRSh, GP1\n\tCBR CRSh, 1\n\tORI CRSh, 248\n\tCLR CRSl\n"); } else if (strcmp(expr->primproc, "cons") == 0 && expr->numBody == 2) { codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tPUSH CRSh\n\tPUSH CRSl\n"); codegen_emit(expr->body[1], parent_numArgs, outputFile); fprintf(outputFile, "\tPOP GP1\n\tPOP GP2\n\tCALL inline_cons\n"); } else if (strcmp(expr->primproc, "car") == 0 && expr->numBody == 1) { codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tCALL inline_car\n"); } else if (strcmp(expr->primproc, "cdr") == 0 && expr->numBody == 1) { codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tCALL inline_cdr\n"); } else if (strcmp(expr->primproc, "set-car!") == 0 && expr->numBody == 2) { codegen_emit(expr->body[1], parent_numArgs, outputFile); fprintf(outputFile, "\tPUSH CRSh\n\tPUSH CRSl\n"); codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tPOP GP1\n\tPOP GP2\n\tCALL inline_set_car\n"); } else if (strcmp(expr->primproc, "set-cdr!") == 0 && expr->numBody == 2) { codegen_emit(expr->body[1], parent_numArgs, outputFile); fprintf(outputFile, "\tPUSH CRSh\n\tPUSH CRSl\n"); codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tPOP GP1\n\tPOP GP2\n\tCALL inline_set_cdr\n"); } else if (strcmp(expr->primproc, "make-vector") == 0 && expr->numBody == 1) { codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tMOVW GP1, CRSl\n\tMOVW CRSl, HFPl\n\tORI CRSh, 160\n\tST X+, GP1\n\tST X+, GP2\n\tLSL GP1\n\tROL GP2\n\tADD HFPl, GP1\n\tADC HFPh, GP2\n"); } else if (strcmp(expr->primproc, "vector?") == 0 && expr->numBody == 1) { codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tORI CRSh, 31\n\tLDI GP1, 191\n\tCPSE CRSh, GP1\n\tCBR CRSh, 1\n\tORI CRSh, 224\n\tCLR CRSl\n"); } else if (strcmp(expr->primproc, "vector-ref") == 0 && expr->numBody == 2) { codegen_emit(expr->body[1], parent_numArgs, outputFile); fprintf(outputFile, "\tPUSH CRSh\n\tPUSH CRSl\n"); codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tPOP GP1\n\tPOP GP2\n\tCALL inline_vector_ref\n"); } else if (strcmp(expr->primproc, "vector-set!") == 0 && expr->numBody == 3) { codegen_emit(expr->body[1], parent_numArgs, outputFile); fprintf(outputFile, "\tPUSH CRSh\n\tPUSH CRSl\n"); codegen_emit(expr->body[2], parent_numArgs, outputFile); fprintf(outputFile, "\tPUSH CRSh\n\tPUSH CRSl\n"); codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tPOP GP3\n\tPOP GP4\n\tPOP GP1\n\tPOP GP2\n\tCALL inline_vector_set\n"); } else if (strcmp(expr->primproc, "vector-length") == 0 && expr->numBody == 1) { codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tCALL inline_vector_length\n"); } else if (strcmp(expr->primproc, ">") == 0 && expr->numBody == 2) { codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tSBRC CRSh, 7\n\tJMP error_notnum\n\tPUSH CRSh\n\tPUSH CRSl\n"); codegen_emit(expr->body[1], parent_numArgs, outputFile); fprintf(outputFile, "\tSBRC CRSh, 7\n\tJMP error_notnum\n\tPOP GP1\n\tPOP GP2\n\tCALL inline_gt\n"); } else if (strcmp(expr->primproc, "<") == 0 && expr->numBody == 2) { // (a < b) == (b > a) codegen_emit(expr->body[1], parent_numArgs, outputFile); fprintf(outputFile, "\tSBRC CRSh, 7\n\tJMP error_notnum\n\tPUSH CRSh\n\tPUSH CRSl\n"); codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tSBRC CRSh, 7\n\tJMP error_notnum\n\tPOP GP1\n\tPOP GP2\n\tCALL inline_gt\n"); } else if (strcmp(expr->primproc, ">=") == 0 && expr->numBody == 2) { // (a >= b) == ¬(b > a) codegen_emit(expr->body[1], parent_numArgs, outputFile); fprintf(outputFile, "\tSBRC CRSh, 7\n\tJMP error_notnum\n\tPUSH CRSh\n\tPUSH CRSl\n"); codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tSBRC CRSh, 7\n\tJMP error_notnum\n\tPOP GP1\n\tPOP GP2\n\tCALL inline_gt\n"); // NOT: fprintf(outputFile, "\tLDI GP1, 1\n\tEOR CRSh, GP1\n"); } else if (strcmp(expr->primproc, "<=") == 0 && expr->numBody == 2) { // (a <= b) == ¬(a > b) codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tSBRC CRSh, 7\n\tJMP error_notnum\n\tPUSH CRSh\n\tPUSH CRSl\n"); codegen_emit(expr->body[1], parent_numArgs, outputFile); fprintf(outputFile, "\tSBRC CRSh, 7\n\tJMP error_notnum\n\tPOP GP1\n\tPOP GP2\n\tCALL inline_gt\n"); // NOT: fprintf(outputFile, "\tLDI GP1, 1\n\tEOR CRSh, GP1\n"); } else if (strcmp(expr->primproc, "digital-state") == 0 && expr->numBody == 2) { codegen_emit(expr->body[1], parent_numArgs, outputFile); fprintf(outputFile, "\tPUSH CRSl\n"); codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tPOP GP3\n\tLD GP4, Y\n\tLDI CRSh, trueHigh\n\tAND GP4, GP3\n\tCPSE GP4, GP3\n\tLDI CRSh, falseHigh\n\tCLR CRSl\n"); } else if (strcmp(expr->primproc, "set-digital-state") == 0 && expr->numBody == 3) { codegen_emit(expr->body[1], parent_numArgs, outputFile); fprintf(outputFile, "\tPUSH CRSl\n"); codegen_emit(expr->body[2], parent_numArgs, outputFile); fprintf(outputFile, "\tPUSH CRSh\n"); codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tPOP GP4\n\tPOP GP3\n\tLD GP5, Y\n\tOR GP5, GP3\n\tCOM GP3\n\tSBRS GP4, 0\n\tAND GP5, GP3\n\tST Y, GP5\n"); } else if (strcmp(expr->primproc, "pause") == 0 && expr->numBody == 1) { codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tCALL util_pause\n"); } else if (strcmp(expr->primproc, "micropause") == 0 && expr->numBody == 1) { codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tCALL util_micropause\n"); } else if (strcmp(expr->primproc, "char->number") == 0 && expr->numBody == 1) { codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tCLR CRSh\n"); } else if (strcmp(expr->primproc, "arity") == 0 && expr->numBody == 1) { codegen_emit(expr->body[0], parent_numArgs, outputFile); fprintf(outputFile, "\tMOV GP1, CRSh\n\tANDI GP1, 224\n\tLDI GP2, 192\n\tCPSE GP1, GP2\n\tJMP error_notproc\n\tANDI CRSh, 31\n\tLD GP1, Y;CRS\n\tMOV CRSl, GP1\n\tMOV CRSh, zeroReg\n"); } else { fprintf(stderr, "ERROR 26: No primitive '%s' taking %i arguments.\n", expr->primproc, expr->numBody); exit(1); } break; default: // this state really shouldn't be reached... fprintf(outputFile, "ERROR 27: Internal Error"); exit(EXIT_FAILURE); } }
int main(int argc, char *argv[]) { // First, we process the user's command-line arguments, which dictate the input file // and target processor. char* fname, *inname, *outname; int c; opterr = 0; while ((c = getopt (argc, argv, "iaucpsovrm:d:t:")) != -1) switch (c) { case 'i': opt_includeonce = false; break; case 'u': opt_upload = true; case 'a': opt_assemble = true; break; case 'c': opt_cleanup = true; break; case 'p': opt_primitives = false; break; case 's': opt_stdlib = false; break; case 'o': opt_aggressive = false; break; case 'v': opt_verbose = true; break; case 'r': opt_verify = true; break; case 'm': model = optarg; break; case 'd': device = optarg; break; case 't': treeshaker_max_rounds = atoi(optarg); break; case '?': if (optopt == 'm') fprintf (stderr, "Option -%c requires an argument.\n", optopt); else if (isprint (optopt)) fprintf (stderr, "Unknown option `-%c'.\n", optopt); else fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt); return 1; default: abort (); } fprintf(stdout, "Microscheme 0.8, (C) Ryan Suchocki\n"); if (argc < 2) { fprintf(stdout, "usage: microscheme [-iaucpsov] [-m model] [-d device] [-t treeshaker-rounds] program[.ms]\n"); return(EXIT_FAILURE); } fname=argv[optind]; if (strncmp(fname + strlen(fname) - 3, ".ms", 3) == 0) fname[strlen(fname) - 3] = 0; inname=str_clone_more(fname, 3); outname=str_clone_more(fname, 2); strcat(inname, ".ms"); strcat(outname, ".s"); if (argc == optind) { fprintf(stderr, "No input file.\n"); exit(EXIT_FAILURE); } if (argc > optind + 1) { fprintf(stderr, "Multiple input files not yet supported.\n"); exit(EXIT_FAILURE); } // This function controls the overall compilation process, which is implemented // as four seperate phases, invoked in order. // 1) Lex the file lexer_tokenNode *root = NULL; if (opt_primitives) root = lexer_lexBlob(src_primitives_ms, src_primitives_ms_len, root); if (opt_stdlib) root = lexer_lexBlob(src_stdlib_ms, src_stdlib_ms_len, root); root = lexer_lexFile(inname, root); globalIncludeList = try_malloc(sizeof(char*)); globalIncludeList[0] = str_clone(inname); globalIncludeListN = 1; // 2) Parse the file AST_expr *ASTroot = parser_parseFile(root->children, root->numChildren, true); // (We can free the memory used by the lexer once the parser has finished)... lexer_freeTokenTree(root); // We set up a global environment: globalEnv = try_malloc(sizeof(Environment)); scoper_initEnv(globalEnv); // And hand it to the scoper... currentEnvironment = globalEnv; // At the top level, there is no 'current closure', and hence no 'current closure environment' currentClosureEnvironment = NULL; // 3) Scope the file: ASTroot = scoper_scopeExpr(ASTroot); numPurgedGlobals = -1; int latestpurge = -2; int rounds = 0; if (opt_aggressive) { globalEnv->realAddress = try_malloc(sizeof(int) * globalEnv->numBinds); int i; for (i = 0; i < globalEnv->numBinds; i++) { globalEnv->realAddress[i] = 0; } while ((numPurgedGlobals > latestpurge) && (rounds < treeshaker_max_rounds)) { //fprintf(stderr, ">> ROUND %i\n", roundi); rounds++; latestpurge = numPurgedGlobals; treeshaker_shakeExpr(ASTroot); treeshaker_purge(); //fprintf(stderr, ">> Aggressive: %i globals purged!\n", numPurgedGlobals); } fprintf(stdout, ">> Treeshaker: After %i rounds: %i globals purged! %i bytes will be reserved.\n", rounds, numPurgedGlobals, numUsedGlobals * 2); if (opt_verbose) { fprintf(stdout, ">> Remaining globals: ["); int i; for (i = 0; i < globalEnv->numBinds; i++) { if (globalEnv->realAddress[i] >= 0) fprintf(stdout, "%s ", globalEnv->binding[i]); } fprintf(stdout, "]\n"); } } else { numUsedGlobals = globalEnv->numBinds; } // 4) Generate code. (Starting with some preamble) FILE *outputFile; outputFile = fopen(outname, "w"); codegen_emitModelHeader(model, outputFile); codegen_emitPreamble(outputFile, numUsedGlobals); // Next, we recursively emit code for the actual program body: codegen_emit(ASTroot, 0, outputFile, model, NULL, opt_aggressive, globalEnv); // Finally, we emit some postamble code codegen_emitPostamble(outputFile); fclose(outputFile); // Finally, the memory allocated during parsing can be freed. parser_freeAST(ASTroot); freeEnvironment(globalEnv); // If we've reached this stage, then everything has gone OK: fprintf(stdout, ">> %i lines compiled OK\n", fileLine); char cmd[100]; char *STR_LEVEL, *STR_TARGET, *STR_PROG, *STR_BAUD; if (strcmp(model, "MEGA") == 0) { STR_LEVEL = "avr6"; STR_TARGET = "atmega2560"; STR_PROG = "wiring"; STR_BAUD = "115200"; } else if (strcmp(model, "UNO") == 0) { STR_LEVEL = "avr5"; STR_TARGET = "atmega328p"; STR_PROG = "arduino"; STR_BAUD = "115200"; } else if (strcmp(model, "LEO") == 0) { STR_LEVEL = "avr5"; STR_TARGET = "atmega32u4"; STR_PROG = "arduino"; STR_BAUD = "115200"; } else { fprintf(stderr, "Device not supported.\n"); return EXIT_FAILURE; } if (opt_assemble) { if (strcmp(model, "") == 0) { fprintf(stderr, "Model Not Set. Cannot assemble.\n"); return EXIT_FAILURE; } fprintf(stderr, ">> Assembling...\n"); sprintf(cmd, "avr-gcc -mmcu=%s -o %s.elf %s.s", STR_LEVEL, fname, fname); try_execute(cmd); sprintf(cmd, "avr-objcopy --output-target=ihex %s.elf %s.hex", fname, fname); try_execute(cmd); } if (opt_upload) { if (strcmp(device, "") == 0) { fprintf(stderr, "Device Not Set. Cannot upload.\n"); return EXIT_FAILURE; } fprintf(stderr, ">> Uploading...\n"); char *opt1, *opt2; if (opt_verbose) opt1 = "-v"; else opt1 = ""; if (opt_verify) opt2 = ""; else opt2 = "-V"; sprintf(cmd, "avrdude %s %s -p %s -c %s -P %s -b %s -D -U flash:w:%s.hex:i", opt1, opt2, STR_TARGET, STR_PROG, device, STR_BAUD, fname); try_execute(cmd); } if (opt_cleanup) { fprintf(stdout, ">> Cleaning Up...\n"); #ifdef __WIN32 // Defined for both 32 and 64 bit environments sprintf(cmd, "del %s.s %s.elf %s.hex", fname, fname, fname); #else sprintf(cmd, "rm -f %s.s %s.elf %s.hex", fname, fname, fname); #endif try_execute(cmd); } fprintf(stdout, ">> Finished.\n"); try_free(inname); try_free(outname); int i; for (i=0; i<globalIncludeListN; i++) try_free(globalIncludeList[i]); try_free(globalIncludeList); return EXIT_SUCCESS; }
int main(int argc, char *argv[]) { // First, we process the user's command-line arguments, which dictate the input file // and target processor. char *inname, *outname, *basename, *shortbase; int c; fprintf(stdout, "Microscheme 0.9.3, (C) Ryan Suchocki\n"); char *helpmsg = "\nUsage: microscheme [-aucvrio] [-m model] [-d device] [-p programmer] [-w filename] [-t rounds] program[.ms]\n\n" "Option flags:\n" " -a Assemble (implied by -u) (requires -m)\n" " -u Upload (requires -d)\n" " -c Cleanup (removes intermediate files)\n" " -v Verbose\n" " -r Verify (Uploading takes longer)\n" " -i Allow the same file to be included more than once\n" " -o Disable optimisations \n" " -h Show this help message \n\n" "Configuration flags:\n" " -m model Specify a model (UNO/MEGA/LEO...)\n" " -d device Specify a physical device\n" " -p programmer Tell avrdude to use a particular programmer\n" " -w files 'Link' with external C or assembly files\n" " -t rounds Specify the maximum number of tree-shaker rounds\n"; while ((c = getopt(argc, argv, "hiaucovrm:d:p:t:w:")) != -1) switch (c) { case 'h': fprintf(stdout, "%s", helpmsg); exit(EXIT_SUCCESS); break; case 'i': opt_includeonce = false; break; case 'u': opt_upload = true; case 'a': opt_assemble = true; break; case 'c': opt_cleanup = true; break; //case 's': opt_softreset = true; break; case 'o': opt_aggressive = false; break; case 'v': opt_verbose = true; break; case 'r': opt_verify = true; break; case 'm': model = optarg; break; case 'd': device = optarg; break; case 'p': programmer = optarg; break; case 'w': linkwith = optarg; break; case 't': treeshaker_max_rounds = atoi(optarg); break; case '?': if (optopt == 'm') fprintf (stderr, "Option -%c requires an argument.\n", optopt); else if (isprint (optopt)) fprintf (stderr, "Unknown option `-%c'.\n", optopt); else fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt); return 1; default: abort (); } if (argc < 2) { fprintf(stdout, "%s", helpmsg); return(EXIT_FAILURE); } inname=argv[optind]; basename=str_clone(inname); #ifdef __WIN32 // Defined for both 32 and 64 bit environments char delimit = '\\'; #else char delimit = '/'; #endif if (strrchr(basename, delimit)) { shortbase = strrchr(basename, delimit) + 1; } else { shortbase = basename; } shortbase[strcspn(shortbase, ".")] = 0; outname=str_clone_more(shortbase, 2); strcat(outname, ".s"); if (argc == optind) { fprintf(stderr, "No input file.\n"); exit(EXIT_FAILURE); } if (argc > optind + 1) { fprintf(stderr, "Multiple input files not yet supported.\n"); exit(EXIT_FAILURE); } model_info theModel; int i; bool found = false; for (i = 0; i<numModels; i++) { if (strcmp(models[i].name, model) == 0) { theModel = models[i]; found = true; } } if (!found) { fprintf(stderr, "Device not supported.\n"); return EXIT_FAILURE; } // This function controls the overall compilation process, which is implemented // as four seperate phases, invoked in order. // 1) Lex the file lexer_tokenNode *root = NULL; root = lexer_lexBlob(src_primitives_ms, src_primitives_ms_len, root); root = lexer_lexBlob(src_stdlib_ms, src_stdlib_ms_len, root); root = lexer_lexFile(inname, root); globalIncludeList = try_malloc(sizeof(char*)); globalIncludeList[0] = str_clone(inname); globalIncludeListN = 1; // 2) Parse the file AST_expr *ASTroot = parser_parseFile(root->children, root->numChildren); // (We can free the memory used by the lexer once the parser has finished)... lexer_freeTokenTree(root); // We set up a global environment: globalEnv = try_malloc(sizeof(Environment)); scoper_initEnv(globalEnv); // And hand it to the scoper... currentEnvironment = globalEnv; // At the top level, there is no 'current closure', and hence no 'current closure environment' currentClosureEnvironment = NULL; // 3) Scope the file: ASTroot = scoper_scopeExpr(ASTroot); numPurgedGlobals = -1; int latestpurge = -2; int rounds = 0; if (opt_aggressive) { globalEnv->realAddress = try_malloc(sizeof(int) * globalEnv->numBinds); int i; for (i = 0; i < globalEnv->numBinds; i++) { globalEnv->realAddress[i] = 0; } while ((numPurgedGlobals > latestpurge) && (rounds < treeshaker_max_rounds)) { //fprintf(stderr, ">> ROUND %i\n", roundi); rounds++; latestpurge = numPurgedGlobals; treeshaker_shakeExpr(ASTroot); treeshaker_purge(); //fprintf(stderr, ">> Aggressive: %i globals purged!\n", numPurgedGlobals); } fprintf(stdout, ">> Treeshaker: After %i rounds: %i globals purged! %i bytes will be reserved.\n", rounds, numPurgedGlobals, numUsedGlobals * 2); if (opt_verbose) { fprintf(stdout, ">> Remaining globals: ["); int i; for (i = 0; i < globalEnv->numBinds; i++) { if (globalEnv->realAddress[i] >= 0) fprintf(stdout, "%s ", globalEnv->binding[i]); } fprintf(stdout, "]\n"); } } else { numUsedGlobals = globalEnv->numBinds; } // 4) Generate code. (Starting with some preamble) FILE *outputFile; outputFile = fopen(outname, "w"); if (!outputFile) { fprintf(stderr, ">> Error! Could not open output file.\n"); exit(EXIT_FAILURE); } codegen_emitModelHeader(theModel, outputFile); codegen_emitPreamble(outputFile); // Next, we recursively emit code for the actual program body: codegen_emit(ASTroot, 0, outputFile); // Finally, we emit some postamble code codegen_emitPostamble(outputFile); fclose(outputFile); // Finally, the memory allocated during parsing can be freed. parser_freeAST(ASTroot); freeEnvironment(globalEnv); // If we've reached this stage, then everything has gone OK: fprintf(stdout, ">> %i lines compiled OK\n", fileLine); char cmd[500]; if (opt_assemble) { if (strcmp(model, "") == 0) { fprintf(stderr, "Model Not Set. Cannot assemble.\n"); return EXIT_FAILURE; } fprintf(stderr, ">> Assembling...\n"); sprintf(cmd, "avr-gcc -mmcu=%s -o %s.elf %s.s %s", theModel.STR_TARGET, shortbase, shortbase, linkwith); try_execute(cmd); sprintf(cmd, "avr-objcopy --output-target=ihex %s.elf %s.hex", shortbase, shortbase); try_execute(cmd); } // if (opt_softreset && theModel.software_reset) { // fprintf(stdout, ">> Attempting software reset...\n"); // int fd = -1; // struct termios options; // tcgetattr(fd, &options); // cfsetispeed(&options, B1200); // cfsetospeed(&options, B1200); // options.c_cflag |= (CLOCAL | CREAD | CS8 | HUPCL); // options.c_cflag &= ~(PARENB | CSTOPB); // tcsetattr(fd, TCSANOW, &options); // fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY); // if (fd == -1) { // fprintf(stderr, ">> Warning: Unable to open %s for soft reset. (%s)\n", device, strerror(errno)); // } else { // close(fd); // } // } if (opt_upload) { if (strcmp(device, "") == 0) { fprintf(stderr, "Device Not Set. Cannot upload.\n"); return EXIT_FAILURE; } if (strcmp(programmer, "") == 0) { programmer = theModel.STR_PROG; } fprintf(stderr, ">> Uploading...\n"); char *opt1, *opt2; if (opt_verbose) opt1 = "-v"; else opt1 = ""; if (opt_verify) opt2 = ""; else opt2 = "-V"; sprintf(cmd, "avrdude %s %s -p %s -P %s -b %s -c %s -D -U flash:w:%s.hex:i", opt1, opt2, theModel.STR_TARGET, device, theModel.STR_BAUD, programmer, shortbase); try_execute(cmd); } if (opt_cleanup) { fprintf(stdout, ">> Cleaning Up...\n"); #ifdef __WIN32 // Defined for both 32 and 64 bit environments sprintf(cmd, "del %s.s %s.elf %s.hex", shortbase, shortbase, shortbase); #else sprintf(cmd, "rm -f %s.s %s.elf %s.hex", shortbase, shortbase, shortbase); #endif try_execute(cmd); } fprintf(stdout, ">> Finished.\n"); try_free(basename); try_free(outname); for (i=0; i<globalIncludeListN; i++) try_free(globalIncludeList[i]); try_free(globalIncludeList); return EXIT_SUCCESS; }