public LMSObject(String name, int id) { this.name = name; this.id = id; this.program = null; this.locals = new DataArea(); this.labels = new Dictionary <String, int>(); this.references = new Dictionary <int, String>(); this.offsetToInstructions = 0; }
public void Assemble(Stream source, Stream target, List <String> errorList) { globals = new DataArea(); objects = new Dictionary <String, LMSObject>(); currentobject = null; // read and process the input line by line StreamReader reader = new StreamReader(source, System.Text.Encoding.ASCII); String l = reader.ReadLine(); for (int linenumber = 1; l != null; l = reader.ReadLine(), linenumber++) { try { ProcessLine(l); } catch (AssemblerException e) { errorList.Add("Error at line " + linenumber + ": " + e.Message); } } if (currentobject != null) { errorList.Add("Unexpected end of file"); } reader.Close(); try { GenerateOutput(target); } catch (AssemblerException e) { errorList.Add("Error at subcall integration: " + e.Message); } // globals.print(); // Console.ReadKey(); }
// decodes a parameter and adds it to bytecode stream. // return either DataElement, int, double, or String (for type checking) private Object DecodeAndAddParameter(DataArea locals, String p) { // this must be a label address difference if ((!p.StartsWith("'")) && p.Contains(':')) { currentobject.AddLabelDifference(p); return(999999999); // only compatible with 32bit numbers } // this must be a variable else if ((p[0] >= 'A' && p[0] <= 'Z') || p[0] == '_') { // check if have offset suffix int offset = 0; int plusidx = p.IndexOf('+'); if (plusidx >= 0) { if (Int32.TryParse(p.Substring(plusidx + 1), NumberStyles.Integer, CultureInfo.InvariantCulture, out offset)) { p = p.Substring(0, plusidx); } } DataElement e = null; bool local = true; if (locals != null) { e = locals.Get(p); } if (e == null) { e = globals.Get(p); local = false; } if (e == null) { throw new AssemblerException("Unknown identifier " + p); } currentobject.AddVariableReference(e.position + offset, local); return(e); } // this must be a constant numeric value else if ((p[0] >= '0' && p[0] <= '9') || p[0] == '-') { Int32 c; double d; if (Int32.TryParse(p, NumberStyles.Integer, CultureInfo.InvariantCulture, out c)) { currentobject.AddConstant(c); return(c); } if (double.TryParse(p, NumberStyles.Float, CultureInfo.InvariantCulture, out d)) { currentobject.AddFloatConstant(d); return(d); } throw new AssemblerException("Can not decode number: " + p); } // this must be a string literal else if (p[0] == '\'') { String l = p.Substring(1, p.Length - 2); currentobject.AddStringLiteral(l); return(l); } else { throw new AssemblerException("Invalid parameter value"); } }
private void ProcessLine(String l) { List <String> tokens = TokenizeLine(l); if (tokens.Count < 1) { return; } String first = tokens[0]; // Console.WriteLine(first); // currently on top level if (currentobject == null) { if (first.Equals("VMTHREAD")) { String name = FetchID(tokens, 1, true); if (objects.ContainsKey(name)) { // could have found object that was created because of forward reference LMSObject lo = objects[name]; lo.StartCode(); currentobject = (LMSThread)lo; // make sure that this object is indeed a thread } else { // this is the first encounter of the name - create a new thread currentobject = new LMSThread(name, objects.Count + 1); currentobject.StartCode(); objects[name] = currentobject; } } else if (first.Equals("SUBCALL")) { String name = FetchID(tokens, 1, true); if (objects.ContainsKey(name)) { // could have found the object that was created because of a forward reference LMSObject lo = objects[name]; lo.StartCode(); currentobject = (LMSSubCall)lo; // make sure that this object is indeed a subcall } else { // this is the first encounter of the name - create a new subcall LMSSubCall sc = new LMSSubCall(name, objects.Count + 1); objects[name] = sc; sc.StartCode(); currentobject = sc; } } else if (first.Equals("DATA8")) { globals.Add(FetchID(tokens, 1, true), 1, 1, DataType.I8, false); } else if (first.Equals("DATA16")) { globals.Add(FetchID(tokens, 1, true), 2, 1, DataType.I16, false); } else if (first.Equals("DATA32")) { globals.Add(FetchID(tokens, 1, true), 4, 1, DataType.I32, false); } else if (first.Equals("DATAF")) { globals.Add(FetchID(tokens, 1, true), 4, 1, DataType.F, false); } else if (first.Equals("DATAS") || first.Equals("ARRAY8")) { globals.Add(FetchID(tokens, 1, false), 1, FetchNumber(tokens, 2, true), DataType.I8, false); } else if (first.Equals("ARRAY16")) { globals.Add(FetchID(tokens, 1, false), 2, FetchNumber(tokens, 2, true), DataType.I16, false); } else if (first.Equals("ARRAY32")) { globals.Add(FetchID(tokens, 1, false), 4, FetchNumber(tokens, 2, true), DataType.I32, false); } else if (first.Equals("ARRAYF")) { globals.Add(FetchID(tokens, 1, false), 4, FetchNumber(tokens, 2, true), DataType.F, false); } else { throw new AssemblerException("Unknown command: " + first); } } // currently inside a structure element else { DataArea locals = currentobject.locals; if (first.Equals("}")) { // currentobject.print(); currentobject = null; return; } if (first.Equals("SUBCALL")) // trying to create a subcall with multiple object IDs, but with the same code { if (!(currentobject is LMSSubCall)) { throw new AssemblerException("Can not add subcall alias to non-subcall object"); } String name = FetchID(tokens, 1, true); if (objects.ContainsKey(name)) { // could have found the object that was created because of a forward reference LMSObject lo = objects[name]; ((LMSSubCall)lo).SetImplementation((LMSSubCall)currentobject); } else { // this is the first encounter of the name - create a new subcall LMSSubCall sc = new LMSSubCall(name, objects.Count + 1); objects[name] = sc; sc.SetImplementation((LMSSubCall)currentobject); } } else if (first.Equals("DATA8")) { locals.Add(FetchID(tokens, 1, true), 1, 1, DataType.I8, false); } else if (first.Equals("DATA16")) { locals.Add(FetchID(tokens, 1, true), 2, 1, DataType.I16, false); } else if (first.Equals("DATA32")) { locals.Add(FetchID(tokens, 1, true), 4, 1, DataType.I32, false); } else if (first.Equals("DATAF")) { locals.Add(FetchID(tokens, 1, true), 4, 1, DataType.F, false); } else if (first.Equals("DATAS") || first.Equals("ARRAY8")) { locals.Add(FetchID(tokens, 1, false), 1, FetchNumber(tokens, 2, true), DataType.I8, false); } else if (first.Equals("ARRAY16")) { locals.Add(FetchID(tokens, 1, false), 2, FetchNumber(tokens, 2, true), DataType.I16, false); } else if (first.Equals("ARRAY32")) { locals.Add(FetchID(tokens, 1, false), 4, FetchNumber(tokens, 2, true), DataType.I32, false); } else if (first.Equals("ARRAYF")) { locals.Add(FetchID(tokens, 1, false), 4, FetchNumber(tokens, 2, true), DataType.F, false); } else if (first.Equals("IN_8")) { locals.Add(FetchID(tokens, 1, true), 1, 1, DataType.I8, true); currentobject.MemorizeIOParameter(DataType.I8, AccessType.Read); } else if (first.Equals("IN_16")) { locals.Add(FetchID(tokens, 1, true), 2, 1, DataType.I16, true); currentobject.MemorizeIOParameter(DataType.I16, AccessType.Read); } else if (first.Equals("IN_32")) { locals.Add(FetchID(tokens, 1, true), 4, 1, DataType.I32, true); currentobject.MemorizeIOParameter(DataType.I32, AccessType.Read); } else if (first.Equals("IN_F")) { locals.Add(FetchID(tokens, 1, true), 4, 1, DataType.F, true); currentobject.MemorizeIOParameter(DataType.F, AccessType.Read); } else if (first.Equals("IN_S")) { int n = FetchNumber(tokens, 2, true); locals.Add(FetchID(tokens, 1, false), 1, n, DataType.I8, true); currentobject.MemorizeStringIOParameter(n, AccessType.ReadMany); } else if (first.Equals("OUT_8")) { locals.Add(FetchID(tokens, 1, true), 1, 1, DataType.I8, true); currentobject.MemorizeIOParameter(DataType.I8, AccessType.Write); } else if (first.Equals("OUT_16")) { locals.Add(FetchID(tokens, 1, true), 2, 1, DataType.I16, true); currentobject.MemorizeIOParameter(DataType.I16, AccessType.Write); } else if (first.Equals("OUT_32")) { locals.Add(FetchID(tokens, 1, true), 4, 1, DataType.I32, true); currentobject.MemorizeIOParameter(DataType.I32, AccessType.Write); } else if (first.Equals("OUT_F")) { locals.Add(FetchID(tokens, 1, true), 4, 1, DataType.F, true); currentobject.MemorizeIOParameter(DataType.F, AccessType.Write); } else if (first.Equals("OUT_S")) { int n = FetchNumber(tokens, 2, true); locals.Add(FetchID(tokens, 1, false), 1, n, DataType.I8, true); currentobject.MemorizeStringIOParameter(n, AccessType.Write); } else if (first.Equals("IO_8")) { locals.Add(FetchID(tokens, 1, true), 1, 1, DataType.I8, true); currentobject.MemorizeIOParameter(DataType.I8, AccessType.ReadWrite); } else if (first.Equals("IO_16")) { locals.Add(FetchID(tokens, 1, true), 2, 1, DataType.I16, true); currentobject.MemorizeIOParameter(DataType.I16, AccessType.ReadWrite); } else if (first.Equals("IO_32")) { locals.Add(FetchID(tokens, 1, true), 4, 1, DataType.I32, true); currentobject.MemorizeIOParameter(DataType.I32, AccessType.ReadWrite); } else if (first.Equals("IO_F")) { locals.Add(FetchID(tokens, 1, true), 4, 1, DataType.F, true); currentobject.MemorizeIOParameter(DataType.F, AccessType.ReadWrite); } else if (first.Equals("IO_S")) { int n = FetchNumber(tokens, 2, true); locals.Add(FetchID(tokens, 1, false), 1, n, DataType.I8, true); currentobject.MemorizeStringIOParameter(n, AccessType.ReadWrite); } // calling a subcall object (maybe without having the declaration yet) else if (first.Equals("CALL")) { String name = FetchID(tokens, 1, false); LMSSubCall sc = null; // the name is already known if (objects.ContainsKey(name)) { LMSObject o = objects[name]; if (!(o is LMSSubCall)) { throw new AssemblerException("Trying to call an object that is not defined as a SUBCALL"); } sc = (LMSSubCall)o; } // name is not known - create an empty subcall object right here else { sc = new LMSSubCall(name, objects.Count + 1); objects[name] = sc; } // generate the opcode and the parameters and memorize the types for later check sc.StartCallerMemorization(); int numpar = tokens.Count - 2; currentobject.AddOpCode(new byte[] { 0x09 }); // CALL currentobject.AddConstant(sc.id); // ID of called subcall currentobject.AddConstant(numpar); for (int i = 0; i < numpar; i++) { Object p = DecodeAndAddParameter(locals, tokens[2 + i]); sc.MemorizeCallerParameter(p); // keep for later type check } } // process a label declaration else if (first.EndsWith(":")) { if (first.IndexOf(':') < first.Length - 1) { throw new AssemblerException("Label must only have one trailing ':'"); } currentobject.MemorizeLabel(first.Substring(0, first.Length - 1)); } else { // process regular VMCommands VMCommand c; int paramstart = 0; if (commands.ContainsKey(tokens[0])) { c = commands[tokens[0]]; paramstart = 1; } else if (tokens.Count < 2) { throw new AssemblerException("Unknown opcode " + tokens[0]); } else { String compound = tokens[0] + " " + tokens[1]; if (commands.ContainsKey(compound)) { c = commands[compound]; paramstart = 2; } else { throw new AssemblerException("Unknown opcode " + compound); } } int paramcount = c.parameters.Length; // this is the default parameter number (can be modifed by some special opcodes) // create opcode and parameters currentobject.AddOpCode(c.opcode); for (int i = 0; i < paramcount; i++) { if (paramstart + i >= tokens.Count) { throw new AssemblerException("Too few parameters for " + c.name); } // of more paramerters then specified, repeat the last type (can only happen for opcodes with variable parameter number) int pidx = Math.Min(i, c.parameters.Length - 1); if (c.parameters[pidx] == DataType.Label) // special handling for jump label parameters { currentobject.AddLabelReference(tokens[paramstart + i]); } else if (c.parameters[pidx] == DataType.VMThread) // special handling for VM thread identifier { String name = tokens[paramstart + i]; LMSThread th = null; // the name is already known if (objects.ContainsKey(name)) { LMSObject o = objects[name]; if (!(o is LMSThread)) { throw new AssemblerException("Trying to start an object that is not defined as a thread"); } th = (LMSThread)o; } // name is not known - create an empty thread object right here else { th = new LMSThread(name, objects.Count + 1); objects[name] = th; } currentobject.AddConstant(th.id); } else if (c.parameters[pidx] == DataType.VMSubcall) // special handling for VM subcall identifier { String name = tokens[paramstart + i]; if (name.Equals("0")) { // no subcall id - want to access something global currentobject.AddConstant(0); } else { LMSSubCall th = null; // the name is already known if (objects.ContainsKey(name)) { LMSObject o = objects[name]; if (!(o is LMSSubCall)) { throw new AssemblerException("Trying to access an object that is not defined as a subcall"); } th = (LMSSubCall)o; } // name is not known - create an empty thread object right here else { th = new LMSSubCall(name, objects.Count + 1); objects[name] = th; } currentobject.AddConstant(th.id); } } else if (c.parameters[pidx] == DataType.ParameterCount) // special handling for opcodes with variable parameter number { Int32 p; if (!Int32.TryParse(tokens[paramstart + i], NumberStyles.Integer, CultureInfo.InvariantCulture, out p)) { throw new AssemblerException("Can not decode parameter count specifier"); } if (p < 0 || p > 1000000000) { throw new AssemblerException("Parameter count specifier out of range"); } currentobject.AddConstant(p); paramcount = c.parameters.Length - 1 + p; // calculate number of parameters needed because of given specifier } else { // normal parameters (numbers, strings, variables) Object a = DecodeAndAddParameter(locals, tokens[paramstart + i]); DataTypeChecker.check(a, c.parameters[pidx], c.access[pidx]); } } // check final number of parameters that were generated if (paramstart + paramcount != tokens.Count) { throw new AssemblerException("Invalid number of parameters for " + c.name); } } } }