2using System.Collections.Generic;
24 #region Private Structs
61 #region Private Variables
77 #region Private Methods
138 throw new ParserException(
"Es sind keine vorangehenden Token mehr vorhanden.");
196 throw new ParserException(
"Der Token '" + tokenType +
"' ist kein Zuweisungsoperator.");
246 throw new ParserException(
"Der Token '" + tokenType +
"' ist kein relationaler Operator.");
267 return typeof(
float);
271 return typeof(
string);
275 return typeof(
double);
277 return typeof(decimal);
279 throw new ParserException(
"Der Token '" + tokenType.ToString() +
"' kann keinem Literal zugeordnet werden.");
295 return derivation.Derivate(token, first, second);
307 throw new ParserException(
"Die Variable '" + identifier +
"' ist in einem umschliessenden Bereich bereits deklariert.");
310 throw new ParserException(
"Die Variable '" + identifier +
"' ist in diesem Bereich bereits deklariert.");
367 List<string> candidates =
new List<string>();
371 candidates.Add(identifier);
373 foreach (
string identifier
in candidates)
441 throw new ParserException(
"Geschwungene Klammer '{' erwartet.", token);
454 throw new ParserException(
"Geschwungene Klammer '}' erwartet.", token);
503 string text = token.
Text;
521 throw new ParserException(
"Ein Keyword oder eine Variable wurde erwartet.", token);
523 return token.
Lexeme.ToString();
561 throw new ParserException(
"Ein Keyword oder eine Variable wurde erwartet.", token);
563 string identifier = token.
Lexeme.ToString();
566 throw new ParserException(
"Ein nicht vorhandener Identifier '" + identifier +
"' wurde referenziert.", token);
581 throw new ParserException(
"Variablen werden mit 'shared' oder 'var' deklariert.", token);
596 throw new ParserException(
"Die Variable '" + identifier +
"' ist bereits vorhanden.", token);
603 script.Manager.SharedMemory[identifier] = NullReference.Instance;
606 executable.ScriptMemory[identifier] = NullReference.Instance;
631 throw new ParserException(
"Lokale Variablen werden mit 'var' deklariert.", token);
699 List<object> parameters =
new List<object>();
701 int parameterCount = 0;
729 if (!manager.
Routines.ContainsKey(identifier))
730 throw new ParserException(
"Die Routine '" + identifier +
"' ist nicht vorhanden.");
735 throw new ParserException(
"Der Aufruf der Routine '" + identifier +
"' hat fehlende Parameter. Erwartet werden " + routine.
ParameterTypes.Count +
" Parameter.\nBeschreibung der Routine: " + routine.
Description().ToString());
738 throw new ParserException(
"Der Aufruf der Routine '" + identifier +
"' hat zu viele Parameter. Erwartet werden " + routine.
ParameterTypes.Count +
" Parameter.\nBeschreibung der Routine: " + routine.
Description().ToString());
818 arrayIdentifier = tmp;
888 int parameterCount = 0;
1184 var literal =
new StringBuilder(input.Length + 2);
1185 literal.Append(
"\"");
1186 foreach (var c
in input)
1190 case '\'': literal.Append(
@"\'");
break;
1191 case '\"': literal.Append(
"\\\"");
break;
1192 case '\\': literal.Append(
@"\\");
break;
1193 case '\0': literal.Append(
@"\0");
break;
1194 case '\a': literal.Append(
@"\a");
break;
1195 case '\b': literal.Append(
@"\b");
break;
1196 case '\f': literal.Append(
@"\f");
break;
1197 case '\n': literal.Append(
@"\n");
break;
1198 case '\r': literal.Append(
@"\r");
break;
1199 case '\t': literal.Append(
@"\t");
break;
1200 case '\v': literal.Append(
@"\v");
break;
1202 if (
char.GetUnicodeCategory(c) != System.Globalization.UnicodeCategory.Control)
1208 literal.Append(
@"\u");
1209 literal.Append(((ushort)c).ToString(
"x4"));
1214 literal.Append(
"\"");
1215 return literal.ToString();
1242 variable.name = tmpIdentifier;
1250 variable.scope =
Scope.Local;
1252 variable.derivatedType = typeof(NullReference);
1268 variable.scope =
Scope.Local;
1294 string identifier = token.
Lexeme.ToString();
1330 string qualified = identifier;
1331 bool hasDot =
false;
1340 qualified +=
"." +
tokenStream[i + 1].Lexeme.ToString();
1345 bool looksLikeQualifiedCall = hasDot && i < tokenStream.Count &&
tokenStream[i].Type ==
TokenType.LeftParen;
1347 if (looksLikeQualifiedCall &&
executable.Script.Manager.IsRegistered(qualified))
1384 variable.scope =
Scope.Local;
1386 variable.derivatedType =
null;
1404 throw new ParserException(
"Fehlerhafter Token '" + token +
"'.", token);
1478 throw new ParserException(
"Ein Comma ',', Semicolon ';' oder Colon ':' wurde erwartet.");
1548 throw new ParserException(
"Ein Comma ',' oder Colon ':' wurde erwartet.");
1593 result.derivatedType = typeof(
int);
1611 List<Instruction> listInstructions =
executable.InstructionsInternal;
1672 List<Instruction> listInstructions =
executable.InstructionsInternal;
1723 List<Instruction> instructions =
executable.InstructionsInternal;
1795 List<Instruction> instructions =
executable.InstructionsInternal;
1812 first.derivatedType = typeof(
int);
1831 List<Instruction> instructions =
executable.InstructionsInternal;
1847 first.derivatedType = typeof(
int);
1866 List<Instruction> instructions =
executable.InstructionsInternal;
1882 first.derivatedType = typeof(
int);
1904 List<Instruction> instructions =
executable.InstructionsInternal;
1942 List<Instruction> instructions =
executable.InstructionsInternal;
1983 throw new ParserException(
"Ein Zuweisungsoperator wurde erwartet erwartet.", token);
2027 List<Instruction> listInstructions =
executable.InstructionsInternal;
2030 List<AccessSegment> segments =
new List<AccessSegment>();
2056 throw new ParserException(
"Ein Zuweisungsoperator wurde erwartet.", tok);
2061 string current = identifier;
2063 for (
int i = 0; i < segments.Count - 1; i++)
2066 var seg = segments[i];
2079 if (segments.Count == 0)
2085 var last = segments[segments.Count - 1];
2086 dest = last.IsMember
2110 List<Instruction> listInstructions =
executable.InstructionsInternal;
2114 string src = identifier;
2166 List<string> members =
new List<string>();
2180 throw new ParserException(
"Ein Zuweisungsoperator wurde erwartet.", tok);
2186 string src = identifier;
2188 for (
int i = 0; i < members.Count - 1; i++)
2237 int iInstructionCheckpoint =
executable.InstructionsInternal.Count;
2264 iInstructionCheckpoint,
2265 executable.InstructionsInternal.Count - iInstructionCheckpoint);
2282 iInstructionCheckpoint,
2283 executable.InstructionsInternal.Count - iInstructionCheckpoint);
2301 int iInstructionCheckpoint =
executable.InstructionsInternal.Count;
2319 executable.InstructionsInternal.RemoveRange(iInstructionCheckpoint,
executable.InstructionsInternal.Count - iInstructionCheckpoint);
2443 throw new ParserException(
"In While Loops wird ein logischer Ausdruck erwartet.", token);
2453 loopControl.Break = end;
2455 loopControl.Continue = start;
2461 this.loopControl.Pop();
2522 throw new ParserException(
"In For Loops wird ein logischer Ausdruck oder 'null' erwartet.", token);
2528 List<Instruction> expression =
null;
2533 int loopStart =
executable.InstructionsInternal.Count;
2537 int loopCount = executable.InstructionsInternal.Count - loopStart;
2539 expression =
executable.InstructionsInternal.GetRange(loopStart, loopCount);
2541 executable.InstructionsInternal.RemoveRange(loopStart, loopCount);
2546 expression =
new List<Instruction>();
2556 loopControl.Break = end;
2558 loopControl.Continue = continueInstruction;
2564 this.loopControl.Pop();
2566 executable.InstructionsInternal.Add(continueInstruction);
2568 executable.InstructionsInternal.AddRange(expression);
2623 && !typeof(System.Collections.IEnumerable).IsAssignableFrom(array.
derivatedType))
2624 throw new ParserException(
"In ForEach Loops wird ein iterierbarer Ausdruck erwartet (Array/List/String/IEnumerable).", token);
2645 loopControl.Break = end;
2647 loopControl.Continue = start;
2653 this.loopControl.Pop();
2675 throw new ParserException(
"Das Keyword 'break' kann nur innerhalb von Loops verwendet werden.", token);
2697 throw new ParserException(
"Das Keyword 'continue' kann nur innerhalb von Loops verwendet werden.", token);
2727 throw new ParserException(
"Keyword 'case' oder 'default' erwartet.", token);
2770 executable.InstructionsInternal.Add(switchInstruction);
2789 throw new ParserException(
"Das Keyword 'default' oder eine schliessende geschwungene Klammer '}' wird am Ende einer 'switch' Anweisung erwartet.", token);
2838 throw new ParserException(
"Funktion werden mit 'function' deklariert.", token);
2842 if (
executable.Functions.ContainsKey(functionName))
2843 throw new ParserException(
"Die Funktion '" + functionName +
"' ist bereits vorhanden.", token);
2849 List<string> parameters =
new List<string>();
2862 string parameter = token.
Lexeme.ToString();
2866 parameters.Add(parameter);
2877 throw new ParserException(
"Comma ',' oder schliessende Klammer ')' erwartet.");
2887 executable.InstructionsInternal.Add(scriptInstructionFunctionEntry);
2891 executable.Functions[functionName] = scriptFunction;
2893 parameters.Reverse();
2895 foreach (
string parameter
in parameters)
2900 executable.InstructionsInternal.Add(scriptInstructionPop);
2928 bool forwardDeclared =
true;
2932 forwardDeclared =
false;
2936 uint parameterCount = 0;
2967 if (forwardDeclared)
2972 if (
function.ParameterCount > parameterCount)
2973 throw new ParserException(
"Der Aufruf der Funktion '" + name +
"' hat fehlende Parameter. Erwartet werden " +
function.ParameterCount +
" Parameter.");
2976 if (
function.ParameterCount < parameterCount)
2977 throw new ParserException(
"Der Aufruf der Funktion '" + name +
"' hat zu viele Parameter. Erwartet werden " +
function.ParameterCount +
" Parameter.");
2988 executable.InstructionsInternal.Add(instruction);
2997 executable.InstructionsInternal.Add(instruction);
3002 variable.scope =
Scope.Local;
3004 variable.derivatedType =
null;
3010 if (!forwardDeclared)
3015 functionDescriptor.name = name;
3017 functionDescriptor.parameterCount = parameterCount;
3019 functionDescriptor.instruction =
null;
3045 if (
executable.Script.Manager.IsRegistered(functionName))
3135 default:
throw new ParserException(
"ParserException::Statement: Ein unerwarteter Token '" + token.
Lexeme +
"' wurde gefunden.", token);
3199 throw new ParserException(
"ParserException: Keyword 'yield' erwartet.", token);
3224 List<Instruction> instructions =
executable.InstructionsInternal;
3230 instructions.Add(waiting);
3236 instructions.Add(arrived);
3290 throw new ParserException(
"Ausserhalb von Funktionen sind keine Anweisungen erlaubt.", token);
3309 string name = functionDescriptor.
name;
3312 throw new ParserException(
"Eine nicht deklarierte Funktion '" + name +
"' wurde referenziert.");
3316 instruction.First.FunctionPointer =
function;
3324 #region Internal Properties
3326 internal bool DebugMode
3334 #region Public Methods
3341 variables =
new Dictionary<String, bool>();
static AccessSegment Index(string indexVar)
static AccessSegment Member(string name)
void AllocateFunctionFrame()
Increase the function frame index.
void ParseScript()
After the first function declaration no more variable, struct or enum declarations are allowed anymor...
List< Token > tokenStream
Variable Or()
Disjunction (not exclusive).
string ReadIdentifier()
Read a new (previously NOT declared) identifier.
void ReadLeftParenthesis()
Variable BitwiseOr()
Bitwise OR '|'.
void FreeFunctionFrame()
Decrease the function frame index.
bool More()
Check if there are more tokens available.
void LockedStatementList()
Variable ArrayAssignment()
Variable AccessChainAssignment()
Mixed access chain assignment.
void Return()
By default null is returned.
void LocalVariableDeclaration()
Variable Assignment()
An assignment can be a variable assignment, an array assignment or a member assignment.
void InsertDebugInfo(Token token)
Variable BinaryNotAssign()
Variable Arithmetic()
Multiplication and division before Addition and substraction.
Variable Atom()
The smallest unit.
string ExpectIdentifier()
Read an expected (previously declared) identifier.
Variable Not()
Proposition.
Variable MemberAssignment()
Variable AccessChain()
Mixed access chain parser.
Variable Pointer()
Array access.
Variable VariableAssignment()
Parser(Script script, List< Token > tokenStream)
void VariableDeclaration()
Shared or local variable declaration.
OpCode AssignmentOpcode(TokenType tokenType)
Type Literal(TokenType tokenType)
Get the literal type of a token.
Dictionary< string, bool > variables
void Wait()
Wait for a locked secion of code to be freed.
void ResolveForwardFunctionDeclarations()
Resolve unresolved, forward declared functions.
Variable BracketArray()
An array enclosed in brackets.
void AllocateVariable(string identifier)
Allocate a local variable.
Variable And()
Conjunction.
void FunctionDeclaration()
Parameter variables are already set to true but not assigned yet. Pop all of them in reverse order on...
string AllocateTemporaryVariable()
Add a temporary variable to the current function frames local memory.
bool RelationalOperator(TokenType tokenType)
bool IsAccessChainAssignment()
Detect whether the upcoming tokens form an assignment expression.
Token LookAhead()
Get the next available token without actually increasing the tokenstream index.
Dictionary< string, bool > localVariables
OpCode RelationalOpcode(TokenType tokenType)
Variable BitwiseXor()
Bitwise XOR '^'.
Token ReadToken()
Get the next available token.
Executable Parse()
Parse the token stream into an executable.
Token LookAhead(int i)
Get the token 'n' steps forward without actually increasing the tokenstream index.
string ReadQualifiedIdentifier()
Read a dotted (qualified) identifier like: std.print or ns.io.print.
string ToLiteral(string input)
void UndoToken()
If you read a token wrong, push it back so the stream stays intact.
void Statement()
A statement can be a local variable declaration, a statement list, an expression or a keyword.
Type Derivate(Token token, Type first, Type second)
Get the resulting type of two computed types.
Dictionary< Instruction, FunctionDescriptor > forwardDeclarations
Variable Expression()
An expression is an assignment or a disjunction.
Variable Member()
Member access.
Variable Term()
Factor ( [*|/|%] Factor ).
Variable BitwiseAnd()
Bitwise AND '&'.
Stack< LoopControl > loopControl
Variable FunctionCall()
Can be a call to a forward declared Function or a Routine. To check what it is we look if it is a reg...
Variable BraceArray()
An array enclosed in braces.
Variable Factor()
Atom | Array.
void StatementList()
A list of statements. If its not a list (not in braces) just return a single statement.
Variable FunctionCall(bool background)
Call a forward declared function Push all parameter identifier onto the stack and call the function/r...
bool AssignmentOperator(TokenType tokenType)
void ReadRightParenthesis()
A lexical token or simply token is a string with an assigned and thus identified meaning.
ReadOnlyDictionary< String, Routine > Routines
A function, forward declared in a script.
An instruction in a virtual intermediate language.
static Operand MemberVariable(string identifier, object val)
static Operand Literal(object val)
static Operand AllocateInstructionPointer(Instruction instruction)
static Operand CreatePointer(string identifier, string pointer)
static Operand AllocateFunctionPointer(Function function)
static Operand AllocateRoutinePointer(Routine routine)
static Operand Variable(string identifier)
A Routine is an abstract representation of a method.
List< Type > ParameterTypes
Internal representation of a text file (source code) which can be passed to the Interpreter to execut...
TokenType
Known types of Token.
Variable(string name, Scope scope, Type derivatedType)