public override void WriteBody(Stream stream, int offsetToInstructions) { if (implementation != null) { return; } int numpar = ioDataTypes.Count; // before actual byte codes there come the IN,OUT,IO descriptors stream.WriteByte((byte)numpar); for (int i = 0; i < numpar; i++) { int ioflags = 0; switch (ioAccessTypes[i]) { case AccessType.Read: case AccessType.ReadMany: ioflags = 0x80; break; case AccessType.Write: ioflags = 0x40; break; case AccessType.ReadWrite: ioflags = 0xC0; break; } switch (ioDataTypes[i]) { case DataType.I8: if (ioStringSizes[i] == 0) // a single I8 will be transfered { stream.WriteByte((byte)(ioflags | 0x00)); } else // transfer a string of I8s { stream.WriteByte((byte)(ioflags | 0x04)); stream.WriteByte((byte)ioStringSizes[i]); } break; case DataType.I16: stream.WriteByte((byte)(ioflags | 0x01)); break; case DataType.I32: stream.WriteByte((byte)(ioflags | 0x02)); break; case DataType.F: stream.WriteByte((byte)(ioflags | 0x03)); break; } } // write actual code parts (with correct termination) WriteByteCodes(stream, offsetToInstructions); stream.WriteByte(0x08); // RETURN stream.WriteByte(0x0A); // OBJECT_END // insert a check to test all occuring calls for compatibility with paramaters foreach (List <Object> l in callerMemorization) { if (l.Count != numpar) { throw new AssemblerException("Detected use of CALL " + name + " with " + l.Count + " parameters instead of " + numpar); } for (int i = 0; i < numpar; i++) { DataTypeChecker.check(l[i], ioDataTypes[i], ioAccessTypes[i]); } } }
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); } } } }