private void GridRAM_CellEndEdit(object sender, DataGridViewCellEventArgs e) { edtMessages.Clear(); errors = new SortedDictionary <byte, string>(); labels = new Dictionary <string, byte>(); for (byte addr = 0; addr < 100; addr++) { string line = (string)GridRAM[1, addr].Value; if (line == null) { continue; } line = line.Trim().ToUpper(); //Make sure the labels are accounted for if (line[0] == ':') { string[] parts = line.Split(new char[] { ' ' }, 2, StringSplitOptions.RemoveEmptyEntries); //validation: what can a label be called? parts[0] = parts[0].Substring(1); //remove the : int dummy; //not ever used if (parts[0] == "" || new string[] { "ADD", "SUB", "LDA", "STO", "BR", "BRP", "BRZ", "HLT", "IN", "OUT", "DAT" }.Contains(parts[0]) || int.TryParse(parts[0], out dummy)) { AddError(addr, "Label '" + parts[0] + "' is invalid!"); continue; } //update the label dictionary if (labels.ContainsKey(parts[0])) { labels[parts[0]] = addr; } else { labels.Add(parts[0], addr); } } } for (byte addr = 0; addr < 100; addr++) { string line = (string)GridRAM[1, addr].Value; if (line == null) { continue; } line = line.Trim().ToUpper(); if (line[0] == ':') { string[] parts = line.Split(new char[] { ' ' }, 2, StringSplitOptions.RemoveEmptyEntries); try { line = parts[1];//remove the label } catch (IndexOutOfRangeException) { continue; } } //now translate this into opcode try { string[] parts = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); //translate labels for (int i = 0; i < parts.Length; i++) { if (labels.ContainsKey(parts[i])) { parts[i] = labels[parts[i]].ToString(); } } line = ""; foreach (string part in parts) { line += part + " "; } ushort opcode = Mnemonic.ToByteCode(line); LMC.RAM[addr] = opcode; } catch (Exception except) { AddError(addr, except.Message); } } }
static public ushort ToByteCode(string instruction) { instruction = instruction.ToUpper(); string[] parts = instruction.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (parts.Length == 0) { throw new Exception("An empty string is not valid syntax"); } //check for numbers ushort potentialNumber; if (ushort.TryParse(parts[0], out potentialNumber)) { return(potentialNumber); } else if (parts[0] == "DAT") { return(Mnemonic.ToByteCode(parts[1]));//DAT is followed either by an instruction or a number } else if (parts[0] == "IN") { if (parts.Length > 1) { throw new Exception("Unexpected arguments for IN instruction"); } else { return(901); } } else if (parts[0] == "OUT") { if (parts.Length > 1) { throw new Exception("Unexpected arguments for OUT instruction"); } else { return(902); } } else if (parts[0] == "HLT") { if (parts.Length > 1) { throw new Exception("Unexpected arguments for HLT instruction"); } else { return(0); } } else { if (parts.Length < 2) { throw new Exception("Argument expected for " + parts[0] + " instruction"); } if (parts.Length > 2) { throw new Exception("Unexpected second argument for " + parts[0] + " instruction"); } ushort address; try { address = ushort.Parse(parts[1]); } catch (Exception) { throw new Exception("Argument is invalid"); } if (address > 99) { throw new Exception("Argument is out of bounds!"); } //otherwise we should be ready to parse an instruction with a parameter switch (parts[0]) { case "ADD": return((ushort)(100 + address)); case "SUB": return((ushort)(200 + address)); case "STO": return((ushort)(300 + address)); case "LDA": return((ushort)(500 + address)); case "BR": return((ushort)(600 + address)); case "BRZ": return((ushort)(700 + address)); case "BRP": return((ushort)(800 + address)); default: throw new Exception("Invalid opcode " + parts[0]); } } }