Пример #1
0
        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]);
                }
            }
        }
Пример #2
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);
                    }
                }
            }
        }