24 #region Private Structs
26 private struct Variable
31 public Type derivatedType;
33 public Variable(
string name,
Scope scope, Type derivatedType)
40 this.derivatedType = derivatedType;
46 private struct FunctionDescriptor
49 public uint parameterCount;
53 private struct LoopControl
61 #region Private Variables
64 private bool debugMode;
65 private List<Token> tokenStream;
66 private int nextToken;
67 private Dictionary<string, bool> variables;
68 private Dictionary<string, bool> localVariables;
69 private int functionFrameIndex;
70 private Dictionary<Instruction, FunctionDescriptor> forwardDeclarations;
71 private Stack<LoopControl> loopControl;
72 private Derivation derivation;
77 #region Private Methods
85 return nextToken < tokenStream.Count;
92 private Token ReadToken()
98 return tokenStream[nextToken++];
106 private Token LookAhead()
112 return tokenStream[nextToken];
121 private Token LookAhead(
int i)
124 if (!More() ||
null == tokenStream[nextToken + i] )
127 return tokenStream[nextToken + i];
134 private void UndoToken()
138 throw new ParserException(
"Es sind keine vorangehenden Token mehr vorhanden.");
149 private bool AssignmentOperator(
TokenType tokenType)
196 throw new ParserException(
"Der Token '" + tokenType +
"' ist kein Zuweisungsoperator.");
207 private bool RelationalOperator(
TokenType tokenType)
246 throw new ParserException(
"Der Token '" + tokenType +
"' ist kein relationaler Operator.");
258 private Type Literal(
TokenType tokenType)
267 return typeof(
float);
271 return typeof(
string);
275 throw new ParserException(
"Der Token '" + tokenType.ToString() +
"' kann keinem Literal zugeordnet werden.");
288 private Type Derivate(
Token token, Type first, Type second)
291 return derivation.Derivate(token, first, second);
299 private void AllocateVariable(
string identifier)
302 if (variables.ContainsKey(identifier))
303 throw new ParserException(
"Die Variable '" + identifier +
"' ist in einem umschliessenden Bereich bereits deklariert.");
305 if (localVariables.ContainsKey(identifier))
306 throw new ParserException(
"Die Variable '" + identifier +
"' ist in diesem Bereich bereits deklariert.");
308 localVariables[identifier] =
true;
317 private void AllocateFunctionFrame()
320 functionFrameIndex++;
329 private string AllocateTemporaryVariable()
337 string identifier =
"[" + functionFrameIndex +
":" + index +
"]";
339 if (!localVariables.ContainsKey(identifier) && !variables.ContainsKey(identifier))
342 localVariables[identifier] =
true;
357 private void FreeFunctionFrame()
360 if (functionFrameIndex == 0)
363 List<string> candidates =
new List<string>();
365 foreach (
string identifier
in localVariables.Keys)
366 if (identifier.StartsWith(
"[" + functionFrameIndex +
":"))
367 candidates.Add(identifier);
369 foreach (
string identifier
in candidates)
370 localVariables.Remove(identifier);
372 --functionFrameIndex;
379 private void ReadSemicolon()
382 Token token = ReadToken();
392 private void ReadComma()
395 Token token = ReadToken();
405 private void ReadLeftParenthesis()
408 Token token = ReadToken();
418 private void ReadRightParenthesis()
421 Token token = ReadToken();
431 private void ReadLeftBrace()
434 Token token = ReadToken();
437 throw new ParserException(
"Geschwungene Klammer '{' erwartet.", token);
444 private void ReadRightBrace()
447 Token token = ReadToken();
450 throw new ParserException(
"Geschwungene Klammer '}' erwartet.", token);
457 private void ReadLeftBracket()
460 Token token = ReadToken();
470 private void ReadRightBracket()
473 Token token = ReadToken();
483 private void ReadPeriod()
486 Token token = ReadToken();
493 private void InsertDebugInfo(
Token token)
499 string text = token.
Text;
511 private string ReadIdentifier()
514 Token token = ReadToken();
517 throw new ParserException(
"Ein Keyword oder eine Variable wurde erwartet.", token);
519 return token.
Lexeme.ToString();
527 private string ExpectIdentifier()
530 Token token = ReadToken();
533 throw new ParserException(
"Ein Keyword oder eine Variable wurde erwartet.", token);
535 string identifier = token.
Lexeme.ToString();
537 if (!variables.ContainsKey(identifier) && !localVariables.ContainsKey(identifier))
538 throw new ParserException(
"Ein nicht vorhandener Identifier '" + identifier +
"' wurde referenziert.", token);
547 private void VariableDeclaration()
550 Token token = ReadToken();
553 throw new ParserException(
"Variablen werden mit 'shared' oder 'var' deklariert.", token);
555 InsertDebugInfo(token);
562 string identifier = ReadIdentifier();
567 if (variables.ContainsKey(identifier))
568 throw new ParserException(
"Die Variable '" + identifier +
"' ist bereits vorhanden.", token);
570 variables[identifier] =
true;
575 script.Manager.SharedMemory[identifier] = NullReference.Instance;
578 executable.ScriptMemory[identifier] = NullReference.Instance;
588 identifier = ReadIdentifier();
599 private Variable StructDeclaration()
602 AllocateFunctionFrame();
604 Token token = ReadToken();
607 throw new ParserException(
"Strukturen werden mit 'struct' deklariert.", token);
609 InsertDebugInfo(token);
611 string identifier = ReadIdentifier();
615 string alloc = AllocateTemporaryVariable();
619 variables[identifier] =
true;
630 Token tok = ReadToken();
640 if (LookAhead().Type ==
TokenType.RightBrace)
649 else if (LookAhead().Type ==
TokenType.Colon)
654 Token tmpToken = ReadToken();
671 if (LookAhead().Type ==
TokenType.RightBrace)
682 executable.ScriptMemory[identifier] = array;
696 private Variable EnumDeclaration()
699 AllocateFunctionFrame();
701 Token token = ReadToken();
704 throw new ParserException(
"Enumerationen werden mit 'enum' deklariert.", token);
706 InsertDebugInfo(token);
708 string identifier = ReadIdentifier();
712 string alloc = AllocateTemporaryVariable();
716 variables[identifier] =
true;
727 Token tok = ReadToken();
737 if (LookAhead().Type ==
TokenType.RightBrace)
754 if (LookAhead().Type ==
TokenType.RightBrace)
765 executable.ScriptMemory[identifier] = array;
776 private void LocalVariableDeclaration()
779 Token token = ReadToken();
782 throw new ParserException(
"Lokale Variablen werden mit 'var' deklariert.", token);
784 string identifier = ReadIdentifier();
789 AllocateVariable(identifier);
815 identifier = ReadIdentifier();
827 Token token = ReadToken();
843 private Variable RoutineCall()
846 string identifier = ReadIdentifier();
848 ReadLeftParenthesis();
850 List<object> parameters =
new List<object>();
852 int parameterCount = 0;
854 if (LookAhead().Type !=
TokenType.RightParen)
860 Variable parameter = Expression();
866 if (LookAhead().Type ==
TokenType.RightParen)
876 ReadRightParenthesis();
880 if (!manager.
Routines.ContainsKey(identifier))
881 throw new ParserException(
"Die Routine '" + identifier +
"' ist nicht vorhanden.");
886 throw new ParserException(
"Der Aufruf der Routine '" + identifier +
"' hat fehlende Parameter. Erwartet werden " + routine.
ParameterTypes.Count +
" Parameter.\nBeschreibung der Routine: " + routine.
Description().ToString());
889 throw new ParserException(
"Der Aufruf der Routine '" + identifier +
"' hat zu viele Parameter. Erwartet werden " + routine.
ParameterTypes.Count +
" Parameter.\nBeschreibung der Routine: " + routine.
Description().ToString());
893 Variable variable =
new Variable
895 name = AllocateTemporaryVariable(),
919 private Variable Pointer()
922 string identifier = ReadIdentifier();
926 while (LookAhead().Type ==
TokenType.LeftBracket)
931 Variable index = Expression();
935 tmp = AllocateTemporaryVariable();
951 private Variable Member()
954 string arrayIdentifier = ReadIdentifier();
958 while (LookAhead().Type ==
TokenType.Period)
963 string member = ReadIdentifier();
965 tmp = AllocateTemporaryVariable();
969 arrayIdentifier = tmp;
981 private Variable PreIncrement()
984 Token token = ReadToken();
989 string identifier = ExpectIdentifier();
1001 private Variable PreDecrement()
1004 Token token = ReadToken();
1009 string identifier = ExpectIdentifier();
1021 private Variable PostIncrement()
1024 string identifier = ExpectIdentifier();
1026 Token token = ReadToken();
1031 string tmp = AllocateTemporaryVariable();
1045 private Variable PostDecrement()
1048 string identifier = ExpectIdentifier();
1050 Token token = ReadToken();
1055 string tmp = AllocateTemporaryVariable();
1069 private Variable ShiftLeft()
1072 string left = ExpectIdentifier();
1074 Token token = ReadToken();
1079 Variable right = Factor();
1091 private Variable ShiftRight()
1094 string left = ExpectIdentifier();
1096 Token token = ReadToken();
1101 Variable right = Factor();
1113 private Variable BinaryAnd()
1116 string left = ExpectIdentifier();
1118 Token token = ReadToken();
1123 Variable right = Factor();
1135 private Variable BinaryOr()
1138 string left = ExpectIdentifier();
1140 Token token = ReadToken();
1145 Variable right = Factor();
1157 private Variable BinaryNotAssign()
1160 string left = ExpectIdentifier();
1162 Token token = ReadToken();
1167 Variable right = Factor();
1179 private Variable BinaryNot()
1182 Token token = ReadToken();
1187 Variable right = Factor();
1199 private Variable Xor()
1202 string left = ExpectIdentifier();
1204 Token token = ReadToken();
1209 Variable right = Factor();
1219 var literal =
new StringBuilder(input.Length + 2);
1220 literal.Append(
"\"");
1221 foreach (var c
in input)
1225 case '\'': literal.Append(
@"\'");
break;
1226 case '\"': literal.Append(
"\\\"");
break;
1227 case '\\': literal.Append(
@"\\");
break;
1228 case '\0': literal.Append(
@"\0");
break;
1229 case '\a': literal.Append(
@"\a");
break;
1230 case '\b': literal.Append(
@"\b");
break;
1231 case '\f': literal.Append(
@"\f");
break;
1232 case '\n': literal.Append(
@"\n");
break;
1233 case '\r': literal.Append(
@"\r");
break;
1234 case '\t': literal.Append(
@"\t");
break;
1235 case '\v': literal.Append(
@"\v");
break;
1237 if (
char.GetUnicodeCategory(c) != System.Globalization.UnicodeCategory.Control)
1243 literal.Append(
@"\u");
1244 literal.Append(((ushort)c).ToString(
"x4"));
1249 literal.Append(
"\"");
1250 return literal.ToString();
1260 Token token = ReadToken();
1271 string tmpIdentifier = AllocateTemporaryVariable();
1277 variable.name = tmpIdentifier;
1283 variable.name = AllocateTemporaryVariable();
1285 variable.scope =
Scope.Local;
1287 variable.derivatedType = typeof(NullReference);
1299 variable.name = AllocateTemporaryVariable();
1301 variable.scope =
Scope.Local;
1303 variable.derivatedType = Literal(token.
Type);
1313 variable = PreIncrement();
1321 variable = PreDecrement();
1327 string identifier = token.
Lexeme.ToString();
1329 switch (LookAhead().Type)
1336 return PostIncrement();
1342 return PostDecrement();
1360 return FunctionCall();
1372 return ShiftRight();
1378 identifier = ExpectIdentifier();
1380 variable.name = AllocateTemporaryVariable();
1382 variable.scope =
Scope.Local;
1384 variable.derivatedType =
null;
1394 variable = Expression();
1396 ReadRightParenthesis();
1402 throw new ParserException(
"Fehlerhafter Token '" + token +
"'.", token);
1412 private Variable BraceArray()
1419 string identifier = AllocateTemporaryVariable();
1421 string indexIdentifier = AllocateTemporaryVariable();
1423 executable.InstructionsInternal.Add(
new Instruction(
OpCode.DC, Operand.Variable(identifier)));
1425 if (LookAhead().Type !=
TokenType.RightBrace)
1431 Variable tmp = Expression();
1433 Token token = LookAhead();
1438 executable.InstructionsInternal.Add(
new Instruction(
OpCode.MOV, Operand.MemberVariable(identifier, index++), Operand.Variable(tmp.name)));
1457 Variable variableKey = tmp;
1461 executable.InstructionsInternal.Add(
new Instruction(
OpCode.MOV, Operand.CreatePointer(identifier, variableKey.name), Operand.Variable(tmp.name)));
1463 if (LookAhead().Type ==
TokenType.RightBrace)
1467 if (LookAhead().Type ==
TokenType.Comma)
1470 if (LookAhead().Type ==
TokenType.SemiColon)
1476 throw new ParserException(
"Ein Comma ',', Semicolon ';' oder Colon ':' wurde erwartet.");
1484 return new Variable(identifier,
Scope.Local, typeof(ArrayList));
1492 private Variable BracketArray()
1499 string identifier = AllocateTemporaryVariable();
1501 string indexIdentifier = AllocateTemporaryVariable();
1503 executable.InstructionsInternal.Add(
new Instruction(
OpCode.DC, Operand.Variable(identifier)));
1505 if (LookAhead().Type !=
TokenType.RightBracket)
1511 Variable tmp = Expression();
1513 Token token = LookAhead();
1518 executable.InstructionsInternal.Add(
new Instruction(
OpCode.MOV, Operand.MemberVariable(identifier, index++), Operand.Variable(tmp.name)));
1520 if (token.Type ==
TokenType.RightBracket)
1536 executable.InstructionsInternal.Add(
new Instruction(
OpCode.MOV, Operand.CreatePointer(identifier, key.name), Operand.Variable(tmp.name)));
1538 if(LookAhead().Type ==
TokenType.RightBracket)
1546 throw new ParserException(
"Ein Comma ',' oder Colon ':' wurde erwartet.");
1554 return new Variable(identifier,
Scope.Local, typeof(ArrayList));
1562 private Variable Factor()
1565 if (LookAhead().Type ==
TokenType.LeftBrace)
1566 return BraceArray();
1569 if (LookAhead().Type ==
TokenType.LeftBracket)
1570 return BracketArray();
1572 Variable variable = Atom();
1582 private Variable Term()
1585 List<Instruction> listInstructions = executable.InstructionsInternal;
1587 Variable first = Factor();
1594 Token token = ReadToken();
1602 listInstructions.Add(
new Instruction(
OpCode.MUL, Operand.Variable(first.name), Operand.Variable(second.name)));
1604 first.derivatedType = Derivate(token, first.derivatedType, second.derivatedType);
1612 listInstructions.Add(
new Instruction(
OpCode.DIV, Operand.Variable(first.name), Operand.Variable(second.name)));
1614 first.derivatedType = Derivate(token, first.derivatedType, second.derivatedType);
1621 listInstructions.Add(
new Instruction(
OpCode.MOD, Operand.Variable(first.name), Operand.Variable(second.name)));
1623 first.derivatedType = Derivate(token, first.derivatedType, second.derivatedType);
1643 private Variable Arithmetic()
1646 List<Instruction> listInstructions = executable.InstructionsInternal;
1648 Variable first = Term();
1655 Token token = ReadToken();
1664 listInstructions.Add(
new Instruction(
OpCode.ADD, Operand.Variable(first.name), Operand.Variable(second.name)));
1666 first.derivatedType = Derivate(token, first.derivatedType, second.derivatedType);
1674 listInstructions.Add(
new Instruction(
OpCode.SUB, Operand.Variable(first.name), Operand.Variable(second.name)));
1694 private Variable Relation()
1697 List<Instruction> instructions = executable.InstructionsInternal;
1699 Variable first = Arithmetic();
1701 Token token = ReadToken();
1703 if (RelationalOperator(token.Type)) {
1705 Variable second = Arithmetic();
1707 instructions.Add(
new Instruction(RelationalOpcode(token.Type), Operand.Variable(first.name), Operand.Variable(second.name)));
1709 first.derivatedType = Derivate(token, first.derivatedType, second.derivatedType);
1726 private Variable Not()
1729 Variable proposition =
new Variable();
1736 if (LookAhead().Type ==
TokenType.LeftParen)
1737 proposition = Expression();
1740 proposition = Relation();
1742 executable.InstructionsInternal.Add(
new Instruction(
OpCode.NOT, Operand.Variable(proposition.name)));
1759 private Variable And()
1762 List<Instruction> instructions = executable.InstructionsInternal;
1764 Variable first = Not();
1769 Token token = ReadToken();
1774 Variable second = Not();
1776 instructions.Add(
new Instruction(
OpCode.AND, Operand.Variable(first.name), Operand.Variable(second.name)));
1778 first.derivatedType = Derivate(token, first.derivatedType, second.derivatedType);
1805 private Variable Or()
1808 List<Instruction> instructions = executable.InstructionsInternal;
1810 Variable first = And();
1815 Token token = ReadToken();
1820 Variable second = And();
1822 instructions.Add(
new Instruction(
OpCode.OR, Operand.Variable(first.name), Operand.Variable(second.name)));
1824 first.derivatedType = Derivate(token, first.derivatedType, second.derivatedType);
1849 private Variable VariableAssignment()
1852 string identifier = ExpectIdentifier();
1854 Token token = ReadToken();
1856 if (!AssignmentOperator(token.Type))
1857 throw new ParserException(
"Ein Zuweisungsoperator wurde erwartet erwartet.", token);
1859 Variable expression = Expression();
1861 executable.InstructionsInternal.Add(
new Instruction(AssignmentOpcode(token.Type), Operand.Variable(identifier), Operand.Variable(expression.name)));
1863 string tmpIdentifier = AllocateTemporaryVariable();
1865 executable.InstructionsInternal.Add(
new Instruction(
OpCode.MOV, Operand.Variable(tmpIdentifier), Operand.Variable(identifier)));
1867 return new Variable(tmpIdentifier,
Scope.Local, expression.derivatedType);
1875 private Variable ArrayAssignment()
1878 string identifier = ExpectIdentifier();
1880 List<Instruction> listInstructions = executable.InstructionsInternal;
1884 string src = identifier;
1888 while (!AssignmentOperator(LookAhead().Type))
1897 if (!AssignmentOperator(LookAhead().Type))
1900 dst = AllocateTemporaryVariable();
1902 listInstructions.Add(
new Instruction(
OpCode.MOV, Operand.Variable(dst), Operand.CreatePointer(src, tmp.name)));
1910 Token tok = ReadToken();
1912 Variable expression = Expression();
1917 listInstructions.Add(
new Instruction(AssignmentOpcode(tok.Type), Operand.CreatePointer(dst, tmp.name), Operand.Variable(expression.name)));
1919 string tmpIdentifier = AllocateTemporaryVariable();
1921 executable.InstructionsInternal.Add(
new Instruction(
OpCode.MOV, Operand.Variable(tmpIdentifier), Operand.CreatePointer(dst, tmp.name)));
1923 return new Variable(tmpIdentifier,
Scope.Local, expression.derivatedType);
1931 private Variable MemberAssignment()
1934 string identifier = ExpectIdentifier();
1936 List<string> members =
new List<string>();
1938 while (LookAhead().Type ==
TokenType.Period)
1943 members.Add(ReadIdentifier());
1947 Token tok = ReadToken();
1949 if (!AssignmentOperator(tok.Type))
1950 throw new ParserException(
"Ein Zuweisungsoperator wurde erwartet.", tok);
1952 Variable expression = Expression();
1956 string src = identifier;
1958 for (
int i = 0; i < members.Count - 1; i++)
1961 dst = AllocateTemporaryVariable();
1963 executable.InstructionsInternal.Add(
new Instruction(
OpCode.MOV, Operand.Variable(dst), Operand.MemberVariable(src, members[i])));
1972 executable.InstructionsInternal.Add(
new Instruction(AssignmentOpcode(tok.Type), Operand.MemberVariable(dst, members[members.Count - 1]), Operand.Variable(expression.name)));
1974 string tmpIdentifier = AllocateTemporaryVariable();
1976 executable.InstructionsInternal.Add(
new Instruction(
OpCode.MOV, Operand.Variable(tmpIdentifier), Operand.MemberVariable(dst, members[members.Count - 1])));
1978 Variable variable =
new Variable(tmpIdentifier,
Scope.Local, expression.derivatedType);
1988 private Variable Assignment()
1991 string identifier = ExpectIdentifier();
1993 Token token = LookAhead();
2009 return VariableAssignment();
2013 return ArrayAssignment();
2017 return MemberAssignment();
2020 throw new ExecutionException(
"Es wurde ein Zuweisungoperator erwartet.");
2030 private bool IsPointer()
2033 Token start = LookAhead();
2038 int iInstructionCheckpoint = executable.InstructionsInternal.Count;
2040 string identifier = ReadIdentifier();
2042 while (LookAhead().Type ==
TokenType.LeftBracket)
2051 Token tok = ReadToken();
2053 while (LookAhead() != start)
2056 executable.InstructionsInternal.RemoveRange(iInstructionCheckpoint, executable.InstructionsInternal.Count - iInstructionCheckpoint);
2058 return AssignmentOperator(tok.Type);
2066 private bool IsMember()
2069 Token start = LookAhead();
2074 string identifier = ReadIdentifier();
2076 while (LookAhead().Type ==
TokenType.Period)
2081 Token token = ReadToken();
2086 while (LookAhead() != start)
2095 Token tok = ReadToken();
2097 while (LookAhead() != start)
2100 return AssignmentOperator(tok.Type);
2108 private Variable Expression()
2111 if (IsPointer() || IsMember())
2112 return Assignment();
2125 Token token = ReadToken();
2128 throw new ParserException(
"Keyword 'if' erwartet.", token);
2130 ReadLeftParenthesis();
2132 Variable condition = Expression();
2134 ReadRightParenthesis();
2136 Instruction start =
new Instruction(
OpCode.NOP);
2138 Instruction end =
new Instruction(
OpCode.NOP);
2140 executable.InstructionsInternal.Add(
new Instruction(
OpCode.JNZ, Operand.Variable(condition.name), Operand.AllocateInstructionPointer(start)));
2144 executable.InstructionsInternal.Add(
new Instruction(
OpCode.JMP, Operand.AllocateInstructionPointer(end)));
2146 executable.InstructionsInternal.Add(start);
2156 executable.InstructionsInternal.Add(end);
2163 private void While()
2166 Token token = ReadToken();
2169 throw new ParserException(
"Keyword 'while' erwartet.", token);
2171 Instruction start =
new Instruction(
OpCode.NOP);
2173 executable.InstructionsInternal.Add(start);
2175 ReadLeftParenthesis();
2177 Variable condition = Expression();
2179 if (condition.derivatedType !=
null && condition.derivatedType != typeof(
bool))
2180 throw new ParserException(
"In While Loops wird ein logischer Ausdruck erwartet.", token);
2182 ReadRightParenthesis();
2184 Instruction end =
new Instruction(
OpCode.NOP);
2186 executable.InstructionsInternal.Add(
new Instruction(
OpCode.JNZ, Operand.Variable(condition.name), Operand.AllocateInstructionPointer(end)));
2188 LoopControl loopControl =
new LoopControl();
2190 loopControl.Break = end;
2192 loopControl.Continue = start;
2194 this.loopControl.Push(loopControl);
2198 this.loopControl.Pop();
2200 executable.InstructionsInternal.Add(
new Instruction(
OpCode.JMP, Operand.AllocateInstructionPointer(start)));
2202 executable.InstructionsInternal.Add(end);
2212 Token token = ReadToken();
2215 throw new ParserException(
"Keyword 'for' erwartet.", token);
2217 ReadLeftParenthesis();
2219 if (LookAhead().Type ==
TokenType.SemiColon)
2222 else if (LookAhead().Type ==
TokenType.Var)
2223 LocalVariableDeclaration();
2234 Instruction start =
new Instruction(
OpCode.NOP);
2236 executable.InstructionsInternal.Add(start);
2238 Instruction continueInstruction =
new Instruction(
OpCode.NOP);
2240 Variable condition =
new Variable();
2242 if (LookAhead().Type ==
TokenType.SemiColon)
2245 condition =
new Variable(AllocateTemporaryVariable(),
Scope.Local, typeof(
bool));
2247 executable.InstructionsInternal.Add(
new Instruction(
OpCode.MOV, Operand.Variable(condition.name), Operand.Literal(
true)));
2256 condition = Expression();
2258 if (condition.derivatedType !=
null && condition.derivatedType != typeof(
bool))
2259 throw new ParserException(
"In For Loops wird ein logischer Ausdruck oder 'null' erwartet.", token);
2265 List<Instruction> expression =
null;
2267 if (LookAhead().Type !=
TokenType.RightParen)
2270 int loopStart = executable.InstructionsInternal.Count;
2274 int loopCount = executable.InstructionsInternal.Count - loopStart;
2276 expression = executable.InstructionsInternal.GetRange(loopStart, loopCount);
2278 executable.InstructionsInternal.RemoveRange(loopStart, loopCount);
2283 expression =
new List<Instruction>();
2285 ReadRightParenthesis();
2287 Instruction end =
new Instruction(
OpCode.NOP);
2289 executable.InstructionsInternal.Add(
new Instruction(
OpCode.JNZ, Operand.Variable(condition.name), Operand.AllocateInstructionPointer(end)));
2291 LoopControl loopControl =
new LoopControl();
2293 loopControl.Break = end;
2295 loopControl.Continue = continueInstruction;
2297 this.loopControl.Push(loopControl);
2301 this.loopControl.Pop();
2303 executable.InstructionsInternal.Add(continueInstruction);
2305 executable.InstructionsInternal.AddRange(expression);
2307 executable.InstructionsInternal.Add(
new Instruction(
OpCode.JMP, Operand.AllocateInstructionPointer(start)));
2309 executable.InstructionsInternal.Add(end);
2316 private void ForEach()
2319 Token token = ReadToken();
2322 throw new ParserException(
"Keyword 'foreach' erwartet.", token);
2324 ReadLeftParenthesis();
2328 string val = ExpectIdentifier();
2330 token = ReadToken();
2337 val = ExpectIdentifier();
2339 token = ReadToken();
2344 throw new ParserException(
"Keyword 'in' erwartet.", token);
2347 key = AllocateTemporaryVariable();
2349 executable.InstructionsInternal.Add(
new Instruction(
OpCode.MOV, Operand.Variable(key), Operand.Literal(NullReference.Instance)));
2351 Instruction start =
new Instruction(
OpCode.NOP);
2353 executable.InstructionsInternal.Add(start);
2355 Variable array = Expression();
2357 if (array.derivatedType !=
null && array.derivatedType != typeof(ArrayList))
2358 throw new ParserException(
"In ForEach Loops wird ein logischer Ausdruck erwartet.", token);
2360 ReadRightParenthesis();
2362 executable.InstructionsInternal.Add(
new Instruction(
OpCode.PTR, Operand.Variable(key), Operand.Variable(array.name)));
2364 string identifier = AllocateTemporaryVariable();
2366 executable.InstructionsInternal.Add(
new Instruction(
OpCode.MOV, Operand.Variable(identifier), Operand.Variable(key)));
2369 executable.InstructionsInternal.Add(
new Instruction(
OpCode.TEST, Operand.Variable(identifier)));
2371 Instruction end =
new Instruction(
OpCode.NOP);
2373 executable.InstructionsInternal.Add(
new Instruction(
OpCode.JZ, Operand.Variable(identifier), Operand.AllocateInstructionPointer(end)));
2375 executable.InstructionsInternal.Add(
new Instruction(
OpCode.MOV, Operand.Variable(val), Operand.CreatePointer(array.name, key)));
2377 LoopControl loopControl =
new LoopControl();
2379 loopControl.Break = end;
2381 loopControl.Continue = start;
2383 this.loopControl.Push(loopControl);
2387 this.loopControl.Pop();
2389 executable.InstructionsInternal.Add(
new Instruction(
OpCode.JMP, Operand.AllocateInstructionPointer(start)));
2391 executable.InstructionsInternal.Add(end);
2398 private void Break()
2401 Token token = ReadToken();
2404 throw new ParserException(
"Keyword 'break' erwartet.", token);
2408 if (loopControl.Count == 0)
2409 throw new ParserException(
"Das Keyword 'break' kann nur innerhalb von Loops verwendet werden.", token);
2411 Instruction breakInstruction = loopControl.Peek().Break;
2413 executable.InstructionsInternal.Add(
new Instruction(
OpCode.JMP, Operand.AllocateInstructionPointer(breakInstruction)));
2420 private void Continue()
2423 Token token = ReadToken();
2426 throw new ParserException(
"Keyword 'continue' erwartet.", token);
2430 if (loopControl.Count == 0)
2431 throw new ParserException(
"Das Keyword 'continue' kann nur innerhalb von Loops verwendet werden.", token);
2433 Instruction continueInstruction = loopControl.Peek().Continue;
2435 executable.InstructionsInternal.Add(
new Instruction(
OpCode.JMP, Operand.AllocateInstructionPointer(continueInstruction)));
2442 private void Switch()
2445 Token token = ReadToken();
2448 throw new ParserException(
"Keyword 'switch' erwartet.", token);
2450 ReadLeftParenthesis();
2452 string switchIdentifier = ExpectIdentifier();
2454 ReadRightParenthesis();
2458 token = LookAhead();
2461 throw new ParserException(
"Keyword 'case' oder 'default' erwartet.", token);
2463 string tmpIdentifier = AllocateTemporaryVariable();
2465 string identifier = AllocateTemporaryVariable();
2467 Instruction end =
new Instruction(
OpCode.NOP);
2469 executable.InstructionsInternal.Add(
new Instruction(
OpCode.MOV, Operand.Variable(tmpIdentifier), Operand.Literal(
false)));
2471 while (LookAhead().Type !=
TokenType.Default && LookAhead().Type !=
TokenType.RightBrace)
2474 token = ReadToken();
2477 throw new ParserException(
"Keyword 'case' erwartet.", token);
2479 InsertDebugInfo(token);
2481 Variable expression = Expression();
2483 token = ReadToken();
2486 throw new ParserException(
"Colon ':' erwartet.", token);
2488 executable.InstructionsInternal.Add(
new Instruction(
OpCode.MOV, Operand.Variable(identifier), Operand.Variable(switchIdentifier)));
2490 executable.InstructionsInternal.Add(
new Instruction(
OpCode.CEQ, Operand.Variable(identifier), Operand.Variable(expression.name)));
2492 executable.InstructionsInternal.Add(
new Instruction(
OpCode.OR, Operand.Variable(tmpIdentifier), Operand.Variable(identifier)));
2496 Instruction switchInstruction =
new Instruction(
OpCode.NOP);
2498 executable.InstructionsInternal.Add(
new Instruction(
OpCode.JNZ, Operand.Variable(tmpIdentifier), Operand.AllocateInstructionPointer(switchInstruction)));
2502 executable.InstructionsInternal.Add(
new Instruction(
OpCode.JMP, Operand.AllocateInstructionPointer(end)));
2504 executable.InstructionsInternal.Add(switchInstruction);
2506 executable.InstructionsInternal.Add(
new Instruction(
OpCode.MOV, Operand.Variable(tmpIdentifier), Operand.Literal(
false)));
2511 token = ReadToken();
2516 executable.InstructionsInternal.Add(end);
2523 throw new ParserException(
"Das Keyword 'default' oder eine schliessende geschwungene Klammer '}' wird am Ende einer 'switch' Anweisung erwartet.", token);
2525 token = ReadToken();
2528 throw new ParserException(
"Ein Colon ':' wurde erwartet.", token);
2534 executable.InstructionsInternal.Add(end);
2541 private void Return()
2544 Token token = ReadToken();
2547 throw new ParserException(
"Keyword 'return' erwartet.", token);
2549 if (LookAhead().Type !=
TokenType.SemiColon)
2550 executable.InstructionsInternal.Add(
new Instruction(
OpCode.PUSH, Operand.Variable(Expression().name)));
2553 executable.InstructionsInternal.Add(
new Instruction(
OpCode.PUSH, Operand.Literal(NullReference.Instance)));
2557 executable.InstructionsInternal.Add(
new Instruction(
OpCode.RET));
2566 private void FunctionDeclaration()
2569 Token token = ReadToken();
2572 throw new ParserException(
"Funktion werden mit 'function' deklariert.", token);
2574 string functionName = ReadIdentifier();
2576 if (executable.Functions.ContainsKey(functionName))
2577 throw new ParserException(
"Die Funktion '" + functionName +
"' ist bereits vorhanden.", token);
2579 ReadLeftParenthesis();
2581 InsertDebugInfo(token);
2583 List<string> parameters =
new List<string>();
2585 if (LookAhead().Type !=
TokenType.RightParen)
2591 token = ReadToken();
2594 throw new ParserException(
"Unerwarteter Token '" + token.Lexeme +
"'.", token);
2596 string parameter = token.Lexeme.ToString();
2598 AllocateVariable(parameter);
2600 parameters.Add(parameter);
2602 token = LookAhead();
2607 else if (token.Type ==
TokenType.RightParen)
2611 throw new ParserException(
"Comma ',' oder schliessende Klammer ')' erwartet.");
2617 ReadRightParenthesis();
2619 Instruction scriptInstructionFunctionEntry =
new Instruction(
OpCode.NOP);
2621 executable.InstructionsInternal.Add(scriptInstructionFunctionEntry);
2623 Function scriptFunction =
new Function(executable, functionName, parameters, scriptInstructionFunctionEntry);
2625 executable.Functions[functionName] = scriptFunction;
2627 parameters.Reverse();
2629 foreach (
string parameter
in parameters)
2632 Instruction scriptInstructionPop =
new Instruction(
OpCode.POP, Operand.Variable(parameter));
2634 executable.InstructionsInternal.Add(scriptInstructionPop);
2640 executable.InstructionsInternal.Add(
new Instruction(
OpCode.PUSH, Operand.Literal(NullReference.Instance)));
2642 executable.InstructionsInternal.Add(
new Instruction(
OpCode.RET));
2644 localVariables.Clear();
2656 private Variable FunctionCall(
bool background)
2659 string name = ReadIdentifier();
2662 bool forwardDeclared =
true;
2665 if (!executable.Functions.ContainsKey(name))
2666 forwardDeclared =
false;
2668 ReadLeftParenthesis();
2670 uint parameterCount = 0;
2672 if (LookAhead().Type !=
TokenType.RightParen)
2679 Variable parameter = Expression();
2681 executable.InstructionsInternal.Add(
new Instruction(
OpCode.PUSH, Operand.Variable(parameter.name)));
2685 if (LookAhead().Type ==
TokenType.RightParen)
2695 ReadRightParenthesis();
2697 Instruction instruction =
null;
2701 if (forwardDeclared)
2704 function = executable.Functions[name];
2706 if (
function.ParameterCount > parameterCount)
2707 throw new ParserException(
"Der Aufruf der Funktion '" + name +
"' hat fehlende Parameter. Erwartet werden " +
function.ParameterCount +
" Parameter.");
2710 if (
function.ParameterCount < parameterCount)
2711 throw new ParserException(
"Der Aufruf der Funktion '" + name +
"' hat zu viele Parameter. Erwartet werden " +
function.ParameterCount +
" Parameter.");
2715 Variable variable =
new Variable();
2720 instruction =
new Instruction(
OpCode.RUN, Operand.AllocateFunctionPointer(
function));
2722 executable.InstructionsInternal.Add(instruction);
2729 instruction =
new Instruction(
OpCode.CALL, Operand.AllocateFunctionPointer(
function));
2731 executable.InstructionsInternal.Add(instruction);
2734 variable.name = AllocateTemporaryVariable();
2736 variable.scope =
Scope.Local;
2738 variable.derivatedType =
null;
2740 executable.InstructionsInternal.Add(
new Instruction(
OpCode.POP, Operand.Variable(variable.name)));
2744 if (!forwardDeclared)
2747 FunctionDescriptor functionDescriptor =
new FunctionDescriptor();
2749 functionDescriptor.name = name;
2751 functionDescriptor.parameterCount = parameterCount;
2753 functionDescriptor.instruction =
null;
2755 forwardDeclarations[instruction] = functionDescriptor;
2768 private Variable FunctionCall()
2771 string functionName = ReadIdentifier();
2775 if (executable.Script.Manager.IsRegistered(functionName))
2776 return RoutineCall();
2779 return FunctionCall(
false);
2786 private void Statement()
2789 AllocateFunctionFrame();
2791 Token token = LookAhead();
2793 InsertDebugInfo(token);
2803 LocalVariableDeclaration();
2821 if(LookAhead().Type ==
TokenType.SemiColon)
2863 LockedStatementList();
2866 default:
throw new ParserException(
"ParserException::Statement: Ein unerwarteter Token '" + token.Lexeme +
"' wurde gefunden.", token);
2870 FreeFunctionFrame();
2878 private void StatementList()
2882 if (LookAhead().Type !=
TokenType.LeftBrace)
2893 while (LookAhead().Type !=
TokenType.RightBrace)
2903 private void LockedStatementList()
2906 Token token = ReadToken();
2909 throw new ExecutionException(
"ParserException: Keyword 'lock' erwartet.");
2911 Variable variable = Expression();
2913 executable.InstructionsInternal.Add(
new Instruction(
OpCode.LOCK, Operand.Variable(variable.name)));
2917 executable.InstructionsInternal.Add(
new Instruction(
OpCode.FREE, Operand.Variable(variable.name)));
2924 private void Yield()
2927 Token token = ReadToken();
2930 throw new ParserException(
"ParserException: Keyword 'yield' erwartet.", token);
2934 executable.InstructionsInternal.Add(
new Instruction(
OpCode.INT));
2946 Token token = ReadToken();
2949 throw new ParserException(
"Keyword 'wailt' erwartet.", token);
2951 string identifier = ExpectIdentifier();
2955 List<Instruction> instructions = executable.InstructionsInternal;
2957 Instruction arrived =
new Instruction(
OpCode.NOP);
2959 Instruction waiting =
new Instruction(
OpCode.JZ, Operand.Variable(identifier), Operand.AllocateInstructionPointer(arrived));
2961 instructions.Add(waiting);
2963 instructions.Add(
new Instruction(
OpCode.INT));
2965 instructions.Add(
new Instruction(
OpCode.JMP, Operand.AllocateInstructionPointer(waiting)));
2967 instructions.Add(arrived);
2975 private void Notify()
2978 Token token = ReadToken();
2981 throw new ParserException(
"Keyword 'notify' erwartet.", token);
2983 string identifier = ExpectIdentifier();
2987 executable.InstructionsInternal.Add(
new Instruction(
OpCode.MOV, Operand.Variable(identifier), Operand.Literal(
true)));
2996 private void ParseScript()
3002 Token token = LookAhead();
3005 VariableDeclaration();
3007 else if (token.Type ==
TokenType.Struct)
3008 StructDeclaration();
3024 Token token = LookAhead();
3027 throw new ParserException(
"Ausserhalb von Funktionen sind keine Anweisungen erlaubt.", token);
3029 FunctionDeclaration();
3038 private void ResolveForwardFunctionDeclarations()
3041 foreach (Instruction instruction
in forwardDeclarations.Keys)
3044 FunctionDescriptor functionDescriptor = forwardDeclarations[instruction];
3046 string name = functionDescriptor.name;
3048 if (!executable.Functions.ContainsKey(name))
3049 throw new ParserException(
"Eine nicht deklarierte Funktion '" + name +
"' wurde referenziert.");
3051 Function function = executable.Functions[name];
3053 instruction.First.FunctionPointer =
function;
3061 #region Internal Properties
3063 internal bool DebugMode
3065 get {
return debugMode; }
3066 set { debugMode = value; }
3071 #region Public Methods
3075 this.script = script;
3078 variables =
new Dictionary<String, bool>();
3079 localVariables =
new Dictionary<String, bool>();
3080 functionFrameIndex = 0;
3081 forwardDeclarations =
new Dictionary<Instruction, FunctionDescriptor>();
3082 loopControl =
new Stack<LoopControl>();
3083 this.tokenStream =
new List<Token>(tokenStream);
3084 derivation =
new Derivation();
3096 localVariables.Clear();
3097 functionFrameIndex = -1;
3098 forwardDeclarations.Clear();
3099 loopControl.Clear();
3104 ResolveForwardFunctionDeclarations();