Пример #1
0
    private static void EmitExpression(Token[] smt, ExpressionType type)
    {
      var 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;
    }
Пример #2
0
 private static void EmitFunctionCall(ref Token[] smt, bool expression, bool hadref)
 {
   var 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 (var j = 1; j < smt.Length; j++)
     {
       smt[j - 1] = smt[j];
     }
     Array.Resize(ref smt, smt.Length - 1);
     return;
   }
   var pos = bw.BaseStream.Length;
   ushort argcount = 0;
   Emit(0);
   Emit(0);
   var i = 0;
   var 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);
           var 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 (var j = i; j < smt.Length; j++)
         {
           smt[j - i] = smt[j];
         }
         Array.Resize(ref smt, smt.Length - i);
         break;
       }
       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
         {
           var 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(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]);
           }
           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:
         var 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]);
             }
             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]);
             }
             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]);
             }
             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]);
         }
         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]);
         }
         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]);
         }
         EmitByte(0x7a);
         bw.Write(double.Parse(smt[i].token));
         break;
       default:
         AddError("Expected <global>|<local>|<constant>");
         return;
     }
   }
   for (var 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;
 }
Пример #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;
   }
   var fs = blockList[smt[1].token];
   var 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 (var 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;
 }
Пример #4
0
 private static void EmitExpressionValue(Token t, Queue<Token> smt, ExpressionType type)
 {
   EmitByte(0x20);
   var 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))
         {
           var 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;
       }
       if (type == ExpressionType.Numeric)
       {
         AddError("Reference type not valid here");
       }
       EmitRefLabel(t, RefType.Standalone);
       break;
     case TokenType.Local:
       var 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");
       }
       EmitByte(lv.type == VarType.Int ? (byte) 0x73 : (byte) 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.ASCII.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 (var i = 1; i < args.Length; i++)
       {
         args[i] = smt.Dequeue();
       }
       EmitFunctionCall(ref args, true, hadRef);
       foreach (var arg in args)
       {
         smt.Enqueue(arg);
       }
       break;
     default:
       AddError("Expected <local>|<global>|<number>|<function>");
       break;
   }
 }
Пример #5
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)
   {
     var 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";
       sr.SetData(t.type == TokenType.edid
         ? TypeConverter.i2h(edidList[t.token].Key)
         : 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");
   }
 }
Пример #6
0
 private static Token[] TrimStatement(Token[] smt, int size)
 {
   var smt2 = new Token[smt.Length - size];
   for (var i = 0; i < smt2.Length; i++)
   {
     smt2[i] = smt[i + size];
   }
   return smt2;
 }
Пример #7
0
 public LocalVar(int index, Token t)
 {
   this.index = index;
   switch (t.keyword)
   {
     case Keywords.Int:
       type = VarType.Int;
       break;
     case Keywords.Float:
       type = VarType.Float;
       break;
     case Keywords.Ref:
       type = VarType.Ref;
       break;
     default:
       throw new Exception("Should never happen: Invalid type passed to local variable constructor");
   }
 }
Пример #8
0
 private static void HandleStatement(Token[] smt)
 {
   if (smt[0].type == TokenType.Function)
   {
     EmitFunctionCall(ref smt, 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);
     var pos = bw.BaseStream.Length;
     Emit(0);
     if (smt[1].type == TokenType.Local)
     {
       var lv = locals[smt[1].token];
       EmitByte(lv.type == VarType.Int ? (byte) 0x73 : (byte) 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);
   }
   else if (smt[0].type == TokenType.Local)
   {
     var 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);
   }
   else
   {
     AddError("Expected 'Set', <function> or <ref>.<function>");
   }
 }
Пример #9
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;
      }
      var pos = bw.BaseStream.Length;
      Emit(0);
      Emit(1);

      switch (smt[1].type)
      {
        case TokenType.edid:
          if (edidList[smt[1].token].Value != "MESG")
          {
            goto default;
          }
          EmitRefLabel(smt[1], RefType.Expression);
          break;
        case TokenType.Local:
          var 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
      {
        var lastwasref = false;
        Emit((ushort) (smt.Length - 2));
        for (var 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);
                var 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:
              var 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;
    }