public static (List <Lex>, List <string>) lex(string[] input) { List <Lex> result = new List <Lex>(); List <string> encounteredErrors = new List <string>(); for (var i = 0; i < input.Length; i++) { string line = input[i]; string[] lineContents = line.Split(new Char[] { ' ', ',' }); if (lineContents.Length <= 0) { continue; } bool isValidCommand = true; Lex thisLex = new Lex(); thisLex.arguments = new List <string>(); switch (lineContents[0].ToUpper()) { case "JP": thisLex.instructionType = InstructionType.JP; break; case "JNE": thisLex.instructionType = InstructionType.JNE; break; case "JPE": thisLex.instructionType = InstructionType.JPE; break; case "LD": thisLex.instructionType = InstructionType.LD; break; case "ADD": thisLex.instructionType = InstructionType.Add; break; case "OR": thisLex.instructionType = InstructionType.OR; break; case "AND": thisLex.instructionType = InstructionType.AND; break; case "XOR": thisLex.instructionType = InstructionType.XOR; break; case "SUB": thisLex.instructionType = InstructionType.SUB; break; case "SLR": thisLex.instructionType = InstructionType.SLR; break; case "SLL": thisLex.instructionType = InstructionType.SLL; break; case "SETDL": thisLex.instructionType = InstructionType.SETDL; break; case "GETDL": thisLex.instructionType = InstructionType.GETDL; break; case "DIS": thisLex.instructionType = InstructionType.DIS; break; default: encounteredErrors.Add($"Line {i.ToString()}: {lineContents[0]} not recognized as a command."); isValidCommand = false; break; } if (isValidCommand) { bool frstArg = true; foreach (string arg in lineContents) { if (frstArg || (arg.Length <= 0)) { frstArg = false; continue; } thisLex.arguments.Add(arg.ToUpper()); } thisLex.lineNumber = i; result.Add(thisLex); } } return(result, encounteredErrors); }
public static (List <char>, List <string>) Assemble(List <Lex> lexerOutput) { List <char> result = new List <char>(); List <string> errors = new List <string>(); for (var i = 0; i < lexerOutput.Count; i++) { Lex line = lexerOutput[i]; char ResultOpcode = (char)0x0000; int dest = new int(); int src = new int(); int lit = new int(); switch (line.instructionType) { case InstructionType.Add: if (line.arguments.Count != 2) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: Bad number of operands."); break; } if (getArgType(line.arguments[0]) != ArgType.reg) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: Destination must be a register."); break; } if ((getArgType(line.arguments[1]) != ArgType.reg) && (getArgType(line.arguments[1]) != ArgType.literal)) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: \"line.arguments[1]\" not recognized as a valid register/literal."); break; } dest = getReg(line.arguments[0]) & 0xF; if (getArgType(line.arguments[1]) == ArgType.reg) { src = getReg(line.arguments[1]) & 0xF; ResultOpcode = (char)(0x8004 + (dest << 8) + (src << 4)); } else { lit = literalParse(line.arguments[1]) & 0xFF; ResultOpcode = (char)(0x7000 + (dest << 8) + lit); } break; case InstructionType.LD: if (line.arguments.Count != 2) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: Bad number of operands."); break; } if (getArgType(line.arguments[0]) != ArgType.reg) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: Destination must be a register."); break; } if ((getArgType(line.arguments[1]) != ArgType.reg) && (getArgType(line.arguments[1]) != ArgType.literal)) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: \"line.arguments[1]\" not recognized as a valid register/literal."); break; } dest = getReg(line.arguments[0]) & 0xF; if (getArgType(line.arguments[1]) == ArgType.reg) { src = getReg(line.arguments[1]) & 0xF; ResultOpcode = (char)(0x8000 + (dest << 8) + (src << 4)); } else { lit = literalParse(line.arguments[1]) & 0xFF; ResultOpcode = (char)(0x6000 + (dest << 8) + lit); } break; case InstructionType.JNE: if (line.arguments.Count != 2) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: Bad number of operands."); break; } if (getArgType(line.arguments[0]) != ArgType.reg) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: Destination must be a register."); break; } if ((getArgType(line.arguments[1]) != ArgType.reg) && (getArgType(line.arguments[1]) != ArgType.literal)) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: \"line.arguments[1]\" not recognized as a valid register/literal."); break; } dest = getReg(line.arguments[0]) & 0xF; if (getArgType(line.arguments[1]) == ArgType.reg) { src = getReg(line.arguments[1]) & 0xF; ResultOpcode = (char)(0x9000 + (dest << 8) + (src << 4)); } else { lit = literalParse(line.arguments[1]) & 0xFF; ResultOpcode = (char)(0x4000 + (dest << 8) + lit); } break; case InstructionType.JPE: if (line.arguments.Count != 2) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: Bad number of operands."); break; } if (getArgType(line.arguments[0]) != ArgType.reg) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: Destination must be a register."); break; } if ((getArgType(line.arguments[1]) != ArgType.reg) && (getArgType(line.arguments[1]) != ArgType.literal)) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: \"line.arguments[1]\" not recognized as a valid register/literal."); break; } dest = getReg(line.arguments[0]) & 0xF; if (getArgType(line.arguments[1]) == ArgType.reg) { src = getReg(line.arguments[1]) & 0xF; ResultOpcode = (char)(0x5000 + (dest << 8) + (src << 4)); } else { lit = literalParse(line.arguments[1]) & 0xFF; ResultOpcode = (char)(0x3000 + (dest << 8) + lit); } break; case InstructionType.SUB: if (line.arguments.Count != 2) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: Bad number of operands."); break; } if (getArgType(line.arguments[0]) != ArgType.reg) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: Destination must be a register."); break; } if (getArgType(line.arguments[1]) != ArgType.reg) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: Source must be a register."); break; } dest = getReg(line.arguments[0]) & 0xF; src = getReg(line.arguments[1]) & 0xF; ResultOpcode = (char)(0x8005 + (dest << 8) + (src << 4)); break; case InstructionType.AND: if (line.arguments.Count != 2) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: Bad number of operands."); break; } if ((getArgType(line.arguments[0]) != ArgType.reg) || (getArgType(line.arguments[1]) != ArgType.reg)) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: Operands must be registers."); break; } dest = getReg(line.arguments[0]) & 0xF; src = getReg(line.arguments[1]) & 0xF; ResultOpcode = (char)(0x8002 + (dest << 8) + (src << 4)); break; case InstructionType.OR: if (line.arguments.Count != 2) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: Bad number of operands."); break; } if ((getArgType(line.arguments[0]) != ArgType.reg) || (getArgType(line.arguments[1]) != ArgType.reg)) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: Operands must be registers."); break; } dest = getReg(line.arguments[0]) & 0xF; src = getReg(line.arguments[1]) & 0xF; ResultOpcode = (char)(0x8001 + (dest << 8) + (src << 4)); break; case InstructionType.XOR: if (line.arguments.Count != 2) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: Bad number of operands."); break; } if ((getArgType(line.arguments[0]) != ArgType.reg) || (getArgType(line.arguments[1]) != ArgType.reg)) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: Operands must be registers."); break; } dest = getReg(line.arguments[0]) & 0xF; src = getReg(line.arguments[1]) & 0xF; ResultOpcode = (char)(0x8003 + (dest << 8) + (src << 4)); break; case InstructionType.SLL: if (line.arguments.Count != 1) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: Bad number of operands."); break; } if (getArgType(line.arguments[0]) != ArgType.reg) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: Operand must be a register."); break; } dest = getReg(line.arguments[0]) & 0xF; ResultOpcode = (char)(0x800E + (dest << 8)); break; case InstructionType.SLR: if (line.arguments.Count != 1) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: Bad number of operands."); break; } if (getArgType(line.arguments[0]) != ArgType.reg) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: Operand must be a register."); break; } dest = getReg(line.arguments[0]) & 0xF; ResultOpcode = (char)(0x8006 + (dest << 8)); break; case InstructionType.DIS: if (line.arguments.Count > 0) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: No operands are needed for DIS."); break; } ResultOpcode = (char)(0xF000); break; default: break; case InstructionType.SETDL: if (line.arguments.Count != 1) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: Bad number of operands."); break; } if (getArgType(line.arguments[0]) != ArgType.reg) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: Operand must be a register."); break; } dest = getReg(line.arguments[0]) & 0xF; ResultOpcode = (char)(0xF015 + (dest << 8)); break; case InstructionType.GETDL: if (line.arguments.Count != 1) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: Bad number of operands."); break; } if (getArgType(line.arguments[0]) != ArgType.reg) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: Operand must be a register."); break; } dest = getReg(line.arguments[0]) & 0xF; ResultOpcode = (char)(0xF007 + (dest << 8)); break; case InstructionType.JP: if (line.arguments.Count != 1) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: Bad number of operands."); break; } if (getArgType(line.arguments[0]) != ArgType.literal) { ResultOpcode = (char)0x0000; errors.Add($"Line {line.lineNumber}: Operand must be a literal."); break; } dest = getReg(line.arguments[0]) & 0xFFF; ResultOpcode = (char)(0x1000 + dest); break; } result.Add(ResultOpcode); } return(result, errors); }