// asmguts.h - copyright 1998-2004 Bruce Tomlin //#include //#include //#include //#include //#include //#include "asmcfg.h" //#include "asmguts.h" //#define DEBUG_PASS #define IHEX_SIZE 32 // max number of data bytes per line in intel hex format #define maxSymLen 16 // max symbol length (only used in DumpSym()) const int symTabCols = 3; // number of columns for symbol table dump #define maxMacParms 10 // maximum macro parameters #define MAX_INCLUDE 10 #define MAX_BYTSTR 1024 // size of bytStr[] typedef unsigned char Str255[256]; // generic string type typedef char bool; // i guess bool is a c++ thing const bool FALSE = 0; const bool TRUE = 1; const char *progname; // pointer to argv[0] struct SymRec { struct SymRec *next; // pointer to next symtab entry unsigned short value; // symbol value bool defined; // TRUE if defined bool multiDef; // TRUE if multiply defined bool isSet; // TRUE if defined with SET pseudo bool equ; // TRUE if defined with EQU pseudo bool known; // TRUE if value is known char name[1]; // symbol name, storage = 1 + length } *symTab = NULL; // pointer to first entry in symtab typedef struct SymRec *SymPtr; struct MacroLine { struct MacroLine *next; // pointer to next macro line char text[1]; // macro line, storage = 1 + length }; typedef struct MacroLine *MacroLinePtr; struct MacroParm { struct MacroParm *next; // pointer to next macro parameter name char name[1]; // macro parameter name, storage = 1 + length }; typedef struct MacroParm *MacroParmPtr; struct MacroRec { struct MacroRec *next; // pointer to next macro bool def; // TRUE after macro is defined in pass 2 MacroLinePtr text; // macro text MacroParmPtr parms; // macro parms int nparms; // number of macro parameters char name[1]; // macro name, storage = 1 + length } *macroTab = NULL; typedef struct MacroRec *MacroPtr; typedef char OpcdStr[maxOpcdLen+1]; struct OpcdRec { OpcdStr name; // opcode name short typ; // opcode type unsigned short parm; // opcode parameter }; typedef struct OpcdRec *OpcdPtr; MacroPtr macPtr; // current macro in use MacroLinePtr macLine; // current macro text pointer char *macParms[maxMacParms]; // pointers to current macro parameters Str255 macParmsLine; // text of current macro parameters unsigned short locPtr; // Current program address unsigned short codPtr; // Current program "real" address int pass; // Current assembler pass bool warnFlag; // TRUE if warning occurred this line bool errFlag; // TRUE if error occurred this line int errCount; // Total number of errors Str255 line; // Current line from input file char *linePtr; // pointer into current line Str255 listLine; // Current listing line bool listFlag; // FALSE to suppress listing source bool listThisLine; // TRUE to force listing this line bool sourceEnd; // TRUE when END pseudo encountered Str255 lastLabl; // last label for @ temps bool listMacFlag; // FALSE to suppress showing macro expansions bool macLineFlag; // TRUE if line came from a macro unsigned char instr[5]; // Current instruction word int instrLen; // Current instruction length unsigned char bytStr[MAX_BYTSTR]; // Buffer for long DB statements bool showAddr; // TRUE to show LocPtr on listing unsigned short xferAddr; // Transfer address from END pseudo bool xferFound; // TRUE if xfer addr defined w/ END // Command line parameters Str255 cl_SrcName; // Source file name Str255 cl_ListName; // Listing file name Str255 cl_ObjName; // Object file name bool cl_Err; // TRUE for errors to screen bool cl_Warn; // TRUE for warnings to screen bool cl_List; // TRUE to generate listing file bool cl_Obj; // TRUE to generate object file FILE *source; // source input file FILE *object; // object output file FILE *listing; // listing output file FILE *(include[MAX_INCLUDE]); // include files int nInclude; // current include file index bool evalKnown; // TRUE if all operands in Eval were "known" void DoOpcode(int typ, int parm); void usage(void); void AsmInit(void); // -------------------------------------------------------------- // error messages /* * Error */ void Error(char *message) { errFlag = TRUE; errCount++; #ifndef DEBUG_PASS if (pass != 1) #endif { listThisLine = TRUE; if (cl_List) fprintf(listing,"*** Error: %s ***\n",message); if (cl_Err) fprintf(stdout/*stderr*/, "*** Error: %s ***\n",message); } } /* * Warning */ void Warning(char *message) { if (pass != 1 && cl_Warn) { listThisLine = TRUE; warnFlag = TRUE; if (cl_List) fprintf(listing,"*** Warning: %s ***\n",message); if (cl_Warn) fprintf(stdout/*stderr*/, "*** Warning: %s ***\n",message); } } // -------------------------------------------------------------- // string utilities /* * Debleft deblanks the string s from the left side */ void Debleft(char *s) { char *p = s; while (*p == 9 || *p == ' ') p++; while (*s++ = *p++); } /* * Debright deblanks the string s from the right side */ void Debright(char *s) { char *p = s + strlen(s); while (p>s && *--p == ' ') *p = 0; } /* * Deblank removes blanks from both ends of the string s */ void Deblank(char *s) { Debleft(s); Debright(s); } /* * Uprcase converts string s to upper case */ void Uprcase(char *s) { char *p = s; while (*p = toupper(*p)) p++; } int ishex(char c) { c = toupper(c); return isdigit(c) || ('A' <= c && c <= 'F'); } int isalphanum(char c) { c = toupper(c); return isdigit(c) || ('A' <= c && c <= 'Z') || c == '_'; } unsigned int EvalBin(char *binStr) { unsigned int binVal; int evalErr; int c; evalErr = FALSE; binVal = 0; while (c = *binStr++) { if (c < '0' || c > '1') evalErr = TRUE; else binVal = binVal * 2 + c - '0'; } if (evalErr) { binVal = 0; Error("Invalid binary number"); } return binVal; } unsigned int EvalOct(char *octStr) { unsigned int octVal; int evalErr; int c; evalErr = FALSE; octVal = 0; while (c = *octStr++) { if (c < '0' || c > '7') evalErr = TRUE; else octVal = octVal * 8 + c - '0'; } if (evalErr) { octVal = 0; Error("Invalid octal number"); } return octVal; } unsigned int EvalDec(char *decStr) { unsigned int decVal; int evalErr; int c; evalErr = FALSE; decVal = 0; while (c = *decStr++) { if (!isdigit(c)) evalErr = TRUE; else decVal = decVal * 10 + c - '0'; } if (evalErr) { decVal = 0; Error("Invalid decimal number"); } return decVal; } int Hex2Dec(c) { c = toupper(c); if (c > '9') return c - 'A' + 10; return c - '0'; } unsigned int EvalHex(char *hexStr) { unsigned int hexVal; int evalErr; int c; evalErr = FALSE; hexVal = 0; while (c = *hexStr++) { if (!ishex(c)) evalErr = TRUE; else hexVal = hexVal * 16 + Hex2Dec(c); } if (evalErr) { hexVal = 0; Error("Invalid hexadecimal number"); } return hexVal; } // -------------------------------------------------------------- // token handling // returns 0 for end-of-line, -1 for alpha-numeric, else char value for non-alphanumeric // converts the word to uppercase, too int GetWord(char *word) { unsigned char c; // Deblank(line); word[0] = 0; // skip initial whitespace c = *linePtr; while (c == 12 || c == '\t' || c == ' ') c = *++linePtr; // skip comments if (c == ';') while (c) c = *++linePtr; // test for end of line if (c) { // test for alphanumeric token if (isalphanum(c)) { while (isalphanum(c)) { *word++ = toupper(c); c = *++linePtr; } *word = 0; return -1; } else { word[0] = c; word[1] = 0; linePtr++; return c; } } return 0; } // same as GetWord, except it allows '.' chars in alphanumerics int GetOpcode(char *word) { unsigned char c; // Deblank(line); word[0] = 0; // skip initial whitespace c = *linePtr; while (c == 12 || c == '\t' || c == ' ') c = *++linePtr; // skip comments if (c == ';') while (c) c = *++linePtr; // test for end of line if (c) { // test for alphanumeric token if (isalphanum(c) || c=='.') { while (isalphanum(c) || c=='.') { *word++ = toupper(c); c = *++linePtr; } *word = 0; return -1; } else { word[0] = c; word[1] = 0; linePtr++; return c; } } return 0; } void Expect(char *expected) { Str255 s; GetWord(s); if (strcmp(s,expected) != 0) { sprintf(s,"\"%s\" expected\n",expected); Error(s); } } void Comma() { Expect(","); } void RParen() { Expect(")"); } void EatIt() { Str255 word; while (GetWord(word)); // eat junk at end of line } /* * IllegalOperand */ void IllegalOperand() { Error("Illegal operand"); EatIt(); } // -------------------------------------------------------------- // macro handling MacroPtr FindMacro(char *name) { MacroPtr p = macroTab; bool found = FALSE; while (p && !found) { found = (strcmp(p -> name, name) == 0); if (!found) p = p -> next; } return p; } MacroPtr AddMacro(char *name) { MacroPtr p; p = malloc(sizeof(struct MacroRec) + strlen(name)); strcpy(p -> name, name); p -> def = FALSE; p -> text = NULL; p -> next = macroTab; p -> parms = NULL; p -> nparms = 0; macroTab = p; return p; } void AddMacroParm(MacroPtr macro, char *name) { MacroParmPtr parm; MacroParmPtr p; parm = malloc(sizeof(struct MacroParm) + strlen(name)); parm -> next = NULL; strcpy(parm -> name, name); macro -> nparms++; p = macro -> parms; if (p) { while (p -> next) p = p -> next; p -> next = parm; } else macro -> parms = parm; } void AddMacroLine(MacroPtr macro, char *line) { MacroLinePtr m; MacroLinePtr p; m = malloc(sizeof(struct MacroLine) + strlen(line)); m -> next = NULL; strcpy(m -> text, line); p = macro -> text; if (p) { while (p -> next) p = p -> next; p -> next = m; } else macro -> text = m; } void GetMacParms(MacroPtr macro) { int i; int n; int quote; char c; char *p; bool done; for (i=0; i=macParms[i] && (*p == ' ' || *p == 9)) *p-- = 0; } if (n > macro -> nparms || n > maxMacParms) Error("Too many macro parameters"); // for (i=0; i parms; while (parm && strcmp(parm -> name, word)) { parm = parm -> next; i++; } // if macro parameter found, replace parameter name with parameter value if (parm) { //printf("found macro parameter name '%s', length=%d, index = %d\n",word, linePtr - p,i); //printf(" old line = '%s'\n",line); // copy from linePtr to temp string strcpy(word, linePtr); // copy from corresponding parameter to p strcpy(p, macParms[i]); // point p to end of appended text p = p + strlen(macParms[i]); // copy from temp to p strcpy(p, word); // update linePtr linePtr = p; //printf(" new line = '%s'\n",line); //printf(" new linePtr = '%s'\n",linePtr); } } // skip initial whitespace c = *linePtr; while (c == 12 || c == '\t' || c == ' ') c = *++linePtr; p = linePtr; token = GetWord(word); } //printf(" new line = '%s'\n",line); } void DumpMacro(MacroPtr p) { MacroLinePtr line; MacroParmPtr parm; if (cl_List) { fprintf(listing,"--- Macro '%s' ---", p -> name); fprintf(listing," def = %d, nparms = %d\n", p -> def, p -> nparms); // dump parms here fprintf(listing,"Parms:"); for (parm = p->parms; parm; parm = parm->next) { fprintf(listing," '%s'",parm->name); } fprintf(listing,"\n"); // dump text here for (line = p->text; line; line = line->next) fprintf(listing," '%s'\n",line->text); } } void DumpMacroTab(void) { struct MacroRec *p; p = macroTab; while (p) { DumpMacro(p); p = p -> next; } } // -------------------------------------------------------------- // opcodes and symbol table /* * FindOpcode */ void FindOpcode(char *name, int *typ, int *parm, MacroPtr *macro) { extern OpcdPtr opcdTab; OpcdPtr p = (OpcdPtr) &opcdTab; bool found = FALSE; while (p -> typ != o_Illegal && !found) { found = (strcmp(p -> name, name) == 0); if (!found) p++; } *typ = p -> typ; *parm = p -> parm; *macro = NULL; if (!found) { *macro = FindMacro(name); if (*macro) *typ = o_MacName; } } /* * FindSym */ SymPtr FindSym(char *symName) { SymPtr p = symTab; bool found = FALSE; while (p && !found) { found = (strcmp(p -> name, symName) == 0); if (!found) p = p -> next; } return p; } /* * AddSym */ SymPtr AddSym(char *symName) { SymPtr p; p = malloc(sizeof(struct SymRec) + strlen(symName)); strcpy(p -> name, symName); p -> value = 0; p -> next = symTab; p -> defined = FALSE; p -> multiDef = FALSE; p -> isSet = FALSE; p -> equ = FALSE; p -> known = FALSE; symTab = p; return p; } /* * RefSym */ int RefSym(char *symName, bool *known) { SymPtr p; int i; Str255 s; if (p = FindSym(symName)) { if (!p -> defined) { sprintf(s, "Symbol '%s' undefined", symName); Error(s); } switch(pass) { case 1: if (!p -> defined) *known = FALSE; break; case 2: if (!p -> known) *known = FALSE; break; } return p -> value; } { // check for 'FFH' style constants here i = strlen(symName)-1; if (toupper(symName[i]) != 'H') i = -1; else while (i>0 && ishex(symName[i-1])) i--; if (i == 0) { strncpy(s, symName, 255); s[strlen(s)-1] = 0; return EvalHex(s); } else { p = AddSym(symName); *known = FALSE; #ifdef DEBUG_PASS sprintf(s, "Symbol '%s' undefined", symName); Error(s); #endif } } return 0; } /* * DefSym */ void DefSym(char *symName, unsigned short val, bool setSym, bool equSym) { SymPtr p; Str255 s; if (symName[0]) // ignore null string symName { p = FindSym(symName); if (p == NULL) p = AddSym(symName); if (!p -> defined || (p -> isSet && setSym)) { p -> value = val; p -> defined = TRUE; p -> isSet = setSym; p -> equ = equSym; } else if (p -> value != val) { p -> multiDef = TRUE; if (pass == 2 && !p -> known) sprintf(s, "Phase error"); else sprintf(s, "Symbol '%s' multiply defined",symName); Error(s); } if (pass == 2) p -> known = TRUE; } } void DumpSym(SymPtr p, char *s) { char *s2; int n; n = 0; s2 = p->name; while(*s2 && nvalue); s = s + strlen(s); n = 0; if (!p->defined) {*s++ = 'U'; n++;} // Undefined if ( p->multiDef) {*s++ = 'M'; n++;} // Multiply defined if ( p->isSet) {*s++ = 'S'; n++;} // Set if ( p->equ) {*s++ = 'E'; n++;} // Equ while (n < 9) { *s++ = ' '; n++; } *s = 0; } void DumpSymTab(void) { struct SymRec *p; int i; Str255 s; i = 1; p = symTab; while (p) { DumpSym(p,s); p = p -> next; i++; if (p == NULL || i > symTabCols) { i = 1; Debright(s); // printf("%s\n",s); if (cl_List) fprintf(listing, "%s\n", s); } else { // printf("%s",s); if (cl_List) fprintf(listing, "%s", s); } } } void SortSymTab() { SymPtr i,j; // pointers to current elements SymPtr ip,jp; // pointers to previous elements SymPtr t; // temp for swapping if (symTab != NULL) { ip = NULL; i = symTab; jp = i; j = i -> next; while (j != NULL) { while (j != NULL) { if (strcmp(i->name,j->name) > 0) // (i->name > j->name) { if (ip != NULL) ip -> next = j; else symTab = j; if (i == jp) { i -> next = j -> next; j -> next = i; } else { jp -> next = i; t = i -> next; i -> next = j -> next; j -> next = t; } t = i; i = j; j = t; } jp = j; j = j -> next; } ip = i; i = i -> next; jp = i; j = i -> next; } } } // -------------------------------------------------------------- // expression evaluation int Eval0(void); // forward declaration int Factor(void) { Str255 word,s; int token; int val; token = GetWord(word); val = 0; switch(token) { case 0: Error("Missing operand"); break; case '%': GetWord(word); val = EvalBin(word); break; case '$': // 6502/6809 only? if (ishex(*linePtr)) { GetWord(word); val = EvalHex(word); break; } // fall-through... case '*': case '.': val = locPtr; break; case '-': val = -Factor(); break; case '+': val = Factor(); break; case '~': val = ~Factor(); break; case '<': val = Factor() & 0xFF; break; case '>': val = (Factor() >> 8) & 0xFF; break; case '(': val = Eval0(); RParen(); break; case '[': val = Eval0(); Expect("]"); break; case 0x27: // single quote val = *linePtr; if (val) { linePtr++; Expect("'"); } else Error("Missing operand"); break; case '@': GetWord(word); strcpy(s,lastLabl); strcat(s,"@"); strcat(s,word); val = RefSym(s, &evalKnown); break; case -1: if (isdigit(word[0])) { val = strlen(word) - 1; token = word[val]; switch(token) { case 'B': word[val] = 0; val = EvalBin(word); break; case 'O': word[val] = 0; val = EvalOct(word); break; case 'D': word[val] = 0; val = EvalDec(word); break; case 'H': word[val] = 0; val = EvalHex(word); break; default: val = EvalDec(word); break; } } else val = RefSym(word,&evalKnown); break; default: // ignore anything else break; } return val; } int Term(void) { Str255 word; int token; int val; char *oldLine; val = Factor(); oldLine = linePtr; token = GetWord(word); while (token == '*' || token == '/' || token == '%') { switch(token) { case '*': val = val * Factor(); break; case '/': val = val / Factor(); break; case '%': val = val % Factor(); break; } oldLine = linePtr; token = GetWord(word); } linePtr = oldLine; return val; } int Eval1(void) { Str255 word; int token; int val; char *oldLine; val = Term(); oldLine = linePtr; token = GetWord(word); while (token == '+' || token == '-') { switch(token) { case '+': val = val + Term(); break; case '-': val = val - Term(); break; } oldLine = linePtr; token = GetWord(word); } linePtr = oldLine; return val; } int Eval0(void) { Str255 word; int token; int val; char *oldLine; val = Eval1(); oldLine = linePtr; token = GetWord(word); while (token == '&' || token == '|' || (token == '<' && *linePtr == '<') || (token == '>' && *linePtr == '>')) { switch(token) { case '&': val = val & Eval1(); break; case '|': val = val | Eval1(); break; case '<': linePtr++; val = val << Eval1(); break; case '>': linePtr++; val = val >> Eval1(); break; } oldLine = linePtr; token = GetWord(word); } linePtr = oldLine; return val; } int Eval(void) { evalKnown = TRUE; return Eval0(); } int EvalByte(void) { int val; val = Eval(); if (val < -128 || val > 255) Error("Byte out of range"); return val & 255; } // -------------------------------------------------------------- // object file generation unsigned char ihex_buf[IHEX_SIZE]; int ihex_len; // length of current intel hex line int ihex_base; // current address in intel hex buffer int ihex_addr; // start address of current intel hex line // Intel hex format: // // :aabbbbccdddd...ddee // // aa = record data length (the number of dd bytes) // bbbb = address for this record // cc = record type // 00 = data (data is in the dd bytes) // 01 = end of file (bbbb is transfer address) // 02 = extended segment address record // dddd (two bytes) represents the segment address // 03 = Start segment address record // dddd (two bytes) represents the segment of the transfer address // 04 = extended linear address record // dddd (two bytes) represents the high address word // 05 = Start linear address record // dddd (two bytes) represents the high word of the transfer address // dd... = data bytes if record type needs it // ee = checksum byte: add all bytes aa through dd // and subtract from 256 (2's complement negate) void ihex_line(int addr, unsigned char *buf, int len, int rectype) { int i,chksum; if (cl_Obj) { chksum = len + (addr >> 8) + addr + rectype; fprintf(object,":%.2X%.4X%.2X",len,addr & 0xFFFF,rectype); for (i=0; i> 8); } void Instr4(int b1, int b2, int b3, int b4) { instr[0] = b1; instr[1] = b2; instr[2] = b3; instr[3] = b4; instrLen = 4; } void Instr4W(int b1, int b2, int w) { Instr4(b1,b2,w & 255,w >> 8); } // -------------------------------------------------------------- // text I/O int OpenInclude(char *fname) { if (nInclude == MAX_INCLUDE - 1) return -1; nInclude++; include[nInclude] = NULL; include[nInclude] = fopen(fname, "r"); if (include[nInclude]) return 1; nInclude--; return 0; } void CloseInclude(void) { if (nInclude < 0) return; fclose(include[nInclude]); include[nInclude] = NULL; nInclude--; } int ReadLine(FILE *file, char *line, int max) { int c; int len = 0; macLineFlag = (macLine != NULL); if (macLineFlag) { strcpy(line, macLine -> text); macLine = macLine -> next; DoMacParms(); } else { macPtr = NULL; while (max > 1) { c = fgetc(file); *line = 0; switch(c) { case EOF: if (len == 0) return 0; case '\n': return 1; case '\r': break; default: *line++ = c; max--; len++; break; } } while (c != EOF && c != '\n') c = fgetc(file); } return 1; } int ReadSourceLine(char *line, int max) { int i; while (nInclude >= 0) { i = ReadLine(include[nInclude], line, max); if (i) return i; CloseInclude(); } return ReadLine(source, line, max); } void ListOut(void) { /* FIXME: need to handle form feed properly IF Deblank(listLine) = #12 THEN WriteLn(listing,#12) */ Debright(listLine); if (cl_List) fprintf(listing,"%s\n",listLine); if (listLine[0]) { if ((errFlag && cl_Err) || warnFlag) printf("%s\n",listLine); } } // -------------------------------------------------------------- // main assembler loops void DoStdOpcode(int typ, int parm) { int val; int i,n; Str255 word,s; char *oldLine; int token; unsigned char ch; unsigned char quote; bool done; // int opcode; // int mode; // const unsigned char *modes; // pointer to current o_Mode instruction's opcodes switch(typ) { /* case o_Implied: Instr1(parm); break; case o_Branch: val = Eval(); val = val - locPtr - 2; if (val < -128 || val > 127) Error("Branch out of range"); Instr2(parm,val); break; */ case o_DB: instrLen = 0; oldLine = linePtr; token = GetWord(word); if (token == 0) Error("Missing operand"); while (token) { if (token == '\'' || token == '"') { quote = token; while (token == quote) { // FIXME: need to handle double quotes and backslashes here while (*linePtr != 0 && *linePtr != token) { ch = *linePtr++; if (ch == '\\' && *linePtr != 0) // backslash { ch = *linePtr++; switch(ch) { case 'r': ch = '\r'; break; case 'n': ch = '\n'; break; case 't': ch = '\t'; break; // case 'x': // add hex, dec, etc. someday } } bytStr[instrLen++] = ch; } token = *linePtr; if (token) linePtr++; if (token == quote && *linePtr == quote) // two quotes together bytStr[instrLen++] = *linePtr++; else token = *linePtr; } } else { linePtr = oldLine; val = EvalByte(); bytStr[instrLen++] = val; } token = GetWord(word); oldLine = linePtr; if (token == ',') { token = GetWord(word); if (token == 0) Error("Missing operand"); } } instrLen = -instrLen; break; case o_DWLE: instrLen = 0; oldLine = linePtr; token = GetWord(word); if (token == 0) Error("Missing operand"); while (token) { linePtr = oldLine; val = Eval(); bytStr[instrLen++] = val & 255; bytStr[instrLen++] = val >> 8; token = GetWord(word); oldLine = linePtr; if (token == ',') { token = GetWord(word); if (token == 0) Error("Missing operand"); } } instrLen = -instrLen; break; case o_DWBE: // big-endian DW instrLen = 0; oldLine = linePtr; token = GetWord(word); if (token == 0) Error("Missing operand"); while (token) { linePtr = oldLine; val = Eval(); bytStr[instrLen++] = val >> 8; bytStr[instrLen++] = val & 255; token = GetWord(word); oldLine = linePtr; if (token == ',') { token = GetWord(word); if (token == 0) Error("Missing operand"); } } instrLen = -instrLen; break; case o_DS: val = Eval(); oldLine = linePtr; if (GetWord(word)) { linePtr = oldLine; n = Eval(); if (val > MAX_BYTSTR) { sprintf(s,"String too long (max %d bytes)",MAX_BYTSTR); Error(s); break; } for (i=0; i= MAX_BYTSTR) { sprintf(s,"String too long (max %d bytes)",MAX_BYTSTR); Error(s); n = i; done = TRUE; } val = Hex2Dec(word[i]) * 16 + Hex2Dec(word[i+1]); bytStr[instrLen++] = val; } else { Error("Invalid HEX string"); n = i; done = TRUE; } } } instrLen = -instrLen; break; case o_FCC: instrLen = 0; oldLine = linePtr; token = GetWord(word); if (token == 0) Error("Missing operand"); ch = token; done = FALSE; while (token && !done) { if (token == ch) { while (token == ch) { while (*linePtr != 0 && *linePtr != token) bytStr[instrLen++] = *linePtr++; token = *linePtr; if (token) linePtr++; if (token == '\'' && *linePtr == '\'') bytStr[instrLen++] = token; else token = *linePtr; } } else { linePtr = oldLine; val = EvalByte(); bytStr[instrLen++] = val; } token = GetWord(word); oldLine = linePtr; if (token == ',') { token = GetWord(word); if (token == 0) Error("Missing operand"); } } instrLen = -instrLen; if (!done) Error("FCC not terminated properly"); break; /* WHILE (Length(line)<>0) AND NOT done DO BEGIN IF line[1]=ch THEN BEGIN IF (Length(line)>1) AND (line[2]=ch) THEN BEGIN bytStr := bytStr + line[1]; Delete(line,1,2); END ELSE BEGIN Delete(line,1,1); DebLeft(line); IF (Length(line)=0) OR (line[1]=comment) THEN done := TRUE ELSE line := ''; END; END ELSE BEGIN bytStr := bytStr + line[1]; Delete(line,1,1); END; END; */ case o_END: if (nInclude >= 0) CloseInclude(); else { oldLine = linePtr; if (GetWord(word)) { linePtr = oldLine; val = Eval(); CodeXfer(val); sprintf(word,"---- (%.4X)",val); for (i=6; i<12; i++) listLine[i] = word[i]; } sourceEnd = TRUE; } break; case o_Include: while (*linePtr == ' ' || *linePtr == '\t') linePtr++; oldLine = word; while (*linePtr !=0 && *linePtr != ' ' && *linePtr != '\t') { ch = *linePtr++; if (ch == '\\' && *linePtr != 0) ch = *linePtr++; *oldLine++ = ch; } *oldLine++ = 0; switch(OpenInclude(word)) { case -1: Error("Too many nested INCLUDEs"); break; case 0: sprintf(s,"Unable to open INCLUDE file '%s'",word); Error(s); break; default: break; } EatIt(); break; case o_ENDM: Error("ENDM without MACRO"); break; default: Error("Unknown opcode"); EatIt(); break; } } void DoLabelOp(int typ, int parm, char *labl) { int val; int i; Str255 word; int token; Str255 opcode; MacroPtr macro; MacroPtr xmacro; int nparms; switch(typ) { case o_EQU: if (labl[0] == 0) Error("Missing label"); else { val = Eval(); sprintf(word,"---- = %.4X",val); for (i=5; i<11; i++) listLine[i] = word[i]; DefSym(labl,val,parm==1,parm==0); } break; case o_ORG: CodeAbsOrg(Eval()); DefSym(labl,locPtr,FALSE,FALSE); showAddr = TRUE; break; case o_RORG: val = Eval(); CodeRelOrg(val); DefSym(labl,/*locPtr?*/codPtr,FALSE,FALSE); if (pass == 2) { sprintf(word,"%.4X = %.4X",codPtr,val); for (i=0; i<11; i++) listLine[i] = word[i]; } break; case o_REND: if (pass == 2) { sprintf(word,"%.4X",locPtr); for (i=0; i<4; i++) listLine[i] = word[i]; } DefSym(labl,locPtr,FALSE,FALSE); CodeAbsOrg(codPtr); break; case o_LIST: listThisLine = TRUE; if (labl[0]) Error("Label not allowed"); GetWord(word); if (strcmp(word,"ON") == 0) listFlag = TRUE; else if (strcmp(word,"OFF") == 0) listFlag = FALSE; else if (strcmp(word,"MACRO") == 0) listMacFlag = TRUE; else if (strcmp(word,"NOMACRO") == 0) listMacFlag = FALSE; else IllegalOperand(); break; case o_OPT: listThisLine = TRUE; if (labl[0]) Error("Label not allowed"); GetWord(word); if (strcmp(word,"LIST") == 0) listFlag = TRUE; else if (strcmp(word,"NOLIST") == 0) listFlag = FALSE; else if (strcmp(word,"MACRO") == 0) listMacFlag = TRUE; else if (strcmp(word,"NOMACRO") == 0) listMacFlag = FALSE; else Error("Illegal option"); break; case o_MACRO: macro = FindMacro(labl); if (macro && macro -> def) Error("Macro multiply defined"); else { if (macro == NULL) { macro = AddMacro(labl); nparms = 0; token = GetWord(word); while (token == -1) { nparms++; if (nparms > maxMacParms) Error("Too many macro parameters"); else { AddMacroParm(macro,word); token = GetWord(word); if (token == ',') token = GetWord(word); } } if (word[0]) Error("Illegal operand"); } if (pass == 2) macro -> def = TRUE; i = ReadSourceLine(line, sizeof(line)); while (i && typ != o_ENDM) { if (pass == 2) ListOut(); strcpy(listLine, " "); // 16 blanks strncat(listLine, line, 255-16); // skip initial formfeeds linePtr = line; while (*linePtr == 12) linePtr++; labl[0] = 0; if (isalphanum(*linePtr) || *linePtr == '@') { token = GetWord(labl); if (token) showAddr = TRUE; while (*linePtr == ' ' || *linePtr == '\t') linePtr++; if (labl[0]) { if (token == '@') { GetWord(word); strcpy(labl,lastLabl); strcat(labl,"@"); strcat(labl,word); // labl = lastLabl + "@" + word; } else strcpy(lastLabl,labl); } if (*linePtr == ':') linePtr++; } typ = 0; if (GetOpcode(opcode)) FindOpcode(opcode, &typ, &parm, &xmacro); switch(typ) { case o_END: Error("END not allowed inside a macro"); break; case o_ENDM: if (pass == 1 && labl[0]) AddMacroLine(macro,labl); break; default: if (pass == 1) AddMacroLine(macro,line); break; } i = ReadSourceLine(line, sizeof(line)); } if (typ != o_ENDM) Error("Missing ENDM"); } break; default: Error("Unknown opcode"); EatIt(); break; } } void DoPass() { Str255 labl; Str255 opcode; int typ; int parm; int i; Str255 word; int token; MacroPtr macro; fseek(source, 0, SEEK_SET); // rewind source file sourceEnd = FALSE; lastLabl[0] = 0; printf("Pass %d\n",pass); #ifdef DEBUG_PASS if (cl_List) fprintf(listing,"========== Pass %d ==========\n",pass); #endif CodeAbsOrg(0); errCount = 0; listFlag = TRUE; listMacFlag = FALSE; i = ReadSourceLine(line, sizeof(line)); while (i && !sourceEnd) { errFlag = FALSE; warnFlag = FALSE; instrLen = 0; showAddr = FALSE; listThisLine = listFlag; strcpy(listLine, " "); // 16 blanks strncat(listLine, line, 255-16); // skip initial formfeeds linePtr = line; while (*linePtr == 12) linePtr++; // look for label at beginning of line labl[0] = 0; if (isalphanum(*linePtr) || *linePtr == '@') { token = GetWord(labl); if (token) showAddr = TRUE; while (*linePtr == ' ' || *linePtr == '\t') linePtr++; if (labl[0]) { if (token == '@') { GetWord(word); strcpy(labl,lastLabl); strcat(labl,"@"); strcat(labl,word); // labl = lastLabl + "@" + word; } else strcpy(lastLabl,labl); } if (*linePtr == ':') linePtr++; } token = GetOpcode(opcode); if (token == 0 || token == '*') // line with label only { DefSym(labl,locPtr,FALSE,FALSE); } else { FindOpcode(opcode, &typ, &parm, ¯o); if (typ == o_Illegal) { sprintf(word,"Illegal opcode '%s'",opcode); Error(word); } else if (typ == o_MacName) { if (macPtr) Error("Nested macros not supported"); else { macPtr = macro; macLine = macro -> text; GetMacParms(macro); showAddr = TRUE; DefSym(labl,locPtr,FALSE,FALSE); } } else if (typ >= o_LabelOp) { showAddr = FALSE; DoLabelOp(typ,parm,labl); } else { showAddr = TRUE; DefSym(labl,locPtr,FALSE,FALSE); DoOpcode(typ, parm); } if (typ != o_Illegal && typ != o_MacName) if (GetWord(word)) Error("Too many operands"); } #ifndef DEBUG_PASS if (pass == 1) AddLocPtr(abs(instrLen)); else #endif { if (showAddr) { sprintf(word,"%.4X",locPtr); // codPtr for (i=0; i<4; i++) listLine[i] = word[i]; } if (instrLen>0) for (i = 0; i < instrLen; i++) { sprintf(word,"%.2X",instr[i]); listLine[i*2+5] = word[0]; listLine[i*2+6] = word[1]; CodeOut(instr[i]); } else if (instrLen<0) { for (i = 0; i < -instrLen; i++) { if (i > 0 && i % 5 == 0) { if (listThisLine) ListOut(); strcpy(listLine, " "); // 16 blanks sprintf(word,"%.4X",locPtr); listLine[0] = word[0]; listLine[1] = word[1]; listLine[2] = word[2]; listLine[3] = word[3]; } sprintf(word,"%.2X",bytStr[i]); if (i<5) { listLine[i*2+5] = word[0]; listLine[i*2+6] = word[1]; } else { listLine[(i%5)*2+5] = word[0]; listLine[(i%5)*2+6] = word[1]; listLine[(i%5)*2+7] = 0; } CodeOut(bytStr[i]); } } if (listThisLine && (errFlag || listMacFlag || !macLineFlag)) ListOut(); } i = ReadSourceLine(line, sizeof(line)); } if (pass == 2) CodeEnd(); // Put the lines after the END statement into the listing file // while still checking for listing control statements. Ignore // any lines which have invalid syntax, etc., because whatever // is found after an END statement should esentially be ignored. if (pass == 2) { while (i) { listThisLine = listFlag; strcpy(listLine, " "); // 16 blanks strncat(listLine, line, 255-16); if (line[0]==' ' || line[0]=='\t') // ignore labels (this isn't the right way) { GetOpcode(opcode); FindOpcode(opcode, &typ, &parm, ¯o); if (typ == o_LIST || typ == o_OPT) { DoLabelOp(typ,parm,""); } } if (listThisLine) ListOut(); i = ReadSourceLine(line, sizeof(line)); } } } // -------------------------------------------------------------- // initialization and parameters void stdusage(void) { printf("\n"); printf("Usage:\n"); printf(" %s [options] srcfile\n",progname); printf("\n"); printf("Options:\n"); printf(" -- end of options\n"); printf(" -e show errors to screen\n"); printf(" -w show warnings to screen\n"); printf(" -l [filename] make a listing file, default is srcfile.lst\n"); printf(" -o [filename] make an object file, default is srcfile.hex\n"); } void getopts(int argc, char * const argv[]) { int ch; while ((ch = getopt(argc, argv, "ewl:o:?")) != -1) { switch (ch) { case 'e': cl_Err = TRUE; break; case 'w': cl_Warn = TRUE; break; case 'l': cl_List = TRUE; if (optarg[0] =='-') { optarg = ""; optind--; } strncpy(cl_ListName, optarg, 255); break; case 'o': cl_Obj = TRUE; if (optarg[0] =='-') { optarg = ""; optind--; } strncpy(cl_ObjName, optarg, 255); break; case '?': default: usage(); } } argc -= optind; argv += optind; // now argc is the number of remaining arguments // and argv[0] is the first remaining argument if (argc != 1) usage(); strncpy(cl_SrcName, argv[0], 255); if (cl_List && cl_ListName[0] == 0) { strncpy(cl_ListName, cl_SrcName, 255-4); strcat (cl_ListName, ".lst"); } if (cl_Obj && cl_ObjName [0] == 0) { strncpy(cl_ObjName, cl_SrcName, 255-4); strcat (cl_ObjName, ".hex"); } } int main (int argc, char * const argv[]) { int i; // initialize and get parms progname = argv[0]; pass = 0; symTab = NULL; xferAddr = 0; xferFound = FALSE; macroTab = NULL; macPtr = NULL; macLine = NULL; cl_Err = FALSE; cl_Warn = FALSE; cl_List = FALSE; cl_Obj = FALSE; for (i=0; i