Example #1
0
        private static void EmitExpressionValue(Token t, Queue<Token> smt, ExpressionType type)
        {
            EmitByte(0x20);
            bool hadRef = false;
            switch (t.type)
            {
                case TokenType.edid:
                    if (smt.Count > 0 && smt.Peek().IsSymbol("."))
                    {
                        EmitRefLabel(t, RefType.Expression);
                        smt.Dequeue();
                        if (smt.Count == 0)
                        {
                            throw new ExpressionParseException("Unexpected end of line");
                        }

                        if (farVars.ContainsKey(t.token))
                        {
                            Dictionary<string, ushort> fars = farVars[t.token];
                            t = smt.Dequeue();
                            if (fars.ContainsKey(t.token))
                            {
                                EmitByte(0x73);
                                Emit(fars[t.token]);
                                break;
                            }
                        }
                        else
                        {
                            t = smt.Dequeue();
                        }

                        hadRef = true;
                        goto case TokenType.Function;
                    }
                    else
                    {
                        if (type == ExpressionType.Numeric)
                        {
                            AddError("Reference type not valid here");
                        }

                        EmitRefLabel(t, RefType.Standalone);
                    }

                    break;
                case TokenType.Local:
                    LocalVar lv = locals[t.token];
                    if (lv.type == VarType.Ref && smt.Count > 0 && smt.Peek().IsSymbol("."))
                    {
                        goto case TokenType.edid;
                    }

                    if (lv.type == VarType.Ref && type == ExpressionType.Numeric)
                    {
                        AddError("Reference type not valid here");
                    }

                    if (lv.type != VarType.Ref && type == ExpressionType.Ref)
                    {
                        AddError("A reference assignment must consist of a single edid or function");
                    }

                    if (lv.type == VarType.Int)
                    {
                        EmitByte(0x73);
                    }
                    else
                    {
                        EmitByte(0x66);
                    }

                    Emit((ushort)lv.index);
                    break;
                case TokenType.Global:
                    if (type == ExpressionType.Ref)
                    {
                        AddError("A reference assignment must consist of a single edid or function");
                    }

                    EmitRefLabel(t, RefType.Expression);
                    break;
                case TokenType.Float:
                case TokenType.Integer:
                    if (type == ExpressionType.Ref && t.token != "0")
                    {
                        AddError("A reference assignment must consist of a single edid or function");
                    }

                    bw.Write(Encoding.Instance.GetBytes(t.token));
                    break;
                case TokenType.Function:

                    // FunctionSig fs=functionList[t.token];
                    // if(fs.requiredArgs!=fs.args.Length) throw new ExpressionParseException("functions with variable argument count cannot be used in expressions");
                    // if(fs.ret==VarType.None) throw new ExpressionParseException("Functions with no return type cannot be used in expressions");
                    // if(smt.Count<fs.args.Length) throw new ExpressionParseException("Not enough parameters to function");
                    var args = new Token[smt.Count + 1];
                    args[0] = t;
                    for (int i = 1; i < args.Length; i++)
                    {
                        args[i] = smt.Dequeue();
                    }

                    EmitFunctionCall(ref args, true, hadRef, type == ExpressionType.Ref);
                    for (int i = 0; i < args.Length; i++)
                    {
                        smt.Enqueue(args[i]);
                    }

                    break;
                default:
                    AddError("Expected <local>|<global>|<number>|<function>");
                    break;
            }
        }
Example #2
0
        private static void EmitFunctionCall(ref Token[] smt, bool expression, bool hadref, bool requiresRef)
        {
            FunctionSig fs = functionList[smt[0].token];
            if (hadref && !fs.allowref)
            {
                AddError("Object reference not valid on this function");
            }

            if (expression)
            {
                EmitByte(0x58);

                // if(fs.ret==VarType.None) AddError("Functions with no return type cannot be used in expressions");
            }

            // if(requiresRef&&fs.ret!=VarType.Ref) AddError("Function does not return a reference");
            Emit(fs.opcode);
            if (fs.skipArgs)
            {
                if (expression)
                {
                    AddError("SkipArgs is not valid on functions used in expressions");
                }

                // for(int j=1;j<smt.Length;j++) smt[j-1]=smt[j];
                // Array.Resize<Token>(ref smt, smt.Length-1);
                smt = new Token[0];
                Emit(0);
                return;
            }

            if (smt.Length == 1)
            {
                if (fs.requiredArgs > 0)
                {
                    AddError("Not enough arguments to function");
                }

                if (fs.args.Length > 0)
                {
                    Emit(2);
                }

                Emit(0);
                smt = new Token[0];
                return;
            }

            if (fs.args.Length == 0)
            {
                Emit(0);
                for (int j = 1; j < smt.Length; j++)
                {
                    smt[j - 1] = smt[j];
                }

                Array.Resize(ref smt, smt.Length - 1);
                return;
            }

            long pos = bw.BaseStream.Length;
            ushort argcount = 0;
            Emit(0);
            Emit(0);
            int i = 0;
            bool lastwasref = false;
            while (true)
            {
                i++;
                if (i == smt.Length)
                {
                    if (argcount < fs.requiredArgs)
                    {
                        AddError("Not enough arguments to function. Expected " + fs.requiredArgs);
                    }

                    smt = new Token[0];
                    break;
                }

                if (smt[i].type == TokenType.Symbol)
                {
                    if (smt[i].IsSymbol(".") && lastwasref)
                    {
                        if (i < smt.Length - 1 && farVars.ContainsKey(smt[i - 1].token))
                        {
                            i++;
                            EmitByte(0x73);
                            Dictionary<string, ushort> vars = farVars[smt[i - 2].token];
                            if (!vars.ContainsKey(smt[i].token))
                            {
                                AddError("Reference '" + smt[i - 2].utoken + "' has no variable called '" + smt[i].utoken + "'");
                            }
                            else
                            {
                                Emit(vars[smt[i].token]);
                            }

                            continue;
                        }
                    }
                    else if (smt[i].IsSymbol("-") && (!expression || (argcount < fs.requiredArgs)))
                    {
                        if (i < smt.Length - 1 && (smt[i + 1].type == TokenType.Integer || smt[i + 1].type == TokenType.Float))
                        {
                            smt[i + 1] = new Token(smt[i + 1].type, "-" + smt[i + 1].token);
                            continue;
                        }
                    }

                    if (expression)
                    {
                        if (argcount < fs.requiredArgs)
                        {
                            AddError("Not enough arguments to function. Expected " + fs.requiredArgs);
                        }

                        for (int j = i; j < smt.Length; j++)
                        {
                            smt[j - i] = smt[j];
                        }

                        Array.Resize(ref smt, smt.Length - i);
                        break;
                    }
                    else
                    {
                        AddError("Unexpected symbol '" + smt[i].token + "' in function arguments");
                    }
                }

                if (argcount == fs.args.Length)
                {
                    AddError("Too many arguments given to function. Expected " + fs.args.Length);
                }

                argcount++;
                lastwasref = false;
                switch (fs.args[argcount - 1])
                {
                    case VarType.Axis:
                        switch (smt[i].token)
                        {
                            case "x":
                                EmitByte((byte)'X');
                                continue;
                            case "y":
                                EmitByte((byte)'Y');
                                continue;
                            case "z":
                                EmitByte((byte)'Z');
                                continue;
                            default:
                                AddError("Expected 'x', 'y' or 'z'");
                                continue;
                        }

                    case VarType.Enum:
                        if (smt[i].type == TokenType.Integer)
                        {
                            Emit(ushort.Parse(smt[i].token));
                        }
                        else
                        {
                            Dictionary<string, ushort> Enum = enumList[fs.reftypes[argcount - 1]];
                            if (!Enum.ContainsKey(smt[i].token))
                            {
                                AddError("'" + smt[i].token + "' is not a valid entry of the enum '" + fs.reftypes[argcount - 1] + "'");
                            }
                            else
                            {
                                Emit(Enum[smt[i].token]);
                            }
                        }

                        continue;
                    case VarType.Short:
                        if (smt[i].type != TokenType.Integer)
                        {
                            AddError("Expected integer argument");
                        }
                        else
                        {
                            Emit(ushort.Parse(smt[i].token));
                        }

                        continue;
                    case VarType.String:
                        Emit((ushort)smt[i].token.Length);
                        bw.Write(System.Text.Encoding.Default.GetBytes(smt[i].token));
                        continue;
                }

                switch (smt[i].type)
                {
                    case TokenType.edid:
                        if (i == smt.Length - 1 || !smt[i + 1].IsSymbol("."))
                        {
                            if (fs.args[argcount - 1] != VarType.Ref)
                            {
                                AddError("Invalid argument " + i + " to function. Expected " + fs.args[argcount - 1].ToString());
                            }

                            if (fs.reftypes[argcount - 1] != null && fs.reftypes[argcount - 1] != edidList[smt[i].token].Value)
                            {
                                AddError("Invalid record type at argument " + i + " of function. Expected " + fs.reftypes[argcount - 1]);
                            }
                        }

                        EmitRefLabel(smt[i], RefType.Expression);
                        lastwasref = true;
                        break;
                    case TokenType.Local:
                        LocalVar vt = locals[smt[i].token];
                        switch (vt.type)
                        {
                            case VarType.Int:
                                if (fs.args[argcount - 1] != VarType.Float && fs.args[argcount - 1] != VarType.Int)
                                {
                                    AddError("Invalid argument " + i + " to function. Expected " + fs.args[argcount - 1].ToString());
                                }

                                EmitByte(0x73);
                                Emit((ushort)locals[smt[i].token].index);
                                break;
                            case VarType.Float:
                                if (fs.args[argcount - 1] != VarType.Float && fs.args[argcount - 1] != VarType.Int)
                                {
                                    AddError("Invalid argument " + i + " to function. Expected " + fs.args[argcount - 1].ToString());
                                }

                                EmitByte(0x66);
                                Emit((ushort)locals[smt[i].token].index);
                                break;
                            case VarType.Ref:
                                if (fs.args[argcount - 1] != VarType.Ref)
                                {
                                    AddError("Invalid argument " + i + " to function. Expected " + fs.args[argcount - 1].ToString());
                                }

                                EmitRefLabel(smt[i], RefType.Expression);
                                break;
                        }

                        break;
                    case TokenType.Global:
                        if (fs.args[argcount - 1] != VarType.Float && fs.args[argcount - 1] != VarType.Int)
                        {
                            AddError("Invalid argument " + i + " to function. Expected " + fs.args[argcount - 1].ToString());
                        }

                        EmitRefLabel(smt[i], RefType.Expression);
                        break;
                    case TokenType.Integer:
                        if (fs.args[argcount - 1] == VarType.Float)
                        {
                            goto case TokenType.Float;
                        }

                        if (fs.args[argcount - 1] != VarType.Int)
                        {
                            AddError("Invalid argument " + i + " to function. Expected " + fs.args[argcount - 1].ToString());
                        }

                        EmitByte(0x6e);
                        bw.Write(int.Parse(smt[i].token));
                        break;
                    case TokenType.Float:
                        if (fs.args[argcount - 1] != VarType.Float && fs.args[argcount - 1] != VarType.Int)
                        {
                            AddError("Invalid argument " + i + " to function. Expected " + fs.args[argcount - 1].ToString());
                        }

                        EmitByte(0x7a);
                        bw.Write(double.Parse(smt[i].token));
                        break;
                    default:
                        AddError("Expected <global>|<local>|<constant>");
                        return;
                }
            }

            for (int j = 0; j < fs.paddingbytes; j++)
            {
                EmitByte(0);
            }

            bw.BaseStream.Position = pos;
            Emit((ushort)(bw.BaseStream.Length - (pos + 2)));
            Emit(argcount);
            bw.BaseStream.Position = bw.BaseStream.Length;
        }
Example #3
0
        private static void EmitBegin(Token[] smt)
        {
            Emit(0x10);
            if (!blockList.ContainsKey(smt[1].token))
            {
                AddError("Unknown block type");
                EmitLong(0);
                EmitLong(0);
                return;
            }

            FunctionSig fs = blockList[smt[1].token];
            long pos = bw.BaseStream.Length;
            Emit(0);
            Emit(fs.opcode);
            EmitLong(0);
            if (smt.Length > fs.args.Length + 2)
            {
                AddError("Too many arguments to 'begin' block");
            }

            // for(int i=0;i<fs.paddingbytes;i++) EmitByte(0);
            if (fs.args.Length > 0)
            {
                Emit((ushort)(smt.Length - 2));
                for (int i = 2; i < smt.Length; i++)
                {
                    switch (fs.args[i - 2])
                    {
                        case VarType.Short:
                            if (smt[i].type != TokenType.Integer)
                            {
                                AddError("Block argument: Expected short");
                            }
                            else
                            {
                                Emit(ushort.Parse(smt[i].token));
                            }

                            break;
                        case VarType.Int:
                            if (smt[i].type != TokenType.Integer)
                            {
                                AddError("Block argument: Expected integer");
                            }
                            else
                            {
                                EmitByte(0x73);
                                EmitLong(uint.Parse(smt[i].token));
                            }

                            break;
                        case VarType.Ref:
                            if (smt[i].type != TokenType.edid)
                            {
                                AddError("Block argument: Expected edid");
                            }
                            else
                            {
                                EmitRefLabel(smt[i], RefType.Expression);
                            }

                            break;
                        default:
                            AddError("Sanity check failed. VarType of block argument was invalid");
                            break;
                    }
                }
            }

            bw.BaseStream.Position = pos;
            Emit((ushort)(bw.BaseStream.Length - (pos + 2)));
            bw.BaseStream.Position = bw.BaseStream.Length;
        }
Example #4
0
        private static void EmitExpression(Token[] smt, ExpressionType type)
        {
            long pos = bw.BaseStream.Length;
            Emit(0);
            try
            {
                EmitExpression2(new Queue<Token>(smt), int.MaxValue, false, type);
            }
            catch (ExpressionParseException ex)
            {
                AddError(ex.Message);
            }

            bw.BaseStream.Position = pos;
            Emit((ushort)(bw.BaseStream.Length - (pos + 2)));
            bw.BaseStream.Position = bw.BaseStream.Length;
        }
Example #5
0
 public LocalVar(int index, Token t)
 {
     this.index = index;
     switch (t.keyword)
     {
         case Keywords.Int:
             this.type = VarType.Int;
             break;
         case Keywords.Float:
             this.type = VarType.Float;
             break;
         case Keywords.Ref:
             this.type = VarType.Ref;
             break;
         default:
             throw new Exception("Should never happen: Invalid type passed to local variable constructor");
     }
 }
Example #6
0
        private static Token[] TrimStatement(Token[] smt, int size)
        {
            var smt2 = new Token[smt.Length - size];
            for (int i = 0; i < smt2.Length; i++)
            {
                smt2[i] = smt[i + size];
            }

            return smt2;
        }
Example #7
0
        private static void HandleStatement(Token[] smt)
        {
            if (smt[0].type == TokenType.Function)
            {
                EmitFunctionCall(ref smt, false, false, false);
            }
            else if (smt[0].IsKeyword(Keywords.ShowMessage))
            {
                EmitShowMessage(smt);
                
            }
            else if (smt[0].IsKeyword(Keywords.Set))
            {
                if (smt.Length < 4 || !(smt[2].IsKeyword(Keywords.To) || smt[2].IsSymbol(".")))
                {
                    AddError("Expected 'set <var> to <expression>'");
                    return;
                }

                Emit(0x15);
                long pos = bw.BaseStream.Length;
                Emit(0);
                if (smt[1].type == TokenType.Local)
                {
                    LocalVar lv = locals[smt[1].token];
                    if (lv.type == VarType.Int)
                    {
                        EmitByte(0x73);
                    }
                    else
                    {
                        EmitByte(0x66);
                    }

                    Emit((ushort)lv.index);
                    EmitExpression(TrimStatement(smt, 3), (lv.type == VarType.Ref) ? ExpressionType.Ref : ExpressionType.Numeric);
                }
                else if (smt[1].type == TokenType.Global)
                {
                    EmitRefLabel(smt[1], RefType.Expression);
                    EmitExpression(TrimStatement(smt, 3), ExpressionType.Numeric);
                }
                else if (smt[1].type == TokenType.edid && farVars.ContainsKey(smt[1].token) && smt[2].IsSymbol("."))
                {
                    if (smt.Length < 6 || !smt[4].IsKeyword(Keywords.To))
                    {
                        AddError("Expected 'set <var> to <expression>'");
                        return;
                    }

                    EmitRefLabel(smt[1], RefType.Expression);
                    EmitByte(0x73);
                    if (!farVars[smt[1].token].ContainsKey(smt[3].token))
                    {
                        AddError("Local variable '" + smt[3].token + " does not exist in quest " + smt[1].token);
                    }
                    else
                    {
                        Emit(farVars[smt[1].token][smt[3].token]);
                    }

                    EmitExpression(TrimStatement(smt, 5), ExpressionType.If);
                }
                else
                {
                    AddError("Expected set <local>|<global> to <expression>");
                }

                bw.BaseStream.Position = pos;
                Emit((ushort)(bw.BaseStream.Length - (pos + 2)));
                bw.BaseStream.Position = bw.BaseStream.Length;
            }
            else if (smt[0].type == TokenType.edid)
            {
                if (smt.Length < 3 || !smt[1].IsSymbol(".") || smt[2].type != TokenType.Function)
                {
                    AddError("Expected ref.function");
                    return;
                }

                EmitRefLabel(smt[0], RefType.Standard);
                smt = TrimStatement(smt, 2);
                EmitFunctionCall(ref smt, false, true, false);
            }
            else if (smt[0].type == TokenType.Local)
            {
                LocalVar lv = locals[smt[0].token];
                if (lv.type != VarType.Ref)
                {
                    AddError("Expected 'Set', <function> or <ref>.<function>");
                    return;
                }

                if (smt.Length < 3 || !smt[1].IsSymbol(".") || smt[2].type != TokenType.Function)
                {
                    AddError("Expected ref.function");
                    return;
                }

                EmitRefLabel(smt[0], RefType.Standard);
                smt = TrimStatement(smt, 2);
                EmitFunctionCall(ref smt, false, true, false);
            }
            else
            {
                AddError("Expected 'Set', <function> or <ref>.<function>");
            }
        }
Example #8
0
        private static void EmitShowMessage(Token[] smt)
        {
            // ShowMessage DoorOpenedScienceMsg passSkill
            // 59 10 0E 00 01 00 72 02 00 01 00 73 01 00 00 00 00 00
            Emit(0x1059);
            if (smt.Length == 1)
            {
                AddError("Not enough arguments to ShowMessage");
                return;
            }

            long pos = bw.BaseStream.Length;
            Emit(0);
            Emit(1);

            switch (smt[1].type)
            {
                case TokenType.edid:
                    if (edidList[smt[1].token].Value != "MESG")
                    {
                        goto default;
                    }
                    else
                    {
                        EmitRefLabel(smt[1], RefType.Expression);
                    }

                    break;
                case TokenType.Local:
                    LocalVar vt = locals[smt[1].token];
                    if (vt.type != VarType.Ref)
                    {
                        goto default;
                    }

                    EmitRefLabel(smt[1], RefType.Expression);
                    break;
                default:
                    AddError("First argument to ShowMessage must be an MESG record");
                    return;
            }

            if (smt.Length == 2)
            {
                Emit(0);
            }
            else
            {
                bool lastwasref = false;
                Emit((ushort)(smt.Length - 2));
                for (int i = 2; i < smt.Length; i++)
                {
                    if (smt[i].type == TokenType.Symbol)
                    {
                        if (smt[i].IsSymbol(".") && lastwasref)
                        {
                            if (i < smt.Length - 1 && farVars.ContainsKey(smt[i - 1].token))
                            {
                                i++;
                                EmitByte(0x73);
                                Dictionary<string, ushort> vars = farVars[smt[i - 2].token];
                                if (!vars.ContainsKey(smt[i].token))
                                {
                                    AddError("Reference '" + smt[i - 2].utoken + "' has no variable called '" + smt[i].utoken + "'");
                                }
                                else
                                {
                                    Emit(vars[smt[i].token]);
                                }

                                continue;
                            }
                        }
                        else if (smt[i].IsSymbol("-"))
                        {
                            if (i < smt.Length - 1 && (smt[i + 1].type == TokenType.Integer || smt[i + 1].type == TokenType.Float))
                            {
                                smt[i + 1] = new Token(smt[i + 1].type, "-" + smt[i + 1].token);
                                continue;
                            }
                        }

                        AddError("Unexpected symbol '" + smt[i].token + "' in ShowMessage arguments");
                    }

                    lastwasref = false;
                    switch (smt[i].type)
                    {
                        case TokenType.edid:
                            EmitRefLabel(smt[i], RefType.Expression);
                            lastwasref = true;
                            break;
                        case TokenType.Local:
                            LocalVar vt = locals[smt[i].token];
                            switch (vt.type)
                            {
                                case VarType.Int:
                                    EmitByte(0x73);
                                    Emit((ushort)locals[smt[i].token].index);
                                    break;
                                case VarType.Float:
                                    EmitByte(0x66);
                                    Emit((ushort)locals[smt[i].token].index);
                                    break;
                                case VarType.Ref:
                                    EmitRefLabel(smt[i], RefType.Expression);
                                    break;
                            }

                            break;
                        case TokenType.Global:
                            EmitRefLabel(smt[i], RefType.Expression);
                            break;
                        case TokenType.Integer:
                            EmitByte(0x6e);
                            bw.Write(int.Parse(smt[i].token));
                            break;
                        case TokenType.Float:
                            EmitByte(0x7a);
                            bw.Write(double.Parse(smt[i].token));
                            break;
                        default:
                            AddError("Expected <global>|<local>|<constant>");
                            return;
                    }
                }
            }

            Emit(0);
            Emit(0);
            bw.BaseStream.Position = pos;
            Emit((ushort)(bw.BaseStream.Length - (pos + 2)));
            bw.BaseStream.Position = bw.BaseStream.Length;
        }
Example #9
0
        private static void EmitRefLabel(Token t, RefType type)
        {
            if (t.type == TokenType.Global)
            {
                EmitByte(0x47);
            }
            else
            {
                switch (type)
                {
                    case RefType.Standard:
                        Emit(0x1c);
                        break;
                    case RefType.Expression:
                        EmitByte(0x72);
                        break;
                    case RefType.Standalone:
                        EmitByte(0x5a);
                        break;
                }
            }

            if (t.type == TokenType.Local)
            {
                LocalVar var = locals[t.token];
                if (var.refid == 0)
                {
                    AddError("Variable was not of type ref");
                }
                else
                {
                    Emit((ushort)var.refid);
                }
            }
            else if (t.type == TokenType.edid || t.type == TokenType.Global)
            {
                if (!edidRefs.ContainsKey(t.token))
                {
                    var sr = new SubRecord();
                    sr.Name = "SCRO";
                    if (t.type == TokenType.edid)
                    {
                        sr.SetData(TypeConverter.i2h(edidList[t.token].Key));
                    }
                    else
                    {
                        sr.SetData(TypeConverter.i2h(globals[t.token]));
                    }

                    r.AddRecord(sr);
                    refcount++;
                    edidRefs[t.token] = (ushort)refcount;
                }

                Emit(edidRefs[t.token]);
            }
            else
            {
                AddError("Expected ref variable or edid");
            }
        }