20 #region Private Classes
26 private class FunctionFrame
30 public int nextInstruction;
35 #region Private Variables
40 private Stack<FunctionFrame> functionStack;
41 private Stack<object> parameterStack;
42 private Dictionary<object, Instruction> locks;
43 private List<Interpreter> jobs;
45 private Memory localMemory;
46 private bool interrupt;
47 private bool interrupted;
48 private bool finished;
52 #region Private Methods
57 private object Evaluate(
Operand operand)
69 return localMemory[(string) operand.
Value];
82 src = localMemory[(string)operand.
Value];
91 if ((
string)operand.
Member ==
"toString")
96 StringBuilder sb =
new StringBuilder();
98 foreach (KeyValuePair<object, object> element
in array)
100 sb.Append(element.Value.ToString());
109 object objectValue = associativeArray[operand.
Member];
114 else if (src.GetType() == typeof(
string))
117 string strSource = (string)src;
119 object objectIndex = operand.
Member;
121 if (objectIndex.GetType() == typeof(
string))
122 if (((
string)objectIndex) ==
"length")
123 return strSource.Length;
125 if (objectIndex.GetType() != typeof(
int))
128 return strSource[(int)objectIndex] +
"";
136 object objectIndex = operand.
Member;
140 System.Reflection.MethodInfo method = ((object)src).GetType().GetMethod((
string)objectIndex);
144 res = method.Invoke(src,
new object[0]);
147 parameterStack.Push(NullReference.Instance);
168 src = localMemory[(string)operand.
Value];
173 object objectIndex = localMemory[operand.
Pointer];
179 else if (src.GetType() == typeof(
string))
182 string strSource = (string)src;
184 object objectIndex = localMemory[operand.
Pointer];
186 if (objectIndex.GetType() != typeof(
int))
189 return strSource[(int)objectIndex] +
"";
197 throw new ExecutionException(
"Der Typ '"+ operand.
Type +
"' kann an dieser Stelle nicht verarbeitet werden.");
208 private void Assignment(
Operand dst,
object val)
211 string identifier = (string)dst.
Value;
217 localMemory[identifier] = val;
226 if (localMemory.Exists(identifier))
227 tmp = localMemory[identifier];
230 tmp = NullReference.Instance;
233 throw new ExecutionException(
"Das Ziel '" + dst +
"' vom Typ '" + tmp.GetType().ToString() +
"' ist nicht indexierbar.");
242 array[localMemory[dst.
Pointer]] = val;
257 private void Arithmetic()
260 String strIdentifierDest = (
String)instruction.First.Value;
261 object objectValueDest = Evaluate(instruction.First);
262 object objectValueSource = Evaluate(instruction.Second);
263 Type typeDest = objectValueDest.GetType();
264 Type typeSource = objectValueSource.GetType();
267 if (instruction.OpCode ==
OpCode.ADD)
269 if (typeDest == typeof(
String))
271 Assignment(instruction.First, objectValueDest.ToString() + objectValueSource.ToString());
277 ((
ArrayList)objectValueDest).Add(objectValueSource);
283 if (instruction.OpCode ==
OpCode.SUB)
285 if (typeDest == typeof(
String))
287 Assignment(instruction.First,
288 objectValueDest.ToString().Replace(objectValueSource.ToString(),
""));
293 ((
ArrayList)objectValueDest).Subtract(objectValueSource);
298 float fValueDest = 0.0f;
299 float fValueSource = 0.0f;
300 float fResult = 0.0f;
302 if (typeDest == typeof(
int))
303 fValueDest = (float)(
int)objectValueDest;
304 else if (typeDest == typeof(
float))
305 fValueDest = (float)objectValueDest;
307 throw new ScriptStackException(
"Values of type '" + typeDest.Name +
"' cannot be used in arithmetic instructions.");
309 if (typeSource == typeof(
int))
310 fValueSource = (float)(
int)objectValueSource;
311 else if (typeSource == typeof(
float))
312 fValueSource = (float)objectValueSource;
314 throw new ScriptStackException(
"Values of type '" + typeSource.Name +
"' cannot be used in arithmetic instructions.");
316 switch (instruction.OpCode)
318 case OpCode.ADD: fResult = fValueDest + fValueSource;
break;
319 case OpCode.SUB: fResult = fValueDest - fValueSource;
break;
320 case OpCode.MUL: fResult = fValueDest * fValueSource;
break;
321 case OpCode.DIV: fResult = fValueDest / fValueSource;
break;
322 case OpCode.MOD: fResult = fValueDest % fValueSource;
break;
324 throw new ExecutionException(
"Invalid arithmetic instruction '" + instruction.OpCode +
"'.");
327 if (typeDest == typeof(
int) && typeSource == typeof(
int))
328 Assignment(instruction.First, (
int)fResult);
330 Assignment(instruction.First, fResult);
344 private void Relation()
347 string identifier = (string)instruction.First.Value;
349 object dst = Evaluate(instruction.First);
351 object src = Evaluate(instruction.Second);
353 Type typeDest = dst.GetType();
355 Type typeSource = src.GetType();
363 if (typeDest == typeof(NullReference) || typeSource == typeof(NullReference))
366 switch (instruction.OpCode)
380 if (typeDest == typeof(NullReference) && typeSource == typeof(NullReference))
381 message =
"Die Operation '" + instruction.OpCode +
"' kann nicht auf den Typ 'null' angewendet werden.";
383 else if (typeDest == typeof(NullReference))
384 message =
"Die Operation '" + instruction.OpCode +
"' kann nicht auf den Typ 'null' als Ziel (links des Operators) angewendet werden.";
387 message =
"Die Operation '" + instruction.OpCode +
"' kann nicht auf den Typ 'null' als Quelle (rechts des Operators) angewendet werden.";
395 Assignment(instruction.First, result);
405 if (typeDest == typeof(
string) || typeSource == typeof(
string))
408 string strDst =
"" + dst;
410 string strSrc =
"" + src;
412 switch (instruction.OpCode)
416 result = strDst == strSrc;
420 result = strDst != strSrc;
424 result = strDst.CompareTo(strSrc) > 0;
428 result = strDst.CompareTo(strSrc) >= 0;
432 result = strDst.CompareTo(strSrc) < 0;
436 result = strDst.CompareTo(strSrc) <= 0;
440 throw new ExecutionException(
"Die Operation '" + instruction.OpCode +
"' kann nicht auf den Typ 'String' angewendet werden.");
444 Assignment(instruction.First, result);
454 if (typeDest == typeof(
int))
455 dstVal =
double.Parse(
"" + (
int)dst);
457 else if (typeDest == typeof(
float))
458 dstVal =
double.Parse(
"" + (
float)dst);
460 else if (typeDest == typeof(
char))
461 dstVal =
double.Parse(
"" + (
char)dst);
463 else if (typeDest == typeof(
double))
464 dstVal = (double)dst;
467 throw new ExecutionException(
"Der Typ '" + typeDest.Name +
"' kann in relationalen Operationen als Ziel (links des Operators) nicht verarbeitet werden.");
469 if (typeSource == typeof(
int))
470 srcVal =
double.Parse(
"" + (
int)src);
472 else if (typeSource == typeof(
float))
473 srcVal =
double.Parse(
"" + (
float)src);
475 else if (typeSource == typeof(
char))
476 srcVal =
double.Parse(
"" + (
char)src);
478 else if (typeSource == typeof(
double))
479 srcVal = (double)src;
482 throw new ExecutionException(
"Der Typ '" + typeSource.Name +
"' kann in relationalen Operationen als Quelle (rechts des Operators) nicht verarbeitet werden.");
484 switch (instruction.OpCode)
488 result = dstVal == srcVal;
492 result = dstVal != srcVal;
496 result = dstVal > srcVal;
500 result = dstVal >= srcVal;
504 result = dstVal < srcVal;
508 result = dstVal <= srcVal;
512 throw new ExecutionException(
"Der OpCode '" + instruction.OpCode +
"' kann in einer relationalen Operation nicht verarbeitet werden.");
516 Assignment(instruction.First, result);
528 string identifier = (string)instruction.First.Value;
530 object dst = Evaluate(instruction.First);
532 object src = Evaluate(instruction.Second);
534 Type typeDest = dst.GetType();
536 Type typeSource = src.GetType();
544 if (typeSource == typeof(
bool))
547 else if (typeSource == typeof(NullReference))
551 srcVal = ((double)src != 0.0) ? true :
false;
554 if (typeDest == typeof(
bool))
557 else if (typeDest == typeof(NullReference))
561 dstVal = ((double)dst != 0.0) ? true :
false;
563 switch (instruction.OpCode)
567 result = dstVal && srcVal;
571 result = dstVal || srcVal;
575 throw new ExecutionException(
"Der OpCode '" + instruction.OpCode +
"' kann in einer logischen Operation nicht verarbeitet werden.");
579 Assignment(instruction.First, result);
586 if (array.Count == 0)
589 object iterator = Evaluate(instruction.First);
595 foreach (
object tmp
in array.Keys)
612 Dictionary<object, object>.KeyCollection.Enumerator keys = array.Keys.GetEnumerator();
621 next = NullReference.Instance;
623 localMemory[instruction.First.Value.ToString()] = next;
627 private void Iterator(
string str)
633 object iterator = Evaluate(instruction.First);
635 if (iterator.GetType() != typeof(
int))
638 localMemory[instruction.First.Value.ToString()] = 0;
644 int elements = (int)iterator;
646 if (elements < str.Length - 1)
647 localMemory[instruction.First.Value.ToString()] = elements + 1;
650 localMemory[instruction.First.Value.ToString()] = NullReference.Instance;
677 if (functionStack.Count == 0)
683 localMemory = functionStack.Peek().localMemory;
691 parameterStack.Push(Evaluate(instruction.First));
700 object tmp = parameterStack.Pop();
702 Operand operand = instruction.First;
704 switch (operand.
Type)
708 localMemory[operand.
Value.ToString()] = tmp;
713 if (localMemory[operand.
Value.ToString()].GetType() != typeof(
ArrayList))
719 array[operand.
Member] = tmp;
722 array[localMemory[operand.
Pointer]] = tmp;
727 throw new ExecutionException(
"Der Typ '" + operand.
Type +
"' kann an dieser Stelle nicht verarbeitet werden.");
739 Assignment(instruction.First, Evaluate(instruction.Second));
791 string identifier = (string)instruction.First.Value;
793 object val = Evaluate(instruction.First);
795 Type typeDest = val.GetType();
797 if (typeDest == typeof(
int))
798 localMemory[identifier] = (int)val + 1;
800 else if (typeDest == typeof(
float))
801 localMemory[identifier] = (float)val + 1;
803 else if (typeDest == typeof(
double))
804 localMemory[identifier] = (double)val + 1;
806 else if (typeDest == typeof(
char))
807 localMemory[identifier] = (char)val + 1;
810 throw new ExecutionException(
"Der Typ '" + typeDest.Name +
"' kann nicht inkrementiert werden.");
820 string identifier = (string)instruction.First.Value;
822 object val = Evaluate(instruction.First);
824 Type typeDest = val.GetType();
826 if (typeDest == typeof(
int))
827 localMemory[identifier] = (int)val - 1;
829 else if (typeDest == typeof(
float))
830 localMemory[identifier] = (float)val - 1;
832 else if (typeDest == typeof(
double))
833 localMemory[identifier] = (double)val - 1;
835 else if (typeDest == typeof(
char))
836 localMemory[identifier] = (char)val - 1;
839 throw new ExecutionException(
"Der Typ '" + typeDest.Name +
"' kann nicht dekrementiert werden.");
849 string identifier = (string)instruction.First.Value;
851 object val = Evaluate(instruction.First);
853 Type typeDest = val.GetType();
855 if (typeDest == typeof(
int))
856 localMemory[identifier] = (int)val * -1;
858 else if (typeDest == typeof(
float))
859 localMemory[identifier] = (float)val * -1;
861 else if (typeDest == typeof(
double))
862 localMemory[identifier] = (double)val * -1;
864 else if (typeDest == typeof(
char))
865 localMemory[identifier] = (char)val * -1;
868 throw new ExecutionException(
"Der Typ '" + typeDest.Name +
"' kann nicht negiert werden.");
878 string identifier =
null;
880 object val = Evaluate(instruction.Second);
882 Operand operand = instruction.First;
884 switch (operand.
Type)
888 int res = (int)localMemory[(
string)operand.
Value] << (int)val;
890 identifier = operand.
Value.ToString();
892 localMemory[identifier] = res;
897 throw new ExecutionException(
"Der Typ '" + operand.
Type +
"' kann in Bitoperationen nicht verarbeitet werden.");
909 string identifier =
null;
911 object val = Evaluate(instruction.Second);
913 Operand operand = instruction.First;
915 switch (operand.
Type)
919 int res = (int)localMemory[(
string)operand.
Value] >> (int)val;
921 identifier = operand.
Value.ToString();
923 localMemory[identifier] = res;
928 throw new ExecutionException(
"Der Typ '" + operand.
Type +
"' kann in Bitoperationen nicht verarbeitet werden.");
939 string identifier = (string)instruction.First.
Value;
941 object val = Evaluate(instruction.First);
943 localMemory[identifier] = val == NullReference.Instance;
1015 string identifier = (string)instruction.First.Value;
1017 object val = Evaluate(instruction.First);
1019 Type typeDest = val.GetType();
1021 if (typeDest != typeof(
bool) && typeDest != typeof(
int))
1022 throw new ExecutionException(
"Der Typ '" + typeDest.Name +
"' kann nicht negiert werden.");
1024 if (typeDest == typeof(
bool))
1025 localMemory[identifier] = !((bool)val);
1027 else if (typeDest == typeof(
int))
1028 localMemory[identifier] = (int)val * -1;
1037 string identifier =
null;
1039 object val = Evaluate(instruction.Second);
1041 Operand operand = instruction.First;
1043 switch (operand.
Type)
1047 int res = (int)val | (
int)localMemory[(string)operand.
Value];
1049 identifier = operand.
Value.ToString();
1051 localMemory[identifier] = res;
1056 throw new ExecutionException(
"Der Typ '" + operand.
Type +
"' kann an dieser Stelle nicht verarbeitet werden.");
1065 string identifier =
null;
1067 object val = Evaluate(instruction.Second);
1069 Operand operand = instruction.First;
1071 switch (operand.
Type)
1075 int res = (int)localMemory[(
string)operand.
Value] & (int)val;
1077 identifier = operand.
Value.ToString();
1079 localMemory[identifier] = res;
1084 throw new ExecutionException(
"Operand type '" + operand.
Type +
"' not supported by logical AND instruction.");
1093 string identifier =
null;
1095 object val = Evaluate(instruction.Second);
1097 Operand operand = instruction.First;
1099 switch (operand.
Type)
1103 var res = ~(int)val;
1105 identifier = operand.
Value.ToString();
1107 localMemory[identifier] = res;
1112 throw new ExecutionException(
"Der Typ '" + operand.
Type +
"' kann an dieser Stelle nicht verarbeitet werden.");
1121 string identifier =
null;
1123 object val = Evaluate(instruction.Second);
1125 Operand operand = instruction.First;
1127 switch (operand.
Type)
1131 int res = (int)val ^ (
int)localMemory[(string)operand.
Value];
1133 identifier = operand.
Value.ToString();
1135 localMemory[identifier] = res;
1140 throw new ExecutionException(
"Der Typ '" + operand.
Type +
"' kann an dieser Stelle nicht verarbeitet werden.");
1152 FunctionFrame frame = functionStack.Peek();
1164 if (!(
bool)Evaluate(instruction.First))
1169 FunctionFrame frame = functionStack.Peek();
1171 frame.nextInstruction = (int)target.
Address;
1181 if ((
bool)Evaluate(instruction.First))
1184 FunctionFrame frame = functionStack.Peek();
1186 frame.nextInstruction = (int)instruction.Second.InstructionPointer.Address;
1195 throw new ExecutionException(
"DCG opcodes cannot be executed within a function frame.");
1202 localMemory[(string)instruction.First.Value] = NullReference.Instance;
1209 if (instruction.First.Type !=
OperandType.Variable)
1214 localMemory[instruction.First.Value.ToString()] = array;
1221 string strIdentifier =
null;
1223 object objectValue = Evaluate(instruction.Second);
1225 Operand operand = instruction.First;
1227 switch (operand.
Type)
1231 int res = (int)objectValue ^ (
int)localMemory[(string)operand.
Value];
1233 strIdentifier = operand.
Value.ToString();
1235 localMemory[strIdentifier] = res;
1240 throw new ExecutionException(
"Operand type '" + operand.
Type +
"' not supported by logical LNEG instruction.");
1253 if (instruction.First.Type !=
OperandType.Variable)
1256 if (instruction.Second.Type !=
OperandType.Variable)
1259 object enumerable = localMemory[instruction.Second.Value.ToString()];
1261 if (enumerable.GetType() == typeof(
ArrayList))
1264 else if (enumerable.GetType() == typeof(
string))
1265 Iterator((
string)enumerable);
1280 Function function = instruction.First.FunctionPointer;
1282 FunctionFrame frame =
new FunctionFrame();
1284 frame.function =
function;
1288 frame.nextInstruction = (int)
function.EntryPoint.Address;
1290 functionStack.Push(frame);
1303 Routine routine = instruction.First.RoutinePointer;
1305 Host stackHandler =
null;
1310 stackHandler = host;
1314 stackHandler = routine.
Handler;
1316 List<object> parameters =
new List<object>();
1319 parameters.Insert(0, parameterStack.Pop());
1321 routine.
Verify(parameters);
1323 object objectResult =
null;
1325 if (stackHandler !=
null)
1329 objectResult = stackHandler.
Invoke(routine.
Name, parameters);
1333 parameterStack.Push(NullReference.Instance);
1338 routine.
Verify(objectResult);
1342 if (objectResult ==
null)
1343 objectResult = NullReference.Instance;
1345 parameterStack.Push(objectResult);
1431 Function function = instruction.First.FunctionPointer;
1433 List<object> parameters =
new List<object>();
1435 for (
int i = 0; i <
function.ParameterCount; i++)
1436 parameters.Insert(0, parameterStack.Pop());
1449 object first = Evaluate(instruction.First);
1451 if (first.GetType() == typeof(NullReference))
1454 if (script.Manager.Locks.ContainsKey(first))
1459 if (locked ==
this && locks[first] != instruction)
1462 FunctionFrame functionFrame = functionStack.Peek();
1463 --functionFrame.nextInstruction;
1471 script.Manager.Locks[first] =
this;
1473 locks[first] = instruction;
1482 object first = Evaluate(instruction.First);
1484 if (first.GetType() == typeof(NullReference))
1487 if (!script.Manager.Locks.ContainsKey(first))
1490 locks.Remove(first);
1492 script.Manager.Locks.Remove(first);
1497 private uint ExecuteBackgroundJobs()
1506 for (
int i = jobs.Count - 1; i >= 0; i--)
1514 private void ExecuteInstruction()
1517 instruction = executable.InstructionsInternal[functionStack.Peek().nextInstruction++];
1519 switch (instruction.OpCode)
1522 case OpCode.DBG: DBG();
break;
1523 case OpCode.NOP: NOP();
break;
1525 case OpCode.INT: INT();
break;
1526 case OpCode.RET: RET();
break;
1528 case OpCode.PUSH: PUSH();
break;
1529 case OpCode.POP: POP();
break;
1530 case OpCode.MOV: MOV();
break;
1532 case OpCode.ADD: Arithmetic();
break;
1533 case OpCode.SUB: Arithmetic();
break;
1534 case OpCode.MUL: Arithmetic();
break;
1535 case OpCode.DIV: Arithmetic();
break;
1536 case OpCode.MOD: Arithmetic();
break;
1538 case OpCode.INC: INC();
break;
1539 case OpCode.DEC: DEC();
break;
1540 case OpCode.NEG: NEG();
break;
1541 case OpCode.SHL: SHL();
break;
1542 case OpCode.SHR: SHR();
break;
1544 case OpCode.TEST: TEST();
break;
1545 case OpCode.CEQ: CEQ();
break;
1546 case OpCode.CNE: CNE();
break;
1547 case OpCode.CG: CG();
break;
1548 case OpCode.CGE: CGE();
break;
1549 case OpCode.CL: CL();
break;
1550 case OpCode.CLE: CLE();
break;
1552 case OpCode.OR: OR();
break;
1553 case OpCode.AND: AND();
break;
1554 case OpCode.NOT: NOT();
break;
1556 case OpCode.ORB: ORB();
break;
1557 case OpCode.ANDB: ANDB();
break;
1558 case OpCode.NOTB: NOTB();
break;
1559 case OpCode.XOR: XOR();
break;
1561 case OpCode.JMP: JMP();
break;
1562 case OpCode.JZ: JZ();
break;
1563 case OpCode.JNZ: JNZ();
break;
1565 case OpCode.DSB: DSB();
break;
1566 case OpCode.DB: DB();
break;
1567 case OpCode.DC: DC();
break;
1568 case OpCode.DCO: DCO();
break;
1569 case OpCode.PTR: PTR();
break;
1571 case OpCode.CALL: CALL();
break;
1572 case OpCode.INV: INV();
break;
1573 case OpCode.RUN: RUN();
break;
1575 case OpCode.LOCK: LOCK();
break;
1576 case OpCode.FREE: FREE();
break;
1584 #region Public Methods
1589 if (
function.ParameterCount != parameters.Count)
1590 throw new ExecutionException(
"Die Funktion '" +
function.Name +
"' wurde mit " + parameters.Count +
" statt erwartet " +
function.ParameterCount +
" Parametern aufgerufen.");
1592 this.function =
function;
1594 script =
function.Executable.Script;
1596 executable = script.Executable;
1598 functionStack =
new Stack<FunctionFrame>();
1600 parameterStack =
new Stack<object>();
1602 locks =
new Dictionary<object, Instruction>();
1604 jobs =
new List<Interpreter>();
1612 foreach (
object parameter
in parameters)
1615 if (parameter ==
null)
1616 parameterStack.Push(NullReference.Instance);
1621 Type parameterType = parameter.GetType();
1623 if (parameterType == typeof(NullReference))
1624 parameterStack.Push(NullReference.Instance);
1626 else if (parameterType == typeof(
int)
1627 || parameterType == typeof(
float)
1628 || parameterType == typeof(
double)
1629 || parameterType == typeof(
bool)
1630 || parameterType == typeof(
string)
1631 || parameterType == typeof(
char)
1633 parameterStack.Push(parameter);
1636 throw new ExecutionException(
"Der Typ '" + parameterType.Name +
"' ist kein generischer Typ.");
1645 this(function, new List<object>())
1650 this(script.
Executable.MainFunction, parameters)
1655 this(script.
Executable.MainFunction, new List<object>())
1662 functionStack.Clear();
1664 FunctionFrame functionFrame =
new FunctionFrame();
1666 functionFrame.function =
function;
1670 functionFrame.nextInstruction = (int)
function.EntryPoint.Address;
1672 functionStack.Push(functionFrame);
1674 parameterStack.Clear();
1678 localMemory = functionFrame.localMemory;
1680 foreach (
object currentLock
in locks.Keys)
1681 script.Manager.Locks.
Remove(currentLock);
1687 interrupted =
false;
1694 localMemory.ExposeTemporaryVariables();
1696 interrupted =
false;
1700 while (!
Finished && !interrupted && executed < instructions)
1703 ExecuteInstruction();
1707 executed += ExecuteBackgroundJobs();
1711 localMemory.HideTemporaryVariables();
1720 DateTime end = DateTime.Now + interval;
1722 localMemory.ExposeTemporaryVariables();
1724 interrupted =
false;
1731 ExecuteInstruction();
1735 executed += ExecuteBackgroundJobs();
1737 if (DateTime.Now >= end)
1742 localMemory.HideTemporaryVariables();
1751 localMemory.ExposeTemporaryVariables();
1753 interrupted =
false;
1760 ExecuteInstruction();
1764 executed += ExecuteBackgroundJobs();
1768 localMemory.HideTemporaryVariables();
1776 #region Public Properties
1780 get {
return script; }
1785 get {
return interrupt; }
1786 set { interrupt = value; }
1789 public ReadOnlyCollection<Interpreter>
Jobs
1791 get {
return jobs.AsReadOnly(); }
1796 get {
return interrupted; }
1801 get {
return finished; }
1808 if (functionStack.Count == 0)
return -1;
1809 return functionStack.Peek().nextInstruction;
1817 List<Function> listFunctions =
new List<Function>();
1818 foreach (FunctionFrame functionFrame
in functionStack)
1819 listFunctions.Add(functionFrame.function);
1820 return new List<Function>(listFunctions).AsReadOnly();
1826 get {
return new List<object>(parameterStack).AsReadOnly(); }
1831 get {
return localMemory; }
1836 get {
return host; }
1837 set { host = value; }