void Assembler::extractMacroDefinitions(){ for(int lineNum=0; lineNum<program.size(); lineNum++){ vector<ProgramLine> macroLines; ProgramLine programLine = program[lineNum]; string token = parser.extractFirstToken(programLine.text); if(token == ".macro"){ macroLines.push_back(programLine); program.erase(program.begin() + lineNum); while(lineNum < program.size()){ if(parser.extractFirstToken(program[lineNum].text) == ".end_macro"){ break; } macroLines.push_back(program[lineNum]); program.erase(program.begin() + lineNum); } if(program.size() == 0){ //EXCEPTION string error = "Macro not matched with .end_macro directive before EOF"; string offendingToken = programLine.text; addException(AssemblerException(programLine, error, offendingToken)); return; } macroLines.push_back(program[lineNum]); program.erase(program.begin() + lineNum); MacroAtom atom = MacroAtom(macroLines); macroDB.push_back(atom); lineNum--; }else{ } } }
void Assembler::replaceLabels(){ for(int i=0; i<alignedProgram.size(); i++){ ProgramAtom atom = alignedProgram[i]; if(atom.type == DIRECTIVE_INSTRUCTION){ //Modified replacement string mnemonic = parser.extractFirstToken(atom.token); mnemonic = parser.toLower(mnemonic); bool isBranch = parser.tokenIsBranchInstructionName(mnemonic); bool isJump = parser.tokenIsJumpInstructionName(mnemonic); vector<string> instructionTokens = parser.tokenizeInstruction(atom.token); if(isBranch || isJump){ string lastToken = instructionTokens[instructionTokens.size() - 1]; if(!tokenIsInLabelDB(lastToken)){ //EXCEPTION string error = ERROR_UNRECOGNIZED_LABEL; string offendingToken = lastToken; addException(AssemblerException(*atom.programLine, error, offendingToken)); continue; } virtualAddr labelAddr = getLabelAddress(lastToken); virtualAddr instructionAddr = atom.addr; virtualAddr immediateVal = 0; if(isBranch){ int32_t offset = labelAddr - instructionAddr - 4; //pc still increments by 4 on branches offset >>= 2; immediateVal = (virtualAddr)offset; }else if(isJump){ immediateVal = (labelAddr & 0x0FFFFFFF) >> 2; } string immediateString = parser.literals.getHexLiteralString(immediateVal); instructionTokens[instructionTokens.size() - 1] = immediateString; string newInstructionString = parser.combineInstructionTokens(instructionTokens); alignedProgram[i].token = newInstructionString; }else{
void Assembler::flushLabelBuffer(){ for(int i=0; i<labelsToAssign.size(); i++){ virtualAddr addr = memorySegmentTopArray[currentMemorySegment]; try{ addLabelAddress(parser.getLabelName(labelsToAssign[i]->text), addr); }catch(InvalidTokenException &e){ //EXCEPTION string error = ERROR_INVALID_LABEL; string offendingToken = labelsToAssign[i]->text; addException(AssemblerException(*labelsToAssign[i], error, offendingToken)); continue; } ProgramAtom atom; atom.addr = addr; atom.token = parser.getLabelName(labelsToAssign[i]->text); atom.type = DIRECTIVE_LABEL; atom.programLine = labelsToAssign[i]; alignedProgram.push_back(atom); } labelsToAssign.clear(); }
void Assembler::loadProgramFromFile(string fileName, ProgramLine* programLine){ string programFileDir = rootDirectory + fileName; fstream file = fstream(programFileDir); if(!file.is_open()){ //EXCEPTION string error = "I'm sorry Dave, I'm afraid I can't open that file"; string offendingToken = rootDirectory + fileName; throw AssemblerException(*programLine, error, offendingToken); return; } string tmpProgramLine; uint32_t lineNumber = 0; while(getline(file, tmpProgramLine)){ tmpProgramLine = parser.sanitizeProgramLine(tmpProgramLine); string token = parser.toLower(parser.extractFirstToken(tmpProgramLine)); if(token == ".include"){ parser.extractAndRemoveFirstToken(tmpProgramLine, token); string nestedFileName = parser.trim(tmpProgramLine); nestedFileName = parser.removeNestedQuotes(nestedFileName); nestedFileName = parser.trim(nestedFileName); ProgramLine* programLinePtr = (program.size() == 0)? NULL : &program[program.size() - 1]; loadProgramFromFile(nestedFileName, programLinePtr); continue; } if(tmpProgramLine != ""){ ProgramLine programLine; programLine.fileName = rootDirectory + fileName; programLine.lineNumber = lineNumber; programLine.text = tmpProgramLine; program.push_back(programLine); } lineNumber++; } }
unsigned short Assembler::start() { unsigned short start = 0; Parser::LinePtr curLine; std::map<std::string, unsigned short> labelAddr; std::deque<Parser::LinePtr> lines; unsigned short curAddr(0); #ifdef DEBUG std::cout << "Analyzing code..." << std::endl; #endif while (curLine = m_parser.getNextLine()) { std::string lbl(curLine->label); if (!curLine->label.empty()) { if (labelAddr.find(curLine->label) != labelAddr.end()) { std::string msg("Duplicate label: "); msg += curLine->label; msg += " on line "; msg += (int)m_parser.getLineNumber(); throw AssemblerException(msg); } labelAddr[curLine->label] = curAddr; this->labelReverse[curAddr] = curLine->label; } lines.push_back(curLine); byteToLineMap[curAddr] = (int)m_parser.getLineNumber(); if (boost::dynamic_pointer_cast<Parser::Byte>(curLine)) { curAddr++; } else { curAddr+=4; } } #ifdef DEBUG std::cout << "Processed: " << m_parser.getLineNumber() << " lines. " << labelAddr.size() << " labels, " << lines.size() * 4 << " bytes used." << std::endl; std::cout << "Building binary block..." << std::endl; #endif curAddr = 0; while (lines.size()) { Parser::LinePtr line(lines.front()); lines.pop_front(); Parser::IntPtr intData(boost::dynamic_pointer_cast<Parser::Int>(line)); Parser::BytePtr byteData(boost::dynamic_pointer_cast<Parser::Byte>(line)); Parser::InstructionPtr instruction(boost::dynamic_pointer_cast<Parser::Instruction>(line)); if (byteData) { // This is byte data m_block[curAddr] = byteData->value; curAddr++; } else if (intData) { *((int*)&m_block[curAddr]) = intData->value; curAddr += sizeof(intData->value); } else if (instruction) { // This is an actual "machine" instruction // First, let's record the address of the first instruction (relative to the "machine") if (!start) start = curAddr; ParamType type = PT_DEFAULT; instructionBlock block; block.value = 0; if (instruction->args.size() >= 1) { char reg(getRegister(instruction->args[0])); if (reg >= 0) { block.uint8_param = (unsigned char)reg; type = PT_REG; } else if (labelAddr.find(instruction->args[0]) != labelAddr.end()) { block.uint16_param2 = labelAddr[instruction->args[0]]; type = PT_ADDR; } else { try { block.uint16_param2 = boost::lexical_cast<unsigned short>(instruction->args[0]); type = PT_IMMEDIATE; } catch (...) { // boost::bad_lexical_cast std::string msg = "Invalid command; unrecognized argument 1 on command " + instruction->name; msg += " on line " + boost::lexical_cast<std::string>(byteToLineMap[curAddr]); throw AssemblerException(msg); } } } if (instruction->args.size() >= 2 && !block.uint16_param2) { char reg(getRegister(instruction->args[1])); if (reg >= 0) { block.uint8_param2 = (unsigned char)reg; type = PT_REGREG; } else if (labelAddr.find(instruction->args[1]) != labelAddr.end()) { block.uint16_param2 = labelAddr[instruction->args[1]]; type = PT_REGADDR; } else { try { block.uint16_param2 = boost::lexical_cast<unsigned short>(instruction->args[1]); type = PT_REGIMMEDIATE; } catch (...) { // boost::bad_lexical_cast std::string msg = "Invalid command; unrecognized argument 2 on command " + instruction->name; msg += " on line " + boost::lexical_cast<std::string>(byteToLineMap[curAddr]); throw AssemblerException(msg); } } } if (instruction->args.size() > 2) { throw AssemblerException("Too many arguments on command " + instruction->name + " on line " + boost::lexical_cast<std::string>(byteToLineMap[curAddr])); } block.instruction = m_config->strToBinary(instruction->name, type); *((int*)&m_block[curAddr]) = block.value; curAddr += sizeof(block.value); } else { throw AssemblerException("Invalid LinePtr found at " + curAddr); } } return start; }
//Post-processing void Assembler::pseudoInstructionReplace(){ for(int i=0; i<alignedProgram.size(); i++){ ProgramAtom atom = alignedProgram[i]; string line = atom.token; if(atom.type == DIRECTIVE_INSTRUCTION){ string mnemonic = parser.extractFirstToken(atom.token); mnemonic = parser.toLower(mnemonic); if(parser.tokenIsPseudoInstructionName(mnemonic)){ int pseudoInstructionNumber = parser.getPseudoInstructionNameNumber(mnemonic); int numInsertedLines = parser.getPseudoInstructionNumberOfLinesToInsert(mnemonic); vector<string> tokenizedInstruction = parser.tokenizeInstruction(line); switch(pseudoInstructionNumber){ //TODO: add exceptions for incorrect number of instruction arguments case 0: { //bge $reg1, $reg2, label if(tokenizedInstruction.size() != 4){addException(AssemblerException(*atom.programLine, ERROR_INVALID_PSEUDOINSTRUCTION, atom.programLine->text));continue;} string registerName1 = tokenizedInstruction[1]; string registerName2 = tokenizedInstruction[2]; string labelName = tokenizedInstruction[3]; string line1 = "slt\t$at, " + registerName1 + ", " + registerName2; string line2 = "beq\t$at, $zero, " + labelName; alignedProgram[i].token = line1; alignedProgram[i+1].token = line2; } break; case 1: { //bgt $reg1, $reg2, label if(tokenizedInstruction.size() != 4){addException(AssemblerException(*atom.programLine, ERROR_INVALID_PSEUDOINSTRUCTION, atom.programLine->text));continue;} string registerName1 = tokenizedInstruction[1]; string registerName2 = tokenizedInstruction[2]; string labelName = tokenizedInstruction[3]; string line1 = "slt\t$at, " + registerName2 + ", " + registerName1; string line2 = "bne\t$at, $zero, " + labelName; alignedProgram[i].token = line1; alignedProgram[i+1].token = line2; } break; case 2: { //ble $reg1, $reg2, label if(tokenizedInstruction.size() != 4){addException(AssemblerException(*atom.programLine, ERROR_INVALID_PSEUDOINSTRUCTION, atom.programLine->text));continue;} string registerName1 = tokenizedInstruction[1]; string registerName2 = tokenizedInstruction[2]; string labelName = tokenizedInstruction[3]; string line1 = "slt\t$at, " + registerName2 + ", " + registerName1; string line2 = "beq\t$at, $zero, " + labelName; alignedProgram[i].token = line1; alignedProgram[i+1].token = line2; } break; case 3: { //blt $reg1, $reg2, label if(tokenizedInstruction.size() != 4){addException(AssemblerException(*atom.programLine, ERROR_INVALID_PSEUDOINSTRUCTION, atom.programLine->text));continue;} string registerName1 = tokenizedInstruction[1]; string registerName2 = tokenizedInstruction[2]; string labelName = tokenizedInstruction[3]; string line1 = "slt\t$at, " + registerName1 + ", " + registerName2; string line2 = "bne\t$at, $zero, " + labelName; alignedProgram[i].token = line1; alignedProgram[i+1].token = line2; } break; case 4: { //clear $reg if(tokenizedInstruction.size() != 2){addException(AssemblerException(*atom.programLine, ERROR_INVALID_PSEUDOINSTRUCTION, atom.programLine->text));continue;} string registerName1 = tokenizedInstruction[1]; string line1 = "add\t" + registerName1 + ", $zero, $zero"; alignedProgram[i].token = line1; } break; case 5: { //la $reg, label if(tokenizedInstruction.size() != 3){addException(AssemblerException(*atom.programLine, ERROR_INVALID_PSEUDOINSTRUCTION, atom.programLine->text));continue;} string labelName = tokenizedInstruction[2]; if(!tokenIsInLabelDB(labelName)){ //EXCEPTION string error = ERROR_UNRECOGNIZED_LABEL; string offendingToken = labelName; addException(AssemblerException(*atom.programLine, error, offendingToken)); continue; } virtualAddr labelAddr = getLabelAddress(labelName); virtualAddr msb = labelAddr >> (SIZE_BITS_VIRTUAL_ADDR / 2); virtualAddr lsb = labelAddr & 0x0000FFFF; string msbHex = parser.literals.getHexLiteralString(msb); string lsbHex = parser.literals.getHexLiteralString(lsb); string registerName = tokenizedInstruction[1]; string line1 = "lui\t" + registerName + ", " + msbHex; string line2 = "ori\t" + registerName + ", " + registerName + ", " + lsbHex; alignedProgram[i].token = line1; alignedProgram[i+1].token = line2; } break; case 6: { //li $reg, imm if(tokenizedInstruction.size() != 3){addException(AssemblerException(*atom.programLine, ERROR_INVALID_PSEUDOINSTRUCTION, atom.programLine->text));continue;} string immediateString = tokenizedInstruction[2]; //EXCEPTION //TODO uint32_t immediateVal; try{ immediateVal = parser.literals.getLiteralValue(immediateString); }catch(InvalidTokenException &e){ string error = ERROR_INVALID_IMMEDIATE_LI; string offendingToken = immediateString; addException(AssemblerException(*atom.programLine, error, offendingToken)); continue; } virtualAddr msb = immediateVal >> (SIZE_BITS_WORD / 2); virtualAddr lsb = immediateVal & 0x0000FFFF; string msbHex = parser.literals.getHexLiteralString(msb); string lsbHex = parser.literals.getHexLiteralString(lsb); string registerName = tokenizedInstruction[1]; string line1 = "lui\t" + registerName + ", " + msbHex; string line2 = "ori\t" + registerName + ", " + registerName + ", " + lsbHex; alignedProgram[i].token = line1; alignedProgram[i+1].token = line2; } break; case 7: { //move $reg1, $reg2 if(tokenizedInstruction.size() != 3){addException(AssemblerException(*atom.programLine, ERROR_INVALID_PSEUDOINSTRUCTION, atom.programLine->text));continue;} string registerName1 = tokenizedInstruction[1]; string registerName2 = tokenizedInstruction[2]; string line1 = "add\t" + registerName1 + ", " + registerName2 + ", $zero"; alignedProgram[i].token = line1; } break; case 8: { //neg $reg1, $reg2 if(tokenizedInstruction.size() != 3){addException(AssemblerException(*atom.programLine, ERROR_INVALID_PSEUDOINSTRUCTION, atom.programLine->text));continue;} string registerName1 = tokenizedInstruction[1]; string registerName2 = tokenizedInstruction[2]; string line1 = "sub\t" + registerName1 + ", $zero, " + registerName2; alignedProgram[i].token = line1; } break; case 9: { //not $reg1, $reg2 if(tokenizedInstruction.size() != 3){addException(AssemblerException(*atom.programLine, ERROR_INVALID_PSEUDOINSTRUCTION, atom.programLine->text));continue;} string registerName1 = tokenizedInstruction[1]; string registerName2 = tokenizedInstruction[2]; string line1 = "addi\t" + registerName1 + ", $zero, -1"; string line2 = "xor\t" + registerName1 + ", " + registerName1 + "," + registerName2; alignedProgram[i].token = line1; alignedProgram[i+1].token = line2; } break; /* PUSH: sub $sp,$sp,4 sw $t2,($sp) POP: lw $t2,($sp) addiu $sp,$sp,4 */ case 10: { //push $reg if(tokenizedInstruction.size() != 2){addException(AssemblerException(*atom.programLine, ERROR_INVALID_PSEUDOINSTRUCTION, atom.programLine->text));continue;} string registerName1 = tokenizedInstruction[1]; string line1 = "sub\t$sp, $sp, 4"; string line2 = "sw\t" + registerName1 + ", 0($sp)"; alignedProgram[i].token = line1; alignedProgram[i+1].token = line2; } break; case 11: { //pop $reg if(tokenizedInstruction.size() != 2){addException(AssemblerException(*atom.programLine, ERROR_INVALID_PSEUDOINSTRUCTION, atom.programLine->text));continue;} string registerName1 = tokenizedInstruction[1]; string line1 = "lw\t" + registerName1 + ", 0($sp)"; string line2 = "addi\t$sp, $sp, 4"; alignedProgram[i].token = line1; alignedProgram[i+1].token = line2; } break; case 12: { //peak $reg if(tokenizedInstruction.size() != 2){addException(AssemblerException(*atom.programLine, ERROR_INVALID_PSEUDOINSTRUCTION, atom.programLine->text));continue;} string registerName = tokenizedInstruction[1]; string line = "lw\t" + registerName + ", 0($sp)"; alignedProgram[i].token = line; } break; case 13: { //rem } break; case 14: { //sge } break; case 15: { //sgt } break; default: break; } i += numInsertedLines; }else{ } }else{ } } }
void Assembler::alignRawProgram(){ for(int lineNum=0; lineNum<program.size(); lineNum++){ ProgramLine programLine = program[lineNum]; string token = parser.extractFirstToken(programLine.text); if(parser.tokenIsLabel(token)){ string labelName = parser.getLabelName(token); programLine.text = labelName; labelsToAssign.push_back(&program[lineNum]); continue; }else if(parser.tokenIsDirective(token)){ parser.extractAndRemoveFirstToken(programLine.text, token); applyDirective(token, &programLine); token = parser.extractFirstToken(programLine.text); } if(programLine.text == "" && currentAction != ACTION_DECLARE_SEGMENT && currentAction != ACTION_MEMWRITE_INTEGRAL){ continue; //if programLine is all consumed, skip to next line unless you need to declare segment in following actions } //consume literal token ProgramAtom atom; string mappedProgramString; switch(currentAction){ case ACTION_INIT: { string error = ERROR_UNRECOGNIZED_TOKEN; string offendingToken = programLine.text; addException(AssemblerException(program[lineNum], error, offendingToken)); continue; } break; case ACTION_DECLARE_SEGMENT: { virtualAddr addr = getCurrentMemoryLocation(); mappedProgramString = parser.getDirectiveName(currentMemorySegment); atom.addr = addr; atom.token = mappedProgramString; atom.type = currentMemorySegment; atom.programLine = &program[lineNum]; alignedProgram.push_back(atom); switch(currentMemorySegment){ case DIRECTIVE_DATA: currentAction = ACTION_INIT; break; case DIRECTIVE_TEXT: currentAction = ACTION_INSTRUCTION_ENCODE; break; case DIRECTIVE_KDATA: currentAction = ACTION_INIT; break; case DIRECTIVE_KTEXT: currentAction = ACTION_INSTRUCTION_ENCODE; break; } } break; case ACTION_MEMWRITE_INTEGRAL: { alignSegmentTop(); flushLabelBuffer(); vector<string> literalTokens = parser.commaSeparatedLiteralListExplode(programLine.text); alignLiteralTokenList(literalTokens, programLine.text, &program[lineNum]); currentAction = ACTION_INIT; } break; case ACTION_MEMWRITE_STRING: { flushLabelBuffer(); int i=0; while(programLine.text[i] != '"'){i++;} string stringLiteral = programLine.text.substr(i); string rawString; try{ rawString = parser.literals.getStringLiteralValue(stringLiteral); }catch(InvalidTokenException &e){ //EXCEPTION string error = ERROR_INVALID_STRING_LITERAL; string offendingToken = programLine.text; addException(AssemblerException(program[lineNum], error, offendingToken)); continue; } mappedProgramString = parser.literals.getRawStringLiteralValue(rawString); atom.addr = getCurrentMemoryLocation(); atom.token = mappedProgramString; atom.type = currentValueTypeSpecifier; atom.programLine = &program[lineNum]; alignedProgram.push_back(atom); virtualAddr segmentIncrementSize = rawString.length() * SIZE_BYTES_BYTE; if(currentValueTypeSpecifier == DIRECTIVE_ASCIIZ){ segmentIncrementSize+=2; } incrementSegmentTop(segmentIncrementSize); currentAction = ACTION_INIT; } break; case ACTION_ALIGN: { try{ currentByteAlignment = parser.literals.getFixedPointLiteralValue(token); }catch(InvalidTokenException &e){ string error = ERROR_INVALID_ALIGNMENT_VALUE; string offendingToken = token; addException(AssemblerException(program[lineNum], error, token)); continue; } alignSegmentTop(); currentAction = ACTION_INIT; } break; case ACTION_SPACE: { currentByteAlignment = SIZE_BYTES_BYTE; alignSegmentTop(); flushLabelBuffer(); parser.extractAndRemoveFirstToken(programLine.text, token); uint32_t spaceSize = 0; try{ spaceSize = parser.literals.getFixedPointLiteralValue(token); }catch(InvalidTokenException &e){ //EXCEPTION string error = ERROR_INVALID_SPACE_VALUE; string offendingToken = token; addException(AssemblerException(program[lineNum], error, offendingToken)); continue; } atom.token = parser.literals.getDecimalLiteralString(spaceSize); atom.addr = getCurrentMemoryLocation(); atom.type = DIRECTIVE_SPACE; atom.programLine = &program[lineNum]; alignedProgram.push_back(atom); incrementSegmentTop(spaceSize); currentAction = ACTION_INIT; } break; case ACTION_INSTRUCTION_ENCODE: { currentByteAlignment = SIZE_BYTES_WORD; alignSegmentTop(); flushLabelBuffer(); atom.addr = getCurrentMemoryLocation(); atom.token = programLine.text; //instruction full line atom.type = DIRECTIVE_INSTRUCTION; atom.programLine = &program[lineNum]; alignedProgram.push_back(atom); incrementSegmentTop(SIZE_BYTES_WORD); } break; default: break; } } }
void Assembler::applyDirective(string directive, ProgramLine* programLine){ uint32_t directiveNumber = parser.getDirectiveNumber(directive); switch(directiveNumber){ //Primary memory segments case DIRECTIVE_DATA: currentMemorySegment = DIRECTIVE_DATA; currentAction = ACTION_DECLARE_SEGMENT; break; case DIRECTIVE_TEXT: currentMemorySegment = DIRECTIVE_TEXT; currentAction = ACTION_DECLARE_SEGMENT; break; case DIRECTIVE_KDATA: currentMemorySegment = DIRECTIVE_KDATA; currentAction = ACTION_DECLARE_SEGMENT; break; case DIRECTIVE_KTEXT: currentMemorySegment = DIRECTIVE_KTEXT; currentAction = ACTION_DECLARE_SEGMENT; break; //Memory value type specifiers (integral) case DIRECTIVE_BYTE: currentValueTypeSpecifier = DIRECTIVE_BYTE; currentByteAlignment = SIZE_BYTES_BYTE; currentAction = ACTION_MEMWRITE_INTEGRAL; break; case DIRECTIVE_HALF: currentValueTypeSpecifier = DIRECTIVE_HALF; currentByteAlignment = SIZE_BYTES_HWORD; currentAction = ACTION_MEMWRITE_INTEGRAL; break; case DIRECTIVE_WORD: currentValueTypeSpecifier = DIRECTIVE_WORD; currentByteAlignment = SIZE_BYTES_WORD; currentAction = ACTION_MEMWRITE_INTEGRAL; break; case DIRECTIVE_FLOAT: currentValueTypeSpecifier = DIRECTIVE_FLOAT; currentByteAlignment = SIZE_BYTES_FLOAT; currentAction = ACTION_MEMWRITE_INTEGRAL; break; case DIRECTIVE_DOUBLE: currentValueTypeSpecifier = DIRECTIVE_DOUBLE; currentByteAlignment = SIZE_BYTES_DOUBLE; currentAction = ACTION_MEMWRITE_INTEGRAL; break; //Memory value type specifiers (string) case DIRECTIVE_ASCII: currentValueTypeSpecifier = DIRECTIVE_ASCII; currentByteAlignment = SIZE_BYTES_BYTE; currentAction = ACTION_MEMWRITE_STRING; break; case DIRECTIVE_ASCIIZ: currentValueTypeSpecifier = DIRECTIVE_ASCIIZ; currentByteAlignment = SIZE_BYTES_BYTE; currentAction = ACTION_MEMWRITE_STRING; break; //Memory alignment specifiers case DIRECTIVE_ALIGN: currentAction = ACTION_ALIGN; break; case DIRECTIVE_SPACE: currentByteAlignment = SIZE_BYTES_BYTE; currentAction = ACTION_SPACE; break; case DIRECTIVE_INCLUDE: break; case DIRECTIVE_EXTERN: break; case DIRECTIVE_GLOBL: break; case DIRECTIVE_SET: break; case DIRECTIVE_MACRO: currentAction = ACTION_INSTRUCTION_ENCODE; break; case DIRECTIVE_END_MACRO: currentAction = ACTION_INIT; break; case DIRECTIVE_EQV: break; default: //EXCEPTION string error = ERROR_UNRECOGNIZED_DIRECTIVE; string offendingToken = directive; addException(AssemblerException(*programLine, error, offendingToken)); break; } }