Example #1
0
        private void GenerateOutput(Stream target)
        {
            int numobjects = objects.Count;

            LMSObject[] oarray = new LMSObject[numobjects];

            // get all objects in order of their ID
            foreach (LMSObject o in objects.Values)
            {
                oarray[o.id - 1] = o;
            }

            // create the byte codes in a temporary buffer and memorize positions
            MemoryStream allbytecodes    = new MemoryStream();
            int          totalheadersize = 16 + numobjects * 12;

            for (int i = 0; i < numobjects; i++)
            {
                oarray[i].WriteBody(allbytecodes, totalheadersize + (int)allbytecodes.Length);
            }

            // write file header
            target.WriteByte((byte)'L');
            target.WriteByte((byte)'E');
            target.WriteByte((byte)'G');
            target.WriteByte((byte)'O');
            DataWriter.Write32(target, totalheadersize + (int)allbytecodes.Length);
            DataWriter.Write16(target, 0x0068);
            DataWriter.Write16(target, numobjects);
            DataWriter.Write32(target, globals.TotalBytes());
            // write object headers
            for (int i = 0; i < numobjects; i++)
            {
                oarray[i].WriteHeader(target);
//                oarray[i].print();
//                Console.ReadKey();
            }
            // write all object bodies
            allbytecodes.WriteTo(target);
        }
Example #2
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();
        }
Example #3
0
        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);
                    }
                }
            }
        }