// Computer System Project( IMPLEMENTING AN ASSEMBLER) // Author: Junshan Li // Date : 2/28/2000 /* Purpose: The program translates the assembly language programs (source programs) into machine language programs (object code) for which the CPU can understand. */ #include #include #include #include #include #include // structure for opcode table struct associate { // Define opcodeTab array to be a global variable. char *opcode; unsigned opcodeNum; } opcodeTab[] = { {"lodd", 0x0}, {"stod", 0x1}, {"addd", 0x2}, {"subd", 0x3}, {"lodl", 0x4}, {"stol", 0x5}, {"addl", 0x6}, {"subl", 0x7}, {"loco", 0x8}, {"jump", 0x9}, {"jpos", 0xA}, {"jneg", 0xB}, {"jzer", 0xC}, {"jnze", 0xD}, {"call", 0xE}, {"retn", 0xF0}, {"push", 0xF1}, {"pop", 0xF2}, {"pshi", 0xF3}, {"popi", 0xF4}, {"swap", 0xF5}, {"insp", 0xF6}, {"desp", 0xF7}, {"uout", 0xFFF5}, {"sin", 0xFFF6}, {"sout", 0xFFF7}, {"hin", 0xFFF8}, {"hout", 0xFFF9}, {"ain", 0xFFFA}, {"aout", 0xFFFB}, {"din", 0xFFFC}, {"dout", 0xFFFD}, {"bkpt", 0xFFFE}, {"halt", 0xFFFF} }; // structure for symbol table struct StSlot { char *symbolPtr; unsigned address; }; // Define opcode table size and symbol table size to be global constants: const int OPCODETABSIZE = 34, SYMTABSIZE = 100; //4096; // void testOpcodeArray(); // =============== function delarations =============== // check if label duplicate void checkDupliateLabel(char aLine[], char *labelPtr, StSlot symTabArray[], int labelTotal, int locn_counter); // check the operand void checkOperands(char aLine[], int locn_counter, char *opPtr, char *operandPtr, unsigned opNum); // check if label is valid: void checkLabelValidity(char aLine[], char *labelPtr, int locn_counter); // display symbol table array void displaySymbolTabArray(StSlot symTabArray[], int labelTotal); // get input file name char *getInfileName(int argc, char *argv[]); // get output file name char *getOutfileName(char *afile); // initialize symbol table void initSymTab(StSlot symTabArray[]); int isLabel(char *operandPtr); int isLabel1(char *operandPtr, StSlot symTabArray[], int labelTotal, unsigned& operandAddr); int isNumber(char *operandPtr); int isValidOperation(char *opPtr, unsigned& opNum); void passOne(ifstream& fin, ofstream& fout, char *infile, StSlot symTabArray[], int& locn_counter, int& labelTotal); void passTwo(ifstream& fin, ofstream& fout, char *infile, StSlot symTabArray[], int& locn_counter, int labelTotal); void processLabel(char aLine[], char *labelPtr, StSlot symTabArray[], int locn_counter, int& labelTotal); void processLine(char aLine[], StSlot symTabArray[], int locn_counter, int& labelTotal, ofstream& fout); void processLine2(char aLine[], StSlot symTabArray[], int locn_counter, int& labelTotal, ofstream& fout); void processOperand(char aLine[], char *operandPtr, int locn_counter, ofstream& fout, StSlot symTabArray[], int labelTotal); void processOperation(char aLine[], char *opPtr, int locn_counter, unsigned& opNum); // =============== Function main ==================== int main(int argc, char *argv[]) { // ===== variable declarations ==================== int locn_counter = 0, labelTotal = 0; char *infileName, *outfileName; ifstream fin; ofstream fout; StSlot symtab[SYMTABSIZE]; // testOpcodeArray(); // ===== Open input and output files ============== // Get input file name infileName = getInfileName(argc, argv); // open input file fin.open(infileName); if (fin.fail()) { cout << "Input file opening failed!!!\n"; exit(1); } // Get output file name outfileName = getOutfileName(infileName); // Open output file fout.open(outfileName); // This will create a new file if not exist. if (fout.fail()) { cout << "Output file opening failed!!!\n"; exit(1); } // ===== Process pass one ========================= initSymTab(symtab); passOne(fin, fout, infileName, symtab, locn_counter, labelTotal); // Output "T": fout.write("T", 1); // Reset input file to the beginning: fin.clear(); // clears EOF fin.seekg(0); // reset file position to beginning // Reset locn_counter: locn_counter = 0; // ===== Process pass two ========================= passTwo(fin, fout, infileName, symtab, locn_counter, labelTotal); // ===== Send message to screen =================== cout << "Input file = " << infileName << endl; cout << "Output file = " << outfileName << endl; cout << "Number base = decimal\n"; cout << "Case sensitive\n"; // ===== Close files ============================== fin.close(); fout.close(); return 0; } // end of main function // ===== Function definitions(in alphabet order) ==== // check if label duplicates: void checkDupliateLabel(char aLine[], char *labelPtr, StSlot symTabArray[], int labelTotal, int locn_counter) { for (int i = 0; i < labelTotal; i++) { // compare the current label to existing labels in symTabArray: if (strcmp(labelPtr, symTabArray[i].symbolPtr) == 0) { cout << "Error on line " << locn_counter << "\n" << aLine << "\nDuplicate label\n"; exit(1); } } } // check the operand void checkOperands(char aLine[], int locn_counter, char *opPtr, char *operandPtr, unsigned opNum) { int junk = isValidOperation(opPtr, opNum); // get current opNum. int stringInt; // cout << "\n^^^^^^^^In checkOperands, opNum = " << opNum << endl; // opcode from 0x0 to 0xE , 0xF6 and 0xF7 should have operand: if ( ((opNum <= 0xE) ||(opNum == 0xF6) || (opNum == 0xF7)) && !operandPtr && !(opNum == 9999)) { cout << "Incorrect number of operands for " << opPtr << ". Terminating ... \n"; exit(1); } else if (isNumber(operandPtr) && operandPtr) { stringInt = atoi(operandPtr); // cout << "In checkOperands, stringInt: " << stringInt << endl; if ((opNum <= 0xE) && (stringInt > 4096)) { cout << "Error on line " << locn_counter << endl << aLine << endl << "x field constants can be at most 4096. " << "Operand out of range. \n"; exit(1); } else if ((stringInt < 0) && (opNum != 9999)) { cout << "Error on line " << locn_counter << endl << aLine << endl << "x, y field constants must be at least 0. " << "Operand out of range. \n"; exit(1); } else if ((stringInt > 255) && ((opNum == 0xF6) || (opNum == 0xF7))) { cout << "Error on line " << locn_counter << endl << aLine << endl << "y field constants must be at most 0. " << "Operand out of range. \n"; exit(1); } } // Other opcodes should not have operands. if ( !( (opNum <= 0xE) || (opNum == 0xF6) || (opNum == 0xF7)) && operandPtr && !(opNum == 9999)) { cout << "opum = " << opNum << " Incorrect number of operands for " << opPtr << ".\n It shouldn't have any operands. Terminating ... \n"; exit(1); } } // check if label is valid: void checkLabelValidity(char aLine[], char *idPtr, int locn_counter) { char *idCopy = "copy"; char *idReturn = "return"; //cout << "In checkValidity******\n"; if (! isalpha(*idPtr)) { // get the first character cout << "Error on line: " << locn_counter << ". " << aLine << "\nThe label: " << idPtr << " is invalid, label should begin with a letter.\n"; exit(1); } while (*idPtr) { if (! (isalpha(*idPtr) || isdigit(*idPtr)) ) { cout << "Error on line: " << locn_counter << ". " << aLine << endl << "Illegal character: " << *idPtr << " found in label." << "\nThe label must only contain letters or digits.\n"; exit(1); } idPtr++; } // end of while } // display symbol table array void displaySymbolTabArray(StSlot symTabArray[], int labelTotal) { cout << "**** Test symbel table Array ****" << endl; cout << "labelTotal: " << labelTotal << endl; for (int i = 0; i < labelTotal; i++) { cout << "In symbol table array: element: " << i << ", the symbolPtr: " << symTabArray[i].symbolPtr << endl << "The address: " << symTabArray[i].address << endl; } cout << "**** End Testing symbel table Array ****" << endl; } // get input file name char *getInfileName(int argc, char *argv[]) { // This func returns a ptr. char *ptr; if (argc != 2) { cout << "Incorrect number of command line arguments" << endl; cout << "Usage: masv1 \n"; exit(1); } else { // if file name without a ".mas" extension, I need to add it in. ptr = strchr(argv[1], '.'); // cout << "The file name is " << argv[1] << endl; if (ptr == NULL) { //cout << "The ptr is NULL\n"; strcat(argv[1], ".mas"); ptr = argv[1]; } else { // If the file name has ".mas" extension, we get it directly: ptr = argv[1]; } } return ptr; } // get output file name char *getOutfileName(char *afile) { char *tokenPtr = " NULL";//= "test"; char *ptr= " NULL"; //= "This is a test"; char *copyReturn= " NULL"; //= "test"; copyReturn = strcpy(tokenPtr, afile); // save a copy for afile. ptr = strtok(tokenPtr, "."); strcat(ptr, ".mac"); return ptr; } // initialize symbol table void initSymTab(StSlot symTabArray[]) { for (int i = 0; i < SYMTABSIZE; i++) { symTabArray[i].symbolPtr = "i"; symTabArray[i].address = 0; } } // check if the operand is a lable, used in pass one int isLabel(char *operandPtr) { if (isalpha(*operandPtr)) return 1; return 0; } // int isLabel1(char *operandPtr, StSlot symTabArray[], int labelTotal, unsigned& operandAddr) { for (int i = 0; i < labelTotal; i++) { // If operand is found in the symbol table, then operand is a label: if (strcmp(operandPtr, symTabArray[i].symbolPtr) == 0) { operandAddr = symTabArray[i].address; //cout << "operand is: " << operandPtr << " &&& address &&&: " // << operandAddr << endl; return 1; // return true } } return 0; // return false } int isNumber(char *operandPtr) { char *idCopy = "copy"; char *idReturn = "return"; idReturn = strcpy(idCopy, operandPtr); //cout << "In isNumber ******\n"; // Check the first symbol is + or - for numbers: if ((*idCopy == '+') || (*idCopy == '-')) { // get the first character idCopy++; } while (*idCopy) { if (! isdigit(*idCopy) ) { return 0; } idCopy++; } // end of while //cout << operandPtr << ": The operand is a digit!\n"; return 1; // return true. } int isValidOperation(char *opPtr, unsigned& opNum) { // cout << "In ValidOperation func************\n"; for (int i = 0; i < OPCODETABSIZE; i++) { // OPCODETABSIZE is global a const. //cout << "opPtr is: " << opPtr << endl; // If operand is found in the symbol table, then operand is a label: if ((strcmp(opPtr, opcodeTab[i].opcode) == 0) || (strcmp(opPtr, "dw") == 0)) { //cout << "opPtr is: " << opPtr << " its hex number: " // << opcodeTab[i].opcodeNum << endl; if (strcmp(opPtr, opcodeTab[i].opcode) == 0) { opNum = opcodeTab[i].opcodeNum; } else opNum = 9999; // "dw" case. return 1; // return true } } // cout << "opcode: " << opPtr << " is invalid.\n"; return 0; // return false } void passOne(ifstream& fin, ofstream& fout, char *infile, StSlot symTabArray[], int& locn_counter, int& labelTotal){ const int SIZE = 40; char aLine[SIZE]; //In pass 1: Loop until no more input: fin.getline(aLine, SIZE); processLine(aLine, symTabArray, locn_counter, labelTotal, fout); while (! fin.eof()) { //cout << "The line is: " << aLine << " locn_counter: " // << locn_counter << endl; locn_counter++; // Increase locn_counter when reading a line. fin.getline(aLine, SIZE); processLine(aLine, symTabArray, locn_counter, labelTotal, fout); } } void passTwo(ifstream& fin, ofstream& fout, char *infile, StSlot symTabArray[], int& locn_counter, int labelTotal){ const int SIZE = 40; char aLine[SIZE]; //int labelTotal = 0; // cout << "***** Starting pass 2: also show symbol table *******\n"; // Test symbol table array: // displaySymbolTabArray(symTabArray, labelTotal); //In pass 2: Loop until no more input: fin.getline(aLine, SIZE); processLine2(aLine, symTabArray, locn_counter, labelTotal, fout); while (! fin.eof()) { //cout << "The line is: " << aLine << " locn_counter: " // << locn_counter << endl; locn_counter++; // Increase locn_counter when reading a line. // check if program overflowed: if (locn_counter > 4095) { cout << "Program overflowed!!!\n"; exit(1); } fin.getline(aLine, SIZE); processLine2(aLine, symTabArray, locn_counter, labelTotal, fout); } //cout << "***** Ending passTwo*****\n"; } void processLabel(char aLine[], char *labelPtr, StSlot symTabArray[], int locn_counter, int& labelTotal) { char *labelCopy = "copy"; char *labelReturn = "return"; // check if label is valid: checkLabelValidity(aLine, labelPtr, locn_counter); // check if duplicate: checkDupliateLabel(aLine, labelPtr, symTabArray, labelTotal, locn_counter); // check if symbol table overflowed: if (labelTotal >= SYMTABSIZE) { cout << "Symbol table overflowed!!!\n"; exit(1); } // make a copy of labelPtr: labelReturn = strcpy(labelCopy, labelPtr); // If all above checkings passed, add an entry into symTabArray: symTabArray[labelTotal].symbolPtr = new char[strlen(labelPtr) + 1]; labelReturn = strcpy(symTabArray[labelTotal].symbolPtr, labelCopy); symTabArray[labelTotal].address = locn_counter; // Increase total number of labels. labelTotal++; } void processLine(char aLine[], StSlot symTabArray[], int locn_counter, int& labelTotal, ofstream& fout) { char *tokenPtr = "test"; // This must be a char pointer in order to work. char *ptr = "init"; char *copyReturn = "test"; char *labelPtr = "label", *opPtr = "opcode", *operandPtr = "operand"; copyReturn = strcpy(tokenPtr, aLine); // save a copy for aLine. ptr = strchr(tokenPtr, ':'); if (ptr) { // label exist? *ptr = ' '; // replace : with blank labelPtr = strtok(tokenPtr, " \t"); // get label // process label: processLabel(aLine, labelPtr, symTabArray, locn_counter, labelTotal); opPtr = strtok(NULL, " \t"); // get operation } else opPtr = strtok(tokenPtr, " \t"); // get operation operandPtr = strtok(NULL, " \t"); // get operand if (operandPtr) { // process operandPtr only when it is not null: processOperand(aLine, operandPtr, locn_counter, fout, symTabArray,labelTotal ); } //cout << "Label: " << labelPtr << " operation: " << opPtr // << " operand: " << operandPtr << endl; } void processLine2(char aLine[], StSlot symTabArray[], int locn_counter, int& labelTotal, ofstream& fout) { char *tokenPtr = "test"; // This must be a char pointer in order to work. char *ptr = "init"; char *copyReturn = "test"; char *labelPtr = "label", *opPtr = "opcode", *operandPtr = "operand"; unsigned opNum = 0x0, operand = 0x0; //, macword = 0x0; int operandConst = 0, yn = 0; long operandLong = 0, macword = 0x0; copyReturn = strcpy(tokenPtr, aLine); // save a copy for aLine. ptr = strchr(tokenPtr, ':'); if (ptr) { // label exist? *ptr = ' '; // replace : with blank labelPtr = strtok(tokenPtr, " \t"); // get label // process label: opPtr = strtok(NULL, " \t"); // get operation } else opPtr = strtok(tokenPtr, " \t"); // get operation operandPtr = strtok(NULL, " \t"); // get operand // Process operation: if (opPtr) { //operandPtr must not be null, otherwisw trouble!! // Check if the operation gets correct number of operands first: if (operandPtr) { checkOperands(aLine, locn_counter, opPtr, operandPtr, opNum); } // Get the opcode number: processOperation(aLine, opPtr, locn_counter, opNum); } if (operandPtr) { // process operandPtr only when it is not null: if (isLabel1(operandPtr, symTabArray, labelTotal, operand)) { //processOperand2(aLine, operandPtr, locn_counter, fout, // symTabArray, labelTotal); } else if (isLabel(operandPtr)) { // label not find. cout << "Label: " << operandPtr << " is not found. Terminating...\n"; exit(1); } else if (isNumber(operandPtr)) { // the operand is an absolute value. // convert the operand to binary: operand = atoi(operandPtr); /*** cout << "In processLine2, dw case, when operand is a number.\n" << "opcode = " << opPtr << "operandPtr = " << operandPtr << " operand = " << operand << endl; ***/ } } if (opPtr) { yn = isValidOperation(opPtr, opNum); } if (yn && (opNum != 9999)) { // if yn == 1, then opNum is mnemonic. /*** cout << "In constructing macword, opPtr: " << opPtr << " opNum: " << opNum << endl << "operand: " << operand << " operandConst: " << operandConst << endl; ***/ if (opPtr && (opNum <= 0xE)) { // 4 bit opcode case macword = (opNum << 12) | operand; //cout << "4 bit opcode case, macword = " << macword << endl; } else if (opPtr && (opNum >= 0xF0) && (opNum <= 0xF7)) { // 8 bit opcode macword = (opNum << 8) | operand; //cout << "8 bit opcode case, opPtr = " << opPtr // << " macword = " << macword << endl; } else if (opPtr && (opNum >= 0xFFF5) && (opNum <= 0xFFFF)) {// 16 bit. macword = opNum; //cout << "16 bit opcode case, opPtr = " << opPtr // << " macword = " << macword << endl; } // **************** Break point ********************** } else if (opPtr && opNum == 9999) { // "dw" case. operandLong = atol(operandPtr); // convert operand into long integer. //cout << "##### dw case #####: operandPtr = " << operandPtr // << " operand = " << operandLong << endl; // Need to check the dw operand is in the correct range: if ((operandLong < -32768) || (operandLong > 65535)) { // -2**15 < operand < 2**16 cout << "dw constant is out of range (-32768 ~ 65535). " << "Terminating...\n"; exit(1); } macword = operandLong; /*** cout << "In processLine2, dw case, when operand is a number.\n" << "opcode = " << opPtr << " operandPtr = " << operandPtr << " operandLong = " << operandLong << endl; cout << "dw case: macword = " << macword << " opPtr: " << opPtr << endl; ***/ } // Output macword: fout.write((char *)&macword, 2); if (labelPtr && opPtr && operandPtr) { //cout << "In processLine2. Label: " << labelPtr << " operation: " << opPtr // << " operand: " << operandPtr << endl; } } void processOperand(char aLine[], char *operandPtr, int locn_counter, ofstream& fout, StSlot symTabArray[], int labelTotal) { // Check if the operand is valid: if (! isNumber(operandPtr)) { checkLabelValidity(aLine, operandPtr, locn_counter); } // If the operand is a label, output "R" and locn_counter to outfile: if (isLabel(operandPtr)) { //cout << "In processOperand************\n"; fout.write("R", 1); fout.write((char *)&locn_counter, 2); } } void processOperation(char aLine[], char *opPtr, int locn_counter, unsigned& opNum) { // Check if the operation code is valid: if (! isValidOperation(opPtr, opNum)) { cout << "Error on line " << locn_counter << "\n" << aLine << "\nInvalid operation\n"; exit(1); /*** cout << "The opcode " << opPtr << " is invalid on line " << locn_counter << endl << "The line is: " << aLine << " Terminating ...\n"; exit(1); ***/ } //cout << "In processOperation, The opNum is: " << opNum << endl; } void testOpcodeArray() { for (int i = 0; i < OPCODETABSIZE; i++) { cout << "opcode mnemonic: " << opcodeTab[i].opcode << " opcode number: " << opcodeTab[i].opcodeNum << endl; } }