#include "nbasic.h" #include #include #include #define SIXTEENBIT 65536 //--------------------------------------- Token::Token(int num_, int type_, int line_, const char* val, int location_) { index = num_; type = type_; line = line_; location = location_; next = prev = NULL; int len = strlen(val); if (len == 0) { value = NULL; return; } value = new char[len+1]; memset(value,0,len+1); strcpy(value, val); valuelen = len; /* if (type == INCBIN) { printf("incbin\n"); fflush(stdout); } */ } Token::~Token() { if (value != NULL) delete value; if (next != NULL) delete next; } //--------------------------------------- TokenList::TokenList() { num_tokens = 0; first = marker = last = NULL; } TokenList::~TokenList() { last = NULL; marker = NULL; if (first != NULL) delete first; //blows away whole list safely } bool TokenList::Match(int start, int type) { const Token *t = GetToken(start); return (t != NULL && t->type == type); } bool TokenList::Match(int start, int type0, int type1) { return Match(start, type0) && Match(start+1, type1); } bool TokenList::Match(int start, int type0, int type1, int type2) { return Match(start, type0, type1) && Match(start+2, type2); } bool TokenList::Match(int start, int type0, int type1, int type2, int type3) { return Match(start, type0, type1, type2) && Match(start+3, type3); } void TokenList::AddToken(int type, const char *val, int len, int linenum, int loc) { char str[len+1]; memset(str,0,len+1); strncpy(str,val,len); Token *t = new Token(num_tokens, type, linenum, str, loc); num_tokens++; if(first == NULL) { first = t; last = t; } else { last->next = t; t->prev = last; last = last->next; } } void TokenList::RemoveToken(int n) { //set marker to the target token, and get handles on surrounding tokens if (first == NULL || n < 0 || n >= num_tokens) return; if (marker == NULL) marker = first; while(marker->index < n) marker = marker->next; while(marker->index > n) marker = marker->prev; Token* tnext = marker->next; Token* tprev = marker->prev; //delete the token if (first == marker) first = tnext; //so we don't lose the whole stream marker->next = NULL; marker->prev = NULL; delete marker; num_tokens--; //re-point marker and hook up others if (tprev != NULL) marker = tprev; else marker = tnext; if (tprev !=NULL) tprev->next = tnext; if (tnext !=NULL) tnext->prev = tprev; //decrement downstream index nums Token* temp = tnext; while (temp != NULL) { temp->index--; temp = temp->next; } } const Token* TokenList::GetToken(int n) { if (first == NULL || n < 0 || n >= num_tokens) return NULL; if (marker == NULL) marker = first; while(marker->index < n) marker = marker->next; while(marker->index > n) marker = marker->prev; return marker; } Token* TokenList::GetTokenPointer(int n) { if (GetToken(n) == NULL) return NULL; return marker; } void TokenList::SetTokenLocation(int i, int loc) { if (GetToken(i) != NULL) marker->location = loc; } bool TokenList::HasToken(const char *value) { const Token *t = first; while(t!=NULL) { if (!strcmp(t->value, value)) return true; t = t->next; } return false; } int TokenList::NumTokens() const { return num_tokens; /* int n = 0; const Token *t = first; while(t!=NULL) { n++; t = t->next; } return n; */ } //--------------------------------------- NBasic::NBasic() { verbose = true; numfiles = 0; numlines = 0; num_regexes = 0; next_autolabel = 1; } NBasic::~NBasic() { //empty } void NBasic::SetVerbosity(bool b) { verbose = b; } void NBasic::SetMaxFiles(int n) { filelines = new int[n]; filenames = new const char*[n]; } int NBasic::TokenType(int i) { if (itype; return PAST_END_FILE; } const char* NBasic::TokenValue(int i) { return tokens.GetToken(i)->value; } void NBasic::AddRegEx(const char *exp, int result, bool require_whitespace) { if (num_regexes == MAX_REGEXES) { printf("ERROR: Max number of regular expressions. Change #define MAX_REGEXES\n"); exit(0); } regex_returns[num_regexes] = result; regexes[num_regexes].Load(exp); regex_requirewhite[num_regexes] = require_whitespace; num_regexes++; } bool IsStartAsm(const char *s) { int i=0; while(s[i]==' ' || s[i]=='\t') i++; if (strncmp(&s[i],"asm",3)!=0) return false; i+=3; while(s[i]==' ' || s[i]=='\t' || s[i]=='\r' || s[i]=='\n') i++; if (s[i]==0) return true; return false; } bool IsEndAsm(const char *s) { int i=0; while(s[i]==' ' || s[i]=='\t') i++; if (strncmp(&s[i],"endasm",6)!=0) return false; i+=6; while(s[i]==' ' || s[i]=='\t' || s[i]=='\r' || s[i]=='\n') i++; if (s[i]==0) return true; return false; } bool IsAsmLine(const char *s, int &start) { int i=0; while(s[i]==' ' || s[i]=='\t') i++; if (strncmp(&s[i],"asmline",7)!=0) return false; start = i+7; return true; } bool NBasic::TokenizeLine(const char *line, int linenum) { static bool in_asm_block = false; int len = strlen(line); if (len == 0) return true; //sure, we can tokenize a blank line! //special case, single ASM line int asmstart = 0; if (IsAsmLine(line,asmstart)) { tokens.AddToken(ASM, NULL, 0, linenum); tokens.AddToken(ASMTEXT, &line[asmstart], len-asmstart, linenum); tokens.AddToken(ENDASM, NULL, 0, linenum); return true; } //special case, entering ASM block if (IsStartAsm(line)) { tokens.AddToken(ASM, NULL, 0, linenum); in_asm_block = true; return true; } //special case, within ASM block if (in_asm_block) { if (IsEndAsm(line)) { tokens.AddToken(ENDASM, NULL, 0, linenum); in_asm_block = false; return true; } tokens.AddToken(ASMTEXT, line, len, linenum); return true; } //general case, parse normally for(int i = 0; i < num_regexes; i++) //try matching against each regex { int match = regexes[i].Matches(line); if (match > -1) { //token match! check whitespace requirements if ((!regex_requirewhite[i]) || (regex_requirewhite[i] && ( match == len || regexes[whitespace_regex].Matches(&line[match])>-1 || regexes[newline_regex].Matches(&line[match])>-1 ) )) { //we're good. add the token, check the rest of the line tokens.AddToken(regex_returns[i], line, match, linenum); return TokenizeLine(&line[match], linenum); } } } return false; } void NBasic::TrimWhitespace() { //remove WHITESPACE, NEWLINE, and COMMENT tokens that aren't in an asm block int i = 0; bool asmblock = false; while(i < tokens.NumTokens()) { int type = TokenType(i); if (asmblock) { if (type == ENDASM) asmblock = false; i++; } else { if (type == WHITESPACE || type == NEWLINE || type == COMMENT) tokens.RemoveToken(i); else i++; if (type == ASM) asmblock = true; } } } void NBasic::CompactMath() { bool done = false; while(!done) { done = true; //set false when no longer true for(int i = 0; i < tokens.NumTokens();) { if (IsMath(i) && tokens.Match(i+1,NUMBER,NUMBER)) { int type = TokenType(i); if (type==PLUS || type==MINUS || type==SHIFTLEFT || type==SHIFTRIGHT || type == BITAND || type == BITOR || type == BITEOR) { done = false; Token *t = tokens.GetTokenPointer(i); int one = NumberValue(TokenValue(i+1), t->line); int two = NumberValue(TokenValue(i+2), t->line); t->type = NUMBER; if (t->value != NULL) delete t->value; t->value = new char[8]; int result = (type==PLUS ? one+two : (type==MINUS ? one-two : (type==SHIFTLEFT ? one<>two : (type==BITAND?/*BITAND*/one&two:(type==BITOR?one | two:(one ^ two))))))); sprintf(t->value,"%i\0", (result+SIXTEENBIT)%SIXTEENBIT); tokens.RemoveToken(i+1); tokens.RemoveToken(i+1); i++; } else i+=3; } else { i++; } } } } #define FBUFSIZE 1024 void NBasic::AddFile(const char *filename) { FILE *f = fopen(filename,"r"); if (!f) { fprintf(stderr,"Could not open file %s for reading. Aborting.\n",filename); exit(0); } char buf[FBUFSIZE]; int line = 0; while(fgets(buf,FBUFSIZE,f) != NULL) { line++; TokenizeLine(buf,line+numlines); } fclose(f); filenames[numfiles] = filename; filelines[numfiles++] = line; numlines += line; if (verbose) printf("Read file %s (%i lines)\n",filename,line); fflush(stdout); } char* NBasic::MakeNumber(const char* n, int line) { int number = NumberValue(n, line); char *s = new char[8]; //more than big enough sprintf(s,"%i\0",number); return s; } int NBasic::NumberValue(const char* n, int line) { int number = 0; if (n[0] == '$') { for(int i = 1; i < strlen(n); i++) number = number*16 + (n[i]>='0'&&n[i]<='9' ? n[i]-'0' : (n[i]>='a'&&n[i]<='f' ? n[i]-'a'+10 : n[i]-'A'+10)); } else if (n[0]=='%') { for(int i = 1; i < strlen(n); i++) number = number*2+(n[i]=='0' ? 0 : 1); } else if (n[0]>='0' && n[0]<='9') { for(int i = 0; i < strlen(n); i++) number = number*10+(n[i]-'0'); } else CompileError("number",line); number = number % SIXTEENBIT; //we'll never need anything bigger than that (CPU limitation) return number; } void NBasic::CompileError(const char *s, int line) { int whichline = line; int whichfile = 0; while (whichline > filelines[whichfile]) { whichline -= filelines[whichfile]; whichfile++; } fprintf(stderr,"\nERROR on line %i of file '%s' compiling %s statement.\n", whichline,filenames[whichfile],s); exit(0); } void NBasic::Compile() { TrimWhitespace(); CompactMath(); AddVariable("nbasic_stack", 0x100, 2, 0x100); int numtokens = tokens.NumTokens(); int i = 0; while (i < numtokens) { i += Compile(i); } } int NBasic::Compile(int i) { const Token* t = tokens.GetToken(i); int type = t->type; int line = t->line; //printf("line %i: %s\n", line, t->value);fflush(stdout); switch(type) { case ENDPROG: //deprecated if (verbose) printf("Encountered program end at line %i\n",line); return tokens.NumTokens(); //past end of input. stop compile case ASM: return CompileAsm(i, type, line); case LABEL: case ENDASM: case ARRAY: return CompileIdentifiers(i, type, line); case PUSH: case POP: return CompilePush(i, type, line); case GOTO: case GOSUB: case RETURN: case RESUME: return CompileJump(i, type, line); case COMMENT: case WHITESPACE: return 1; case DATA: return CompileData(i, type, line); case SET: return CompileSet(i, type, line); case INC: case DEC: return CompileIncrement(i, type, line); case IF: return CompileConditional(i, type, line); default: break; } CompileError("",tokens.GetToken(i)->line); return -1; } void NBasic::CreateAutoVariables() { int n = asmlist.NumTokens(); for(int i = 0; i < n; i++) { const Token *t = asmlist.GetToken(i); if (t->type==STAp && (t->value[0]<'0' || t->value[0]>'9')) AddVariable(t->value); } } void NBasic::VarError(const char* name) { fprintf(stderr, "Redefinition of variable %s. Aborting.\n", name); exit(0); } void NBasic::VarAllocError(const char* name) { fprintf(stderr, "Error allocating memory for variable %s. Aborting.\n", name); exit(0); } void NBasic::OutputVariables(FILE *f) { TokenList tempvars; int numtokens = variables.NumTokens(); //add absolute location vars for(int i=0; itype == 2) { if(tempvars.HasToken(t->value)) VarError(t->value); tempvars.AddToken(t->type, t->value, t->valuelen, t->line, t->location); } } //add zeropage vars for(int i=0; itype == 1) { if(tempvars.HasToken(t->value)) VarError(t->value); tempvars.AddToken(t->type, t->value, t->valuelen, t->line, t->location); } } //add auto-allocated pre-sized vars for(int i=0; itype == 0 && t->line != -1) { if(tempvars.HasToken(t->value)) VarError(t->value); tempvars.AddToken(t->type, t->value, t->valuelen, t->line, t->location); } } //add auto-allocated default vars for(int i=0; itype == 0 && t->line == -1) if(!tempvars.HasToken(t->value)) tempvars.AddToken(t->type, t->value, t->valuelen, 1, t->location); } //now try to allocate memory for each variable int numvars = tempvars.NumTokens(); bool memory[SIXTEENBIT]; //true means filled for(int i=0; ilocation; int len = t->line; if(t->type == 2 && len != 0) //absolute { for(int j = start; j < start+len; j++) { if(memory[j]) VarAllocError(t->value); memory[j] = true; } } else if (t->type == 1 && len != 0) //zeropage { start = 0; bool found = false; while(start < 0x100-len && !found) { if(!memory[start]) { found = true; for(int j = 0; j < len; j++) if(memory[start+j]) found = false; } if (!found) start++; } if (!found) VarAllocError(t->value); for(int j = 0; j < len; j++) memory[start+j] = true; tempvars.SetTokenLocation(i, start); } else if(len != 0) //auto allocate { start = 0; bool found = false; while(start < 0xffff-len && !found) { if(!memory[start]) { found = true; for(int j = 0; j < len; j++) if(memory[start+j]) found = false; } if (!found) start++; } if (!found) VarAllocError(t->value); for(int j = 0; j < len; j++) memory[start+j] = true; tempvars.SetTokenLocation(i, start); } } //actually output them now for(int i=0; ivalue, t->location); } } bool NBasic::VariableExists(const char* name) { for(int i = 0; i < variables.NumTokens(); i++) if (!strcmp(name, variables.GetToken(i)->value)) return true; return false; } void NBasic::AddVariable(const char* name, int length, int vartype, int loc) { if(vartype==2 && strcmp(name,"nbasic_stack")) //warn user if it conflicts with the stack { for(int i=loc; i < loc+length; i++) if (i>=256 && i<= 511) { fprintf(stderr,"Declaration of variable '%s' conflicts with NES stack ($100-$1FF)\n",name); fprintf(stderr,"Compile Aborted\n");fflush(stdout); exit(0); } } variables.AddToken(vartype, name, strlen(name), length, loc); } int NBasic::CompileIdentifiers(int i, int type, int line) { const Token* t; switch(type) { case LABEL: t = tokens.GetToken(i); asmlist.AddToken(ASMLABEL, t->value, t->valuelen, line); return 1; case ARRAY: if(tokens.Match(i,ARRAY,VAR,NUMBER)) { AddVariable(TokenValue(i+1), NumberValue(TokenValue(i+2),line)); return 3; } else if(tokens.Match(i,ARRAY,ZEROPAGE,VAR,NUMBER)) { AddVariable(TokenValue(i+2), NumberValue(TokenValue(i+3),line), 1); return 4; } else if(tokens.Match(i+1,/*ARRAY,*/ABSOLUTE,NUMBER,VAR,NUMBER)) { AddVariable(TokenValue(i+3), NumberValue(TokenValue(i+4),line),2, NumberValue(TokenValue(i+2),line)); return 5; } CompileError("array declaration",line); //invalid array declaration syntax case ENDASM: CompileError("endasm",line); //should never see it here } } int NBasic::CompileAsm(int i, int type, int line) { bool done = false; int added = 1; while (!done) { const Token* t = tokens.GetToken(i + added++); if (t!=NULL && t->type!=ENDASM) asmlist.AddToken(ASMTEXT, t->value, t->valuelen, t->line); else done = true; } return added; } int NBasic::CompileJump(int i, int type, int line) { const Token* t; switch(type) { case RESUME: asmlist.AddToken(RTI, "", 0, line); return 1; case RETURN: asmlist.AddToken(RTS, "", 0, line); return 1; case GOTO: case GOSUB: if (tokens.Match(i+1, VAR)) { t = tokens.GetToken(i+1); asmlist.AddToken((type==GOTO ? JMP : JSR), t->value, t->valuelen, line); return 2; } break; } CompileError(type==GOTO ? "goto" : "gosub", line); } bool IsHex(char c) { if ('0'<=c && c<='9') return true; if ('a'<=c && c<='f') return true; if ('A'<=c && c<='F') return true; return false; } int HexValue(char c) { if ('0'<=c && c<='9') return c-'0'; if ('a'<=c && c<='f') return c-'a'+10; if ('A'<=c && c<='F') return c-'A'+10; return 0; } int NBasic::CompileData(int toknum, int type, int line) { const Token *t = tokens.GetToken(toknum); if (t==NULL || t->value==NULL) CompileError("data", line); const char *s = t->value; int i = 4, len = strlen(s), numints=0; if (len > 80) CompileError("data (line too long)", line); int ints[len]; while (s[i]==' ' || s[i]=='\t') i++; //skip initial whitespace //value line includes data keyword until (including) \n bool in_string = false; bool between_values = false; while (s[i]!='\n' && s[i]!=0) { if (between_values) { while (s[i]==' ' || s[i]=='\t') i++; //whitespace if (s[i++]!=',') CompileError("data",line); while (s[i]==' ' || s[i]=='\t') i++; //whitespace between_values = false; } else if (!in_string) { if (s[i]=='\"') { in_string = true; i++; } else if (s[i]=='$') //hexadecimal { int temp=0; i++; if (!IsHex(s[i])) CompileError("data (hexadecimal)", line); while (IsHex(s[i])) temp = temp*16+HexValue(s[i++]); ints[numints++] = temp; between_values = true; } else if (s[i]=='%') //binary { int temp=0; i++; if (s[i]!='0' && s[i]!='1') CompileError("data (binary)", line); while (s[i]=='0' || s[i]=='1') temp = temp*2 + (s[i]-'0'); ints[numints++] = temp; between_values = true; } else if ('0'<=s[i] && s[i]<='9') //decimal { int temp = 0; while ('0'<=s[i] && s[i]<='9') temp = temp*10 + s[i++]-'0'; if (temp>255) CompileError("data (value too large)", line); ints[numints++] = temp; between_values = true; } else between_values = true; } else { if (s[i]=='\"') //quote { in_string = false; between_values = true; i++; } else if (s[i]=='\\') //backslash { ints[numints++] = s[i+1]; i+=2; } else ints[numints++] = s[i++]; } } //now create the ASM output int startint = 0; while (startint < numints) { int endint = startint+10; if (endint > numints) endint = numints; char outbuf[64]; sprintf(outbuf, " .db "); for (int i = startint; i < endint; i++) { if (i!=startint) sprintf(&outbuf[strlen(outbuf)], ",%i", ints[i]); else sprintf(&outbuf[strlen(outbuf)], "%i", ints[i]); } sprintf(&outbuf[strlen(outbuf)], "\n"); startint += 10; asmlist.AddToken(ASMTEXT, outbuf, strlen(outbuf), line); } return 1; } bool NBasic::IsConditional(int token_index) { switch(TokenType(token_index)) { case ISEQUAL: case NOTEQUAL: case ISLESS: case ISGREATER: case LESSEQ: case GREATEREQ: return true; default: break; } return false; } int NBasic::ConditionalOpposite(int cond) { switch(cond) { case ISEQUAL: return ISEQUAL; case NOTEQUAL: return NOTEQUAL; case ISLESS: return ISGREATER; case ISGREATER: return ISLESS; case LESSEQ: return GREATEREQ; case GREATEREQ: return LESSEQ; } return -1; } int NBasic::CompileConditional(int i, int type, int line) { int j = -1; //indicates start of second half of the conditional int cond = -1; //which conditional // A cond VAR // A cond NUM // X cond math // Y cond math if( (tokens.Match(i+1,X) || tokens.Match(i+1,Y) || tokens.Match(i+1,A)) && IsConditional(i+2) && IsMath(i+3)) { int reg = TokenType(i+1); //which register cond = TokenType(i+2); //which conditional int type = TokenType(i+3); //which math type int len = 1; if (type == VAR) { asmlist.AddToken(reg==A?CMPp:(reg==X?CPXp:CPYp), TokenValue(i+3), strlen(TokenValue(i+3)), line); } else if (type == NUMBER) { char *num = MakeNumber(TokenValue(i+3), line); asmlist.AddToken(reg==A?CMPi:(reg==X?CPXi:CPYi), num, strlen(num), line); delete num; } else //other math { //if(reg==A) CompileError("conditional",line); len = CompileMath(i+3, type, line); asmlist.AddToken(STAp,"nbasic_temp",strlen("nbasic_temp"),line); asmlist.AddToken( reg==X ? CPXp : CPYp, "nbasic_temp", strlen("nbasic_temp"), line); } j = len + 3; } // VAR cond math (compile math, opposite cond) // NUM cond math (compile math, opposite cond) else if((tokens.Match(i+1,VAR) || tokens.Match(i+1,NUMBER)) && IsConditional(i+2) && IsMath(i+3)) { cond = ConditionalOpposite(TokenType(i+2)); j = CompileMath(i+3, TokenType(i+3), line) + 3; if (TokenType(i+1) == VAR) asmlist.AddToken(CMPp, TokenValue(i+1), strlen(TokenValue(i+1)), line); else { char *num = MakeNumber(TokenValue(i+1), line); asmlist.AddToken(CMPi, num, strlen(num), line); delete num; } } // math cond VAR (same cond) // math cond NUM (same cond) // math cond math else if (IsConditional(i+1+MathLength(i+1,line)) && IsMath(i+2+MathLength(i+1,line))) { int len = CompileMath(i+1, TokenType(i+1), line); cond = TokenType(i+1+len); if (TokenType(i+2+len) == VAR) { asmlist.AddToken(CMPp, TokenValue(i+2+len), strlen(TokenValue(i+2+len)), line); j = len + 3; } else if (TokenType(i+2+len) == NUMBER) { char *num = MakeNumber(TokenValue(i+2+len), line); asmlist.AddToken(CMPi, num, strlen(num), line); delete num; j = len + 3; } else { asmlist.AddToken(STAp, "nbasic_temp", strlen("nbasic_temp"), line); int two = CompileMath(i+2+len, TokenType(i+2+len), line); cond = ConditionalOpposite(cond); j = len + 2 + two; } } if (j==-1) CompileError("conditional", line); if (tokens.Match(i+j, BRANCHTO, VAR)) { const char* label = TokenValue(i+j+1); int len = strlen(label); switch(cond) // branch on same case { case ISEQUAL: asmlist.AddToken(BEQ, label, len, line); break; case NOTEQUAL: asmlist.AddToken(BNE, label, len, line); break; case ISLESS: asmlist.AddToken(BMI, label, len, line); break; case ISGREATER: asmlist.AddToken(BCS, label, len, line); break; case LESSEQ: asmlist.AddToken(BCC, label, len, line); break; case GREATEREQ: asmlist.AddToken(BPL, label, len, line); break; default: CompileError("conditional branchto",line); break; } j+=2; } else { int my_autolabel = next_autolabel++; char autolabel[24]; sprintf(autolabel,"nbasic_autolabel_%i\0",my_autolabel); int len = strlen(autolabel); switch(cond) // branch to autolabel on opposite case { case ISEQUAL: asmlist.AddToken(BNE, autolabel, len, line); break; case NOTEQUAL: asmlist.AddToken(BEQ, autolabel, len, line); break; case ISLESS: asmlist.AddToken(BCS, autolabel, len, line); break; case ISGREATER: asmlist.AddToken(BCC, autolabel, len, line); asmlist.AddToken(BEQ, autolabel, len, line); break; case LESSEQ: asmlist.AddToken(BCS, autolabel, len, line); asmlist.AddToken(BEQ, autolabel, len, line); break; case GREATEREQ: asmlist.AddToken(BCC, autolabel, len, line); break; default: CompileError("conditional branch",line); break; } // compile conditional code (check for THEN) if (TokenType(i+j)==THEN) { j++; int typeij = TokenType(i+j); while(typeij!=ENDIF && typeij!=PAST_END_FILE) { j += Compile(i+j); typeij = TokenType(i+j); } if (typeij == PAST_END_FILE) CompileError("if..then without corresponding endif",line); j++; } else { j += Compile(i+j); } // create autolabel sprintf(autolabel,"nbasic_autolabel_%i:\0",my_autolabel); asmlist.AddToken(ASMLABEL, autolabel, strlen(autolabel), line); } return j; } int NBasic::CompileSet(int i, int type, int line) { //=============set basic memory location if (tokens.Match(i+1,VAR,A)) { asmlist.AddToken(STAp, TokenValue(i+1), strlen(TokenValue(i+1)), line); return 3; } else if (tokens.Match(i+1,NUMBER,A)) { char *num = MakeNumber(TokenValue(i+1), line); asmlist.AddToken(STAp, num, strlen(num), line); delete num; return 3; } if (tokens.Match(i+1,VAR,X)) { asmlist.AddToken(TXA,"",0,line); asmlist.AddToken(STAp, TokenValue(i+1), strlen(TokenValue(i+1)), line); return 3; } else if (tokens.Match(i+1,NUMBER,X)) { char *num = MakeNumber(TokenValue(i+1), line); asmlist.AddToken(TXA,"",0,line); asmlist.AddToken(STAp, num, strlen(num), line); delete num; return 3; } else if (tokens.Match(i,SET,VAR) && IsMath(i+2)) { const Token *t = tokens.GetToken(i+2); int len = CompileMath(i+2, t->type, t->line); t = tokens.GetToken(i+1); asmlist.AddToken(STAp, t->value, t->valuelen, line); return len+2; } else if (tokens.Match(i,SET,NUMBER) && IsMath(i+2)) { const Token *t = tokens.GetToken(i+2); int len = CompileMath(i+2, t->type, t->line); char *num = MakeNumber(TokenValue(i+1),line); asmlist.AddToken(STAp, num, strlen(num), line); delete num; return len+2; } //================ set the accumulator register else if (tokens.Match(i,SET,A,X)) { asmlist.AddToken(TXA, "", 0, line); return 3; } else if (tokens.Match(i,SET,A,Y)) { asmlist.AddToken(TYA, "", 0, line); return 3; } else if (tokens.Match(i,SET,A) && IsMath(i+2)) { const Token *t = tokens.GetToken(i+2); return 2 + CompileMath(i+2, t->type, t->line); } //================= set the X register else if (tokens.Match(i,SET,X,A)) { asmlist.AddToken(TAX, "", 0, line); return 3; } else if (tokens.Match(i,SET,X,VAR)) { const Token *t = tokens.GetToken(i+2); asmlist.AddToken(LDXp, t->value, t->valuelen, t->line); return 3; } else if (tokens.Match(i,SET,X,NUMBER)) { char *num = MakeNumber(TokenValue(i+2),line); asmlist.AddToken(LDXi, num, strlen(num), line); delete num; return 3; } else if (tokens.Match(i,SET,X) && IsMath(i+2)) { int len = CompileMath(i+2, TokenType(i+2), line); asmlist.AddToken(TAX, "", 0, line); return len + 2; } //=================== set the Y register else if (tokens.Match(i,SET,Y,A)) { asmlist.AddToken(TAY, "", 0, line); return 3; } else if (tokens.Match(i,SET,Y,VAR)) { const Token *t = tokens.GetToken(i+2); asmlist.AddToken(LDYp, t->value, t->valuelen, t->line); return 3; } else if (tokens.Match(i,SET,Y,NUMBER)) { char *num = MakeNumber(TokenValue(i+2),line); asmlist.AddToken(LDYi, num, strlen(num), line); delete num; return 3; } else if (tokens.Match(i,SET,Y) && IsMath(i+2)) { int len = CompileMath(i+2, TokenType(i+2), line); asmlist.AddToken(TAY, "", 0, line); return len + 2; } //=============set simple var array location else if (tokens.Match(i+1,BRACKETOPEN,VAR,X,BRACKETCLOSE) && IsMath(i+5)) { int len = CompileMath(i+5, TokenType(i+5), line); asmlist.AddToken(STApx, TokenValue(i+2), strlen(TokenValue(i+2)), line); return len+5; } else if (tokens.Match(i+1,BRACKETOPEN,VAR,Y,BRACKETCLOSE) && IsMath(i+5)) { int len = CompileMath(i+5, TokenType(i+5), line); asmlist.AddToken(STApy, TokenValue(i+2), strlen(TokenValue(i+2)), line); return len+5; } else if (tokens.Match(i+1,BRACKETOPEN,VAR,VAR,BRACKETCLOSE) && IsMath(i+5)) { int len = CompileMath(i+5, TokenType(i+5), line); asmlist.AddToken(LDXp, TokenValue(i+3), strlen(TokenValue(i+3)), line); asmlist.AddToken(STApx, TokenValue(i+2), strlen(TokenValue(i+2)), line); return len+5; } else if (tokens.Match(i+1,BRACKETOPEN,VAR,NUMBER,BRACKETCLOSE) && IsMath(i+5)) { int len = CompileMath(i+5, TokenType(i+5), line); asmlist.AddToken(LDXi, TokenValue(i+3), strlen(TokenValue(i+3)), line); asmlist.AddToken(STApx, TokenValue(i+2), strlen(TokenValue(i+2)), line); return len+5; } //=============set simple number array location else if (tokens.Match(i+1,BRACKETOPEN,NUMBER,X,BRACKETCLOSE) && IsMath(i+5)) { int len = CompileMath(i+5, TokenType(i+5), line); char *num = MakeNumber(TokenValue(i+2),line); asmlist.AddToken(STApx, num, strlen(num), line); delete num; return len+5; } else if (tokens.Match(i+1,BRACKETOPEN,NUMBER,Y,BRACKETCLOSE) && IsMath(i+5)) { int len = CompileMath(i+5, TokenType(i+5), line); char *num = MakeNumber(TokenValue(i+2),line); asmlist.AddToken(STApy, num, strlen(num), line); delete num; return len+5; } else if (tokens.Match(i+1,BRACKETOPEN,NUMBER,VAR,BRACKETCLOSE) && IsMath(i+5)) { int len = CompileMath(i+5, TokenType(i+5), line); char *num = MakeNumber(TokenValue(i+2),line); asmlist.AddToken(LDXp, TokenValue(i+3), strlen(TokenValue(i+3)), line); asmlist.AddToken(STApx, num, strlen(num), line); delete num; return len+5; } else if (tokens.Match(i+1,BRACKETOPEN,NUMBER,NUMBER,BRACKETCLOSE) && IsMath(i+5)) { int len = CompileMath(i+5, TokenType(i+5), line); char *num = MakeNumber(TokenValue(i+2),line); asmlist.AddToken(LDXi, TokenValue(i+3), strlen(TokenValue(i+3)), line); asmlist.AddToken(STApx, num, strlen(num), line); delete num; return len+5; } //=============set complex number array location // SET BRACKETOPEN VAR [math] BRACKETCLOSE [math] else if (tokens.Match(i+1,BRACKETOPEN,VAR) && tokens.Match(i+3+MathLength(i+3,line),BRACKETCLOSE)) { int len1 = CompileMath(i+3, TokenType(i+3), line); asmlist.AddToken(PHA, "", 0, line); int len2 = CompileMath(i+4+len1, TokenType(i+4+len1), line); asmlist.AddToken(STAp, "nbasic_temp", strlen("nbasic_temp"), line); asmlist.AddToken(PLA, "", 0, line); asmlist.AddToken(TAX, "", 0, line); asmlist.AddToken(LDAp, "nbasic_temp", strlen("nbasic_temp"), line); asmlist.AddToken(STApx, TokenValue(i+2), strlen(TokenValue(i+2)), line); return 4 + len1 + len2; } // SET BRACKETOPEN NUMBER [math] BRACKETCLOSE [math] else if (tokens.Match(i+1,BRACKETOPEN,NUMBER) && tokens.Match(i+3+MathLength(i+3,line),BRACKETCLOSE)) { int len1 = CompileMath(i+3, TokenType(i+3), line); asmlist.AddToken(PHA, "", 0, line); int len2 = CompileMath(i+4+len1, TokenType(i+4+len1), line); asmlist.AddToken(STAp, "nbasic_temp", strlen("nbasic_temp"), line); asmlist.AddToken(PLA, "", 0, line); asmlist.AddToken(TAX, "", 0, line); asmlist.AddToken(LDAp, "nbasic_temp", strlen("nbasic_temp"), line); char *num = MakeNumber(TokenValue(i+2),line); asmlist.AddToken(STApx, num, strlen(num), line); delete num; return 4 + len1 + len2; } else CompileError("'set'", line); return 0; } int NBasic::CompilePush(int i, int type, int line) { if (tokens.Match(i,PUSH,A)) { asmlist.AddToken(PHA, "", 0, line); return 2; } else if (tokens.Match(i,POP,A)) { asmlist.AddToken(PLA, "", 0, line); return 2; } else if (tokens.Match(i,PUSH,X)) { asmlist.AddToken(TXA, "", 0, line); asmlist.AddToken(PHA, "", 0, line); return 2; } else if (tokens.Match(i,POP,X)) { asmlist.AddToken(PLA, "", 0, line); asmlist.AddToken(TAX, "", 0, line); return 2; } else if (tokens.Match(i,PUSH,Y)) { asmlist.AddToken(TYA, "", 0, line); asmlist.AddToken(PHA, "", 0, line); return 2; } else if (tokens.Match(i,POP,Y)) { asmlist.AddToken(PLA, "", 0, line); asmlist.AddToken(TAY, "", 0, line); return 2; } CompileError("Error compiling push/pop statement", line); return 0; } int NBasic::CompileIncrement(int i, int type, int line) { if (tokens.Match(i,INC,X)) { asmlist.AddToken(INX, "", 0, line); return 2; } else if (tokens.Match(i,DEC,X)) { asmlist.AddToken(DEX, "", 0, line); return 2; } else if (tokens.Match(i,INC,Y)) { asmlist.AddToken(INY, "", 0, line); return 2; } else if (tokens.Match(i,DEC,Y)) { asmlist.AddToken(DEY, "", 0, line); return 2; } else if (tokens.Match(i,INC,VAR)) { const Token *t = tokens.GetToken(i+1); asmlist.AddToken(INCp, t->value, t->valuelen, t->line); return 2; } else if (tokens.Match(i,DEC,VAR)) { const Token *t = tokens.GetToken(i+1); asmlist.AddToken(DECp, t->value, t->valuelen, t->line); return 2; } CompileError("not fully implemented feature 'inc'", line); return 0; } bool NBasic::IsMath(int token_index) { int type = TokenType(token_index); switch(type) { case VAR: case NUMBER: case PLUS: case MINUS: case SHIFTLEFT: case SHIFTRIGHT: case BRACKETOPEN: case BITAND: case BITOR: case BITEOR: return true; default: return false; } return false; } int NBasic::MathLength(int i, int line) { int one,two; switch(TokenType(i)) { case VAR: case NUMBER: return 1; case PLUS: case MINUS: case BITAND: case BITOR: case BITEOR: one = MathLength(i+1, line); two = MathLength(i+1+one, line); return 1 + one + two; case SHIFTLEFT: case SHIFTRIGHT: one = MathLength(i+1, line); return one+2; case BRACKETOPEN: one = MathLength(i+1, line); if (TokenType(i+1+one) == BRACKETCLOSE) return one + 2; two = MathLength(i+1+one, line); if (TokenType(i+two+one+1)!=BRACKETCLOSE) CompileError("Error calculating bracketed math string", line); return 2 + one + two; default: CompileError("Error calculating math string", line); } return -1; //should never get here } int NBasic::CompileMath(int i, int type, int line) { switch(type) { case VAR: { const Token *t = tokens.GetToken(i); asmlist.AddToken(LDAp, t->value, t->valuelen, t->line); return 1; } case NUMBER: { char *num = MakeNumber(TokenValue(i), line); asmlist.AddToken(LDAi, num, strlen(num), line); delete num; return 1; } case BRACKETOPEN: { if (tokens.Match(i+1,VAR,X,BRACKETCLOSE)) // [var x] { const Token *t = tokens.GetToken(i+1); asmlist.AddToken(LDApx, t->value, t->valuelen, t->line); return 4; } if (tokens.Match(i+1,VAR,VAR,BRACKETCLOSE)) // [var var] { const Token *t = tokens.GetToken(i+1); const Token *t2 = tokens.GetToken(i+2); asmlist.AddToken(LDXp, t2->value, t2->valuelen, t2->line); asmlist.AddToken(LDApx, t->value, t->valuelen, t->line); return 4; } if (tokens.Match(i+1,VAR,NUMBER,BRACKETCLOSE)) // [var num] { const Token *t = tokens.GetToken(i+1); char *num = MakeNumber(TokenValue(i+2),line); asmlist.AddToken(LDXi, num, strlen(num), line); asmlist.AddToken(LDApx, t->value, t->valuelen, t->line); delete num; return 4; } else if(tokens.Match(i+1,VAR) && tokens.Match(i+2+MathLength(i+2,line),BRACKETCLOSE)) //[var math] { const Token *t = tokens.GetToken(i+1); int len = CompileMath(i+2, TokenType(i+2), line); asmlist.AddToken(TAX, "", 0, line); asmlist.AddToken(LDApx, t->value, t->valuelen, t->line); return len + 3; } else if (tokens.Match(i+1,NUMBER,BRACKETCLOSE)) // [num] { char *num = MakeNumber(TokenValue(i+1),line); asmlist.AddToken(LDAp,num,strlen(num),line); delete num; return 3; } else if (tokens.Match(i+1,NUMBER,X,BRACKETCLOSE)) // [num x] { char *num = MakeNumber(TokenValue(i+1),line); asmlist.AddToken(LDApx, num, strlen(num), line); delete num; return 4; } else if (tokens.Match(i+1,NUMBER,VAR,BRACKETCLOSE)) // [num var] { char *num = MakeNumber(TokenValue(i+1),line); const Token *t = tokens.GetToken(i+2); asmlist.AddToken(LDXp, t->value, t->valuelen, t->line); asmlist.AddToken(LDApx, num, strlen(num), line); delete num; return 4; } else if (tokens.Match(i+1,NUMBER,NUMBER,BRACKETCLOSE)) // [num num] { // [$2000 3] is the same as [$2003] int val = (NumberValue(TokenValue(i+1),line) + NumberValue(TokenValue(i+2),line)) % SIXTEENBIT; char num[8]; sprintf(num, "%i\0",val); asmlist.AddToken(LDAp, num, strlen(num), line); return 4; } else if(tokens.Match(i+1,NUMBER) && tokens.Match(i+2+MathLength(i+2,line),BRACKETCLOSE)) //[num math] { char *num = MakeNumber(TokenValue(i+1),line); int len = CompileMath(i+2, TokenType(i+2), line); asmlist.AddToken(TAX, "", 0, line); asmlist.AddToken(LDApx, num, strlen(num), line); delete num; return len + 3; } CompileError("array access", line); } case PLUS: { if (tokens.Match(i+1,VAR)) // + var math { int len = CompileMath(i+2, TokenType(i+2), line); /*if (len == 1)*/ asmlist.AddToken(CLC, "", 0, line); const Token *t = tokens.GetToken(i+1); asmlist.AddToken(ADCp, t->value, t->valuelen, t->line); return len + 2; } else if (tokens.Match(i+1,NUMBER)) // + num math { int len = CompileMath(i+2, TokenType(i+2), line); /*if (len == 1)*/ asmlist.AddToken(CLC, "", 0, line); char *num = MakeNumber(TokenValue(i+1), line); asmlist.AddToken(ADCi, num, strlen(num), line); delete num; return len + 2; } else if (tokens.Match(i+1+MathLength(i+1,line), VAR)) // + math var { int len = CompileMath(i+1, TokenType(i+1), line); /*if (len == 1)*/ asmlist.AddToken(CLC, "", 0, line); const Token *t = tokens.GetToken(i+1+len); asmlist.AddToken(ADCp, t->value, t->valuelen, t->line); return len + 2; } else if (tokens.Match(i+1+MathLength(i+1,line), NUMBER)) // + math num { int len = CompileMath(i+1, TokenType(i+1), line); /*if (len == 1)*/ asmlist.AddToken(CLC, "", 0, line); char *num = MakeNumber(TokenValue(i+1+len), line); asmlist.AddToken(ADCi, num, strlen(num), line); delete num; return len + 2; } else if (IsMath(i+1+MathLength(i+1,line)))// + math math { int len1 = CompileMath(i+1,TokenType(i+1),line); asmlist.AddToken(PHA,"",0,line); int len2 = CompileMath(i+1+len1,TokenType(i+1+len1),line); asmlist.AddToken(STAp, "nbasic_temp", strlen("nbasic_temp"), line); asmlist.AddToken(PLA,"",0,line); asmlist.AddToken(CLC,"",0,line); asmlist.AddToken(ADCp, "nbasic_temp", strlen("nbasic_temp"), line); return len1 + len2 + 1; } CompileError("addition", line); } case MINUS: { if (tokens.Match(i+1+MathLength(i+1,line), NUMBER)) // - math num { int len = CompileMath(i+1,TokenType(i+1),line); /*if (len == 1)*/ asmlist.AddToken(SEC,"",0,line); char *num = MakeNumber(TokenValue(i+1+len),line); asmlist.AddToken(SBCi,num,strlen(num),line); delete num; return 2+len; } else if (tokens.Match(i+1+MathLength(i+1,line), VAR)) // - math var { int len = CompileMath(i+1,TokenType(i+1),line); /*if (len == 1)*/ asmlist.AddToken(SEC,"",0,line); asmlist.AddToken(SBCp, TokenValue(i+1+len), strlen(TokenValue(i+1+len)), line); return 2+len; } else if (IsMath(i+1+MathLength(i+1,line))) // - math math { int len1 = CompileMath(i+1,TokenType(i+1),line); asmlist.AddToken(PHA,"",0,line); int len2 = CompileMath(i+1+len1,TokenType(i+1+len1),line); asmlist.AddToken(STAp, "nbasic_temp", strlen("nbasic_temp"), line); asmlist.AddToken(PLA,"",0,line); asmlist.AddToken(SEC,"",0,line); asmlist.AddToken(SBCp, "nbasic_temp", strlen("nbasic_temp"), line); return len1 + len2 + 1; } CompileError("subtraction", line); } case BITAND: { if (tokens.Match(i+1, VAR) && IsMath(i+2)) // & var math { int len = CompileMath(i+2, TokenType(i+2), line); asmlist.AddToken(ANDp, TokenValue(i+1), strlen(TokenValue(i+1)), line); return len + 2; } else if (tokens.Match(i+1, NUMBER) && IsMath(i+2)) // & num math { char *num = MakeNumber(TokenValue(i+1), line); int len = CompileMath(i+2, TokenType(i+2), line); asmlist.AddToken(ANDi, num, strlen(num), line); delete num; return len + 2; } else if (tokens.Match(i+1+MathLength(i+1, line), VAR)) // & math var { int len = CompileMath(i+1, TokenType(i+1), line); asmlist.AddToken(ANDp, TokenValue(i+1+len), strlen(TokenValue(i+1+len)), line); return len + 2; } else if (tokens.Match(i+1+MathLength(i+1, line), NUMBER)) // & math num { int len = CompileMath(i+1, TokenType(i+1), line); char *num = MakeNumber(TokenValue(i+1+len), line); asmlist.AddToken(ANDi, num, strlen(num), line); delete num; return len + 2; } else if (IsMath(i+1+MathLength(i+1,line)))// & math math { int len1 = CompileMath(i+1,TokenType(i+1),line); asmlist.AddToken(PHA,"",0,line); int len2 = CompileMath(i+1+len1,TokenType(i+1+len1),line); asmlist.AddToken(STAp, "nbasic_temp", strlen("nbasic_temp"), line); asmlist.AddToken(PLA,"",0,line); asmlist.AddToken(ANDp, "nbasic_temp", strlen("nbasic_temp"), line); return len1 + len2 + 1; } CompileError("bitwise-and",line); } case BITOR: { if (tokens.Match(i+1, VAR) && IsMath(i+2)) // | var math { int len = CompileMath(i+2, TokenType(i+2), line); asmlist.AddToken(ANDp, TokenValue(i+1), strlen(TokenValue(i+1)), line); return len + 2; } else if (tokens.Match(i+1, NUMBER) && IsMath(i+2)) // | num math { char *num = MakeNumber(TokenValue(i+1), line); int len = CompileMath(i+2, TokenType(i+2), line); asmlist.AddToken(ORi, num, strlen(num), line); delete num; return len + 2; } else if (tokens.Match(i+1+MathLength(i+1, line), VAR)) // | math var { int len = CompileMath(i+1, TokenType(i+1), line); asmlist.AddToken(ORp, TokenValue(i+1+len), strlen(TokenValue(i+1+len)), line); return len + 2; } else if (tokens.Match(i+1+MathLength(i+1, line), NUMBER)) // | math num { int len = CompileMath(i+1, TokenType(i+1), line); char *num = MakeNumber(TokenValue(i+1+len), line); asmlist.AddToken(ORi, num, strlen(num), line); delete num; return len + 2; } else if (IsMath(i+1+MathLength(i+1,line)))// | math math { int len1 = CompileMath(i+1,TokenType(i+1),line); asmlist.AddToken(PHA,"",0,line); int len2 = CompileMath(i+1+len1,TokenType(i+1+len1),line); asmlist.AddToken(STAp, "nbasic_temp", strlen("nbasic_temp"), line); asmlist.AddToken(PLA,"",0,line); asmlist.AddToken(ORp, "nbasic_temp", strlen("nbasic_temp"), line); return len1 + len2 + 1; } CompileError("bitwise-or",line); } case BITEOR: { if (tokens.Match(i+1, VAR) && IsMath(i+2)) // ^ var math { int len = CompileMath(i+2, TokenType(i+2), line); asmlist.AddToken(EORp, TokenValue(i+1), strlen(TokenValue(i+1)), line); return len + 2; } else if (tokens.Match(i+1, NUMBER) && IsMath(i+2)) // ^ num math { char *num = MakeNumber(TokenValue(i+1), line); int len = CompileMath(i+2, TokenType(i+2), line); asmlist.AddToken(EORi, num, strlen(num), line); delete num; return len + 2; } else if (tokens.Match(i+1+MathLength(i+1, line), VAR)) // ^ math var { int len = CompileMath(i+1, TokenType(i+1), line); asmlist.AddToken(EORp, TokenValue(i+1+len), strlen(TokenValue(i+1+len)), line); return len + 2; } else if (tokens.Match(i+1+MathLength(i+1, line), NUMBER)) // ^ math num { int len = CompileMath(i+1, TokenType(i+1), line); char *num = MakeNumber(TokenValue(i+1+len), line); asmlist.AddToken(EORi, num, strlen(num), line); delete num; return len + 2; } else if (IsMath(i+1+MathLength(i+1,line)))// ^ math math { int len1 = CompileMath(i+1,TokenType(i+1),line); asmlist.AddToken(PHA,"",0,line); int len2 = CompileMath(i+1+len1,TokenType(i+1+len1),line); asmlist.AddToken(STAp, "nbasic_temp", strlen("nbasic_temp"), line); asmlist.AddToken(PLA,"",0,line); asmlist.AddToken(EORp, "nbasic_temp", strlen("nbasic_temp"), line); return len1 + len2 + 1; } CompileError("bitwise-eor",line); } case SHIFTLEFT: if (tokens.Match(i+1+MathLength(i+1, line), NUMBER)) // << math num { int len = CompileMath(i+1, TokenType(i+1), line); int num = NumberValue(TokenValue(i+1+len), line); asmlist.AddToken(CLC,"",0,line); for(int j = 0; j < num; j++) asmlist.AddToken(ASLa,"",0,line); return len + 2; } CompileError("left shift", line); case SHIFTRIGHT: if (tokens.Match(i+1+MathLength(i+1, line), NUMBER)) // << math num { int len = CompileMath(i+1, TokenType(i+1), line); int num = NumberValue(TokenValue(i+1+len), line); asmlist.AddToken(CLC,"",0,line); for(int j = 0; j < num; j++) asmlist.AddToken(LSRa,"",0,line); return len + 2; } CompileError("right shift", line); break; defualt: CompileError("arithmetic",line); } } bool NBasic::Output(const char* filename) { FILE *f = fopen(filename,"w"); if (!f) return false; Output(f); fclose(f); return true; } void NBasic::Output(FILE *f) { if (verbose) printf("Beginning compile\n"); CreateAutoVariables(); OutputVariables(f); int n = asmlist.NumTokens(); const Token* t; for(int i = 0; i < n; i++) { t = asmlist.GetToken(i); switch(t->type) { //addition case ADCi: fprintf(f, " adc #%s\n",t->value); break; case ADCp: fprintf(f, " adc %s\n",t->value); break; case ADCpx: fprintf(f, " adc %s,x\n",t->value); break; //bitwise and case ANDi: fprintf(f, " and #%s\n", t->value); break; case ANDp: fprintf(f, " and %s\n", t->value); break; //bitwise or case ORi: fprintf(f, " or #%s\n", t->value); break; case ORp: fprintf(f, " or %s\n", t->value); break; //bitwise eor case EORi: fprintf(f, " eor #%s\n", t->value); break; case EORp: fprintf(f, " eor %s\n", t->value); break; //shift left case ASLa: fprintf(f, " asl a\n"); break; //labels case ASMACCEPTABLE: case ASMTEXT: fprintf(f, "%s",t->value); break; case ASMLABEL: fprintf(f, "\n%s\n",t->value); break; //branches case BCC: fprintf(f, " bcc %s\n",t->value); break; case BCS: fprintf(f, " bcs %s\n",t->value); break; case BEQ: fprintf(f, " beq %s\n",t->value); break; case BMI: fprintf(f, " bmi %s\n",t->value); break; case BNE: fprintf(f, " bne %s\n",t->value); break; case BPL: fprintf(f, " bpl %s\n",t->value); break; //clear carry case CLC: fprintf(f, " clc\n"); break; //comparisons case CMPi: fprintf(f, " cmp #%s\n",t->value); break; case CMPp: fprintf(f, " cmp %s\n",t->value); break; case CPXi: fprintf(f, " cpx #%s\n",t->value); break; case CPXp: fprintf(f, " cpx %s\n",t->value); break; case CPYi: fprintf(f, " cpy #%s\n",t->value); break; case CPYp: fprintf(f, " cpy %s\n",t->value); break; //decrements case DECp: fprintf(f, " dec %s\n",t->value); break; case DECpx: fprintf(f, " dec %s,x\n",t->value); break; case DEX: fprintf(f, " dex\n"); break; case DEY: fprintf(f, " dey\n"); break; //increments case INCp: fprintf(f, " inc %s\n",t->value); break; case INCpx: fprintf(f, " inc %s,x\n",t->value); break; case INX: fprintf(f, " inx\n"); break; case INY: fprintf(f, " iny\n"); break; //jumps case JMP: fprintf(f, " jmp %s\n",t->value); break; case JSR: fprintf(f, " jsr %s\n",t->value); break; //loads case LDAi: fprintf(f, " lda #%s\n",t->value); break; case LDAp: fprintf(f, " lda %s\n",t->value); break; case LDApx: fprintf(f, " lda %s,x\n",t->value); break; case LDApy: fprintf(f, " lda %s,y\n",t->value); break; case LDXi: fprintf(f, " ldx #%s\n",t->value); break; case LDXp: fprintf(f, " ldx %s\n",t->value); break; case LDXpy: fprintf(f, " ldx %s,y\n",t->value); break; case LDYi: fprintf(f, " ldy #%s\n",t->value); break; case LDYp: fprintf(f, " ldy %s\n",t->value); break; case LDYpx: fprintf(f, " ldy %s,x\n",t->value); break; //shift right case LSRa: fprintf(f, " lsr a\n"); break; //stack ops case PHA: fprintf(f, " pha\n"); break; case PLA: fprintf(f, " pla\n"); break; //subtraction case SBCi: fprintf(f, " sbc #%s\n",t->value); break; case SBCp: fprintf(f, " sbc %s\n",t->value); break; case SBCpx: fprintf(f, " sbc %s,x\n",t->value); break; case SEC: fprintf(f, " sec\n"); break; //stores case STAp: fprintf(f, " sta %s\n",t->value); break; case STApx: fprintf(f, " sta %s,x\n",t->value); break; case STApy: fprintf(f, " sta %s,y\n",t->value); break; case STXp: fprintf(f, " stx %s\n",t->value); break; case STXpy: fprintf(f, " stx %s,y\n",t->value); break; case STYp: fprintf(f, " sty %s\n",t->value); break; case STYpx: fprintf(f, " sty %s,x\n",t->value); break; case RTI: fprintf(f, " rti\n"); break; case RTS: fprintf(f, " rts\n"); break; //transfers case TAX: fprintf(f, " tax\n"); break; case TAY: fprintf(f, " tay\n"); break; case TXA: fprintf(f, " txa\n"); break; case TYA: fprintf(f, " tya\n"); break; //unhandled default: fprintf(stderr, "don't know how to handle ASM opcode type %i\n",t->type); } } fprintf(f,"\n"); if (verbose) printf("Compile completed successfully.\n"); }