Пример #1
0
        public string TryMatch(TokenType token)
        {
            ParserUtil.IteratePastWhitespaceAndComments(source, ref Iterator);
            int len = token.Match(source, Iterator);

            if (len < 0)
            {
                return(null);
            }
            Iterator += len;
            return(source.Substring(Iterator - len, len));
        }
Пример #2
0
        public static InstructionInstance[] Parse(string source, Action <string, ErrorLevelE, int> onError)
        {
            int          iter    = 0;
            ParseContext context = new ParseContext();
            // Try to parse the code into rough tokens/instructions
            var res = Parse(source, ref iter, ParserSetup.BlockRule, context);

            ParserUtil.IteratePastWhitespaceAndComments(source, ref iter);
            // Was there more code that couldnt be parsed?
            if (res == null || iter < source.Length)
            {
                int    line     = source.Substring(0, context.MaxParseChar).Count(c => c == '\n') + 1;
                string lineData = null;
                int    at       = context.MaxParseChar;
                while (at > 0 && source[at - 1] != '\n')
                {
                    --at;
                }
                int end = source.IndexOf('\n', at);
                while (end > 0 && char.IsWhiteSpace(source[end - 1]))
                {
                    --end;
                }
                while (at < end && char.IsWhiteSpace(source[at]))
                {
                    ++at;
                }
                if (end == -1)
                {
                    end = source.Length;
                }
                lineData = source.Substring(at, end - at);
                onError(
                    "Unable to parse XScript at line " + line + " byte " + context.MaxParseChar + "\r\n" +
                    " " + lineData + "\r\n" +
                    " " + new string(Enumerable.Repeat(' ', context.MaxParseChar - at).ToArray()) + "^\r\n" +
                    "Expected:\r\n" +
                    context.ExpectedTokens.Select(k => "  As <" + k.Key.ToString() + ">:\r\n" +
                                                  "\t" + k.Value.Select(v => v.ToString()).Aggregate((s1, s2) => s1 + ", " + s2) + "\r\n"
                                                  ).Aggregate((s1, s2) => s1 + s2),
                    ErrorLevelE.Error,
                    line
                    );
            }
            // Ensure no temporary instructions are still present (starting with '+')
            var parsedInstrs = context.GetCurrentContext().Children;

            for (int i = 0; i < parsedInstrs.Count; ++i)
            {
                var instr = parsedInstrs[i];
                if (instr.Command.StartsWith("+"))
                {
                    switch (instr.Command)
                    {
                    case "+Error": onError((string)instr.Value, ErrorLevelE.Error, instr.Location.GetLineNumber(source)); break;

                    case "+Info": onError((string)instr.Value, ErrorLevelE.Info, instr.Location.GetLineNumber(source)); break;

                    case "+Warning": onError((string)instr.Value, ErrorLevelE.Warning, instr.Location.GetLineNumber(source)); break;

                    default: {
                        onError("Unexpected token " + instr.Command, ErrorLevelE.Error, instr.Location.GetLineNumber(source));
                    } break;
                    }
                }
            }
            // Begin matching internal instructions to tokens/instructions extracted
            // from the source string
            List <InstructionInstance> instrList = new List <InstructionInstance>();

            {
                var instrSet           = StackBasedVM.Instructions.Set;
                List <StackType> stack = new List <StackType>();
                // Helper method to insert instructions into the instrList array
                // without putting them at the end
                Action <int, InstructionInstance> insertInstruction = (at, instr) => {
                    instrList.Insert(at, instr);
                    for (int s = 0; s < stack.Count; ++s)
                    {
                        if (stack[s].InstructionId >= at)
                        {
                            var stackT = stack[s];
                            stackT.InstructionId++;
                            stack[s] = stackT;
                        }
                    }
                };
                // Where to read instructions from
                for (int i = 0; i < parsedInstrs.Count; ++i)
                {
                    var instr = parsedInstrs[i];
                    // We get the instruction which best matches the parameters
                    // available on the stack, when the instruction is invoked
                    // (for type safety)
                    Instruction bestInstr = null;
                    int         bestScore = 0;
                    foreach (var iSet in instrSet)
                    {
                        var instrP = iSet.Value;
                        // Must match names
                        if (instrP.Name != instr.Command)
                        {
                            continue;
                        }
                        // Calculate a score for how well the parameters match
                        int score = 100;
                        for (int p = 0; p < instrP.ConsumptionValues.Length; ++p)
                        {
                            string paramType = instrP.ConsumptionValues[p];
                            string stackType = stack[stack.Count - 1 - p].Type;
                            score = score * ParserUtil.CompareConversion(stackType, paramType) / 100;
                            if (score <= bestScore)
                            {
                                break;
                            }
                        }
                        // Is this score better than our previous score?
                        if (score <= bestScore)
                        {
                            continue;
                        }
                        bestScore = score;
                        bestInstr = instrP;
                    }
                    // No instruction was found for this token/instruction
                    if (bestInstr == null)
                    {
                        onError("Unable to find instruction for " + instr + "\r\n" +
                                (bestInstr != null ?
                                 " Best match expected (" + bestInstr.ConsumptionValues.Aggregate((s1, s2) => s1 + ", " + s2) +
                                 ") but was given (" + stack.Skip(stack.Count - bestInstr.ConsumptionValues.Length).Select(v => v.Type).Aggregate((s1, s2) => s1 + ", " + s2) + ")"
                            :
                                 " Using params (" + stack.Skip(Math.Max(stack.Count - 3, 0)).Select(v => v.Type).Aggregate((s1, s2) => s1 + ", " + s2) + ")"
                                ),
                                ErrorLevelE.Error,
                                instr.Location.GetLineNumber(source)
                                );
                        break;
                    }
                    else
                    {
                        // Are any of the parameters available on the stack incorrect?
                        // Do they need to be cast to anoter type? (ie. float to int)
                        for (int p = 0; p < bestInstr.ConsumptionValues.Length; ++p)
                        {
                            var    stackT      = stack[stack.Count - 1 - p];
                            var    toConvInstr = instrList[stackT.InstructionId];
                            string paramType   = bestInstr.ConsumptionValues[p];
                            string stackType   = stackT.Type;
                            if (paramType == stackType)
                            {
                                continue;
                            }
                            if (ParserUtil.StripStars(paramType) == "var")
                            {
                                continue;
                            }
                            // Constants can be changed at compile-time
                            if (toConvInstr.Instruction.Name == "Constant")
                            {
                                string type = ParserUtil.GetCleanTypeName(toConvInstr.Data.GetType().Name);
                                Debug.Assert(stackT.Type == type,
                                             "Stack type and constant value type must match!");
                                if (paramType == "int")
                                {
                                    toConvInstr.Data = Convert.ToInt32(toConvInstr.Data);
                                    continue;
                                }
                                else if (paramType == "real")
                                {
                                    toConvInstr.Data = (XReal)Convert.ToSingle(toConvInstr.Data);
                                    continue;
                                }
                            }
                            // Otherwise fall back to the more expensive run-time conversion
                            int score = ParserUtil.CompareConversion(stackType, paramType);
                            if (score < 100)
                            {
                                var convInstr = instrSet.FirstOrDefault(i2 => i2.Value.Type == paramType && i2.Value.Name == "Conform").Value;
                                if (convInstr == null)
                                {
                                    onError("Unable to find conversion from " + stackType + " to " + paramType,
                                            ErrorLevelE.Warning,
                                            instr.Location.GetLineNumber(source));
                                    continue;
                                }
                                insertInstruction(stackT.InstructionId + 1, new InstructionInstance()
                                {
                                    Instruction = convInstr,
                                    Data        = stackType + "2" + paramType
                                });
                            }
                        }
                        // Simulate executing the instruction to maintain our
                        // faux stack, so next instructions can get the correct
                        // instruction for the expected types
                        Debug.Assert(bestInstr != null,
                                     "Unable to find matching instruction!");
                        int    toRemove = bestInstr.ConsumptionValues.Length;
                        string retVal   = bestInstr.ReturnValues.Length > 0 ? bestInstr.ReturnValues[0] : "void";
                        int    retStars = ParserUtil.CountStars(retVal);
                        if (retStars > 0)
                        {
                            retVal = retVal.Substring(0, retVal.Length - retStars);
                        }
                        if (retVal == "var")
                        {
                            retVal = ParserUtil.StripStars(instr.Type);
                            if (retVal == "auto")
                            {
                                retVal = "var";
                            }
                        }
                        if (retVal == "var" && toRemove > 0)
                        {
                            retVal = ParserUtil.StripStars(stack[stack.Count - 1].Type);
                        }
                        else if (retStars > 0)
                        {
                            retVal = ParserUtil.AddStars(retVal, retStars);
                        }
                        if (toRemove > 0)
                        {
                            stack.RemoveRange(stack.Count - toRemove, toRemove);
                        }
                        if (retVal != "void")
                        {
                            stack.Add(new StackType(instrList.Count, retVal));
                        }

                        instrList.Add(new InstructionInstance()
                        {
                            Instruction = bestInstr,
                            Data        = instr.Value,
                        });
                    }
                }
                Debug.Assert(stack.Count == 0,
                             "Stack is not balanced!");
            }
            // Our parser wraps the entire file in a block, remove this block
            // so that global variables are not cleaned up after execution
            if (instrList.Count > 0)
            {
                Debug.Assert(instrList[0].Instruction.Name == "BlockStart",
                             "Script should be contained within a block");
                Debug.Assert(instrList[instrList.Count - 1].Instruction.Name == "BlockEnd",
                             "Script should be contained within a block");
                instrList.RemoveAt(0);
                instrList.RemoveAt(instrList.Count - 1);
            }
            return(instrList.ToArray());
            //context.BreakOnError = true;
            //res = Parse(str, ref iter, blockRule, context);
        }
Пример #3
0
        // Called recursively to generate tokens/instructions from a source code string
        public static IEnumerable <string> Parse(string source, ref int sourceI, GrammarElement element, ParseContext context)
        {
            IEnumerable <string> res = null;

            if (element is GrammarElementA)
            {
                var elA  = element as GrammarElementA;
                int iter = sourceI;
                using (var level = context.GetCurrentContext()) {
                    for (int e = 0; e < elA.Elements.Length; ++e)
                    {
                        var ok = Parse(source, ref iter, elA.Elements[e], context);
                        if (ok == null)
                        {
                            level.RemoveChanges();
                            return(null);
                        }
                        if (res == null)
                        {
                            res = ok;
                        }
                        else
                        {
                            res = res.Concat(ok);
                        }
                    }
                }
                sourceI = iter;
            }
            else if (element is GrammarElementO)
            {
                var elA = element as GrammarElementO;
                for (int e = 0; e < elA.Elements.Length; ++e)
                {
                    int iter = sourceI;
                    var ok   = Parse(source, ref iter, elA.Elements[e], context);
                    if (ok != null)
                    {
                        sourceI = iter; res = ok; break;
                    }
                }
            }
            else if (element is GrammarElementT)
            {
                ParserUtil.IteratePastWhitespaceAndComments(source, ref sourceI);
                var elA   = element as GrammarElementT;
                var token = elA.TokenType;
                int match = token.Match(source, sourceI);
                if (match < 0)
                {
                    context.MarkError(sourceI, token);
                    return(null);
                }
                sourceI += match;
                return(new string[] { token.Name });
            }
            else if (element is GrammarElementR)
            {
                var elA  = element as GrammarElementR;
                var rule = elA.Rule;

                ParserUtil.IteratePastWhitespaceAndComments(source, ref sourceI);
                int  sourceS    = sourceI;
                int  iter       = sourceI;
                bool isImplicit = rule.Name == "Implicit";
                isImplicit = false;
                ParseContext.Level level = new ParseContext.Level();
                if (!isImplicit)
                {
                    context.PushRule(rule);
                    level = context.GetCurrentContext();
                }
                for (int r = 1; r <= rule.Cardinality.To; ++r)
                {
                    if (!isImplicit)
                    {
                        level.ClearChildren();
                    }
                    var ok = Parse(source, ref iter, rule.Element, context);
                    if (ok != null)
                    {
                        if (!isImplicit)
                        {
                            if (rule.Build != null)
                            {
                                SourceIterator sourceIter = new SourceIterator(source, sourceI, iter);
                                rule.Build(level, sourceIter);
                            }
                            else
                            {
                                level.PassThrough();
                            }
                        }
                        if (r >= rule.Cardinality.From)
                        {
                            if (res == null)
                            {
                                res = ok;
                            }
                            else
                            {
                                res = res.Concat(ok);
                            }
                            sourceI = iter;
                        }
                    }
                    else
                    {
                        break;
                    }
                }
                if (res == null && rule.Cardinality.From == 0)
                {
                    res = new string[] { };
                }
                if (!isImplicit)
                {
                    context.PopRule(rule);
                    if (res == null)
                    {
                        level.RemoveChanges();
                    }
                    level.Dispose();
                }
            }
            return(res);
        }
Пример #4
0
        static ParserSetup()
        {
            // Create our language grammar
            TokenType emptyToken        = new TokenType("~", (str, b) => 0);
            TokenType ifToken           = new TokenType("if", "^(if)");
            TokenType elseToken         = new TokenType("else", "^(else)");
            TokenType forToken          = new TokenType("for", "^(for)");
            TokenType flowControlToken  = new TokenType("break", "^(break|continue|return)");
            TokenType paramStartToken   = new TokenType("(", "^[(]");
            TokenType paramEndToken     = new TokenType(")", "^[)]");
            TokenType blockStartToken   = new TokenType("{", "^[{]");
            TokenType blockEndToken     = new TokenType("}", "^[}]");
            TokenType typeToken         = new TokenType("type", "^(int|float|double|bool|string|void|class|fn|var)");
            TokenType nameToken         = new TokenType("name", "^[a-zA-Z_][a-zA-Z0-9_]*");
            TokenType numberToken       = new TokenType("const", "^[0-9]+(\\.[0-9]*)?[f]?");
            TokenType stringToken       = new TokenType("const", "^\"(\\.|[^\"])*\"");
            TokenType boolToken         = new TokenType("const", "^(true|false)");
            TokenType charToken         = new TokenType("const", "^['][\\\\]?.[']");
            TokenType commaToken        = new TokenType(",", "^[,]");
            TokenType endStatementToken = new TokenType(";", "^[;]");
            TokenType assignToken       = new TokenType("=", "^[=]");
            TokenType andOrToken        = new TokenType("oper", "^(&&|\\|\\|)");
            TokenType mulDivToken       = new TokenType("MulDiv", "^[*/]");
            TokenType addSubToken       = new TokenType("AddSub", "^[+\\-]");
            TokenType operatorToken     = new TokenType("oper", "^[*+\\-/^]");
            TokenType comparitorToken   = new TokenType("compar", "^[<>=][=]?");
            TokenType unaryToken        = new TokenType("unary", "^[+-]");
            TokenType increment         = new TokenType("incr", "^(\\+\\+|\\-\\-)");

            GrammarRule emptyRule = new GrammarRule("Empty", emptyToken);
            //GrammarRule semicolonRule = new GrammarRule("Semicolon", endStatementToken);
            GrammarRule variableRule         = new GrammarRule("Variable");
            GrammarRule constantRule         = new GrammarRule("Constant");
            GrammarRule ifRule               = new GrammarRule("If");
            GrammarRule forRule              = new GrammarRule("For");
            GrammarRule flowControlRule      = new GrammarRule("Flow", flowControlToken);
            GrammarRule blockOrStatementRule = new GrammarRule("BOS");
            GrammarRule statementRule        = new GrammarRule("Statement");
            GrammarRule assignmentRule       = new GrammarRule("Assignment");
            GrammarRule vAssignmentRule      = new GrammarRule("VAssignment");
            GrammarRule callRule             = new GrammarRule("Call");
            GrammarRule termRule             = new GrammarRule("Term");
            GrammarRule equationRule         = new GrammarRule("Equation");
            GrammarRule andOrRule            = new GrammarRule("AndOr");
            GrammarRule mulDivRule           = new GrammarRule("MulDiv");
            GrammarRule addSubRule           = new GrammarRule("AddSub");
            GrammarRule compareRule          = new GrammarRule("Compare");
            GrammarRule paramRule            = new GrammarRule("Parameter");
            GrammarRule parmsRule            = new GrammarRule("Parameters");
            GrammarRule vDeclrRule           = new GrammarRule("VDeclr");
            GrammarRule fDeclrRule           = new GrammarRule("FDeclr");

            blockRule = new GrammarRule("Block");
            GrammarRule rValueRule    = new GrammarRule("RValue", equationRule);
            GrammarRule conditionRule = new GrammarRule("Condition", equationRule);

            constantRule.SetElements(numberToken | stringToken | charToken | boolToken);
            variableRule.SetElements(nameToken);        // TODO: ++ operator should be here

            blockOrStatementRule.SetElements((blockStartToken & blockRule & blockEndToken) | (statementRule));
            GrammarRule elseRule = null;

            ifRule.SetElements(ifToken & paramStartToken & conditionRule & paramEndToken &
                               blockOrStatementRule &
                               ((elseRule = (
                                     elseToken & (
                                         blockOrStatementRule |
                                         ifRule
                                         )
                                     )) | emptyRule)
                               );
            GrammarRule forConditionRule = null;

            forRule.SetElements(forToken & paramStartToken &
                                (statementRule | emptyRule) &
                                (forConditionRule = ((comparitorToken & equationRule) | emptyRule)) &
                                paramEndToken &
                                blockOrStatementRule
                                );
            assignmentRule.SetElements(assignToken & rValueRule);
            vAssignmentRule.SetElements(nameToken & assignmentRule);
            callRule.SetElements(nameToken & paramStartToken & parmsRule & paramEndToken);
            GrammarRule unaryRule = null;

            termRule.SetElements(
                unaryRule = ((unaryToken | emptyRule) & (
                                 (increment & variableRule) | (variableRule & increment) |
                                 callRule | constantRule | variableRule | (paramStartToken & equationRule & paramEndToken)
                                 ))
                );
            GrammarRule andOrOperRule  = null;
            GrammarRule mulDivOperRule = null;
            GrammarRule addSubOperRule = null;
            GrammarRule compOperRule   = null;

            andOrRule.SetElements(compareRule & ((andOrOperRule = andOrToken & andOrRule) | emptyRule));
            mulDivRule.SetElements(termRule & ((mulDivOperRule = mulDivToken & mulDivRule) | emptyRule));
            addSubRule.SetElements(mulDivRule & ((addSubOperRule = addSubToken & addSubRule) | emptyRule));
            compareRule.SetElements(addSubRule & ((compOperRule = comparitorToken & compareRule) | emptyRule));
            equationRule.SetElements(andOrRule);
            paramRule.SetElements(rValueRule);
            parmsRule.SetElements(
                (paramRule & (commaToken & paramRule)[0, 1000]) |
                emptyRule
                );
            vDeclrRule.SetElements(typeToken & nameToken & (assignmentRule | emptyToken));
            GrammarRule pDeclrRule = new GrammarRule("PDeclr");
            GrammarRule pArrRule   = new GrammarRule("PArr");

            pDeclrRule.SetElements(typeToken & nameToken & (assignmentRule | emptyToken));
            pArrRule.SetElements(pDeclrRule & ((commaToken & pArrRule) | emptyToken));
            fDeclrRule.SetElements(typeToken & nameToken & paramStartToken &
                                   (pArrRule | typeToken | emptyRule) &
                                   paramEndToken & blockStartToken & blockRule & blockEndToken
                                   );
            GrammarRule nerfReturnRules = (
                (fDeclrRule) |
                (vDeclrRule & endStatementToken) |
                (vAssignmentRule & endStatementToken) |
                (callRule & endStatementToken) |
                (termRule & endStatementToken)
                );

            statementRule.SetElements(
                ifRule |
                forRule |
                (flowControlRule & endStatementToken) |
                nerfReturnRules
                );
            blockRule.SetElements(new GrammarRule(statementRule)[0, 1000]);

            int uid = 0;

            // Setup how these grammars are built into instructions
            unaryRule.Build += delegate(ParseContext.Level context, SourceIterator source) {
                string unary = source.TryMatch(unaryToken);
                context.PassThrough();
                if (unary == "-")
                {
                    context.Store.Add(new InstructionItem("Constant", "int", -1, source.From));
                    context.Store.Add(new InstructionItem("Mul", "auto", "unary", source.From));
                }
            };
            constantRule.Build += delegate(ParseContext.Level context, SourceIterator source) {
                string data = source.SourceCode;
                if (numberToken.Match(data, 0) >= 0)
                {
                    if (data.Contains('.'))
                    {
                        context.Store.Add(new InstructionItem("Constant", "real", XReal.Parse(data), source.From));
                    }
                    else
                    {
                        context.Store.Add(new InstructionItem("Constant", "int", int.Parse(data), source.From));
                    }
                }
                else if (stringToken.Match(data, 0) >= 0)
                {
                    context.Store.Add(new InstructionItem("Constant", "string", ParserUtil.UnescapeString(data), source.From));
                }
                else if (boolToken.Match(data, 0) >= 0)
                {
                    context.Store.Add(new InstructionItem("Constant", "bool", data == "true", source.From));
                }
                else if (charToken.Match(data, 0) >= 0)
                {
                    context.Store.Add(new InstructionItem("Constant", "char", data[1], source.From));
                }
            };
            variableRule.Build += delegate(ParseContext.Level context, SourceIterator source) {
                context.Store.Add(new InstructionItem("Variable", "auto", source.Match(nameToken), source.From));
            };
            vDeclrRule.Build += delegate(ParseContext.Level context, SourceIterator source) {
                string type = ParserUtil.GetCleanTypeName(source.Match(typeToken));
                string name = source.Match(nameToken);
                context.Store.Add(new InstructionItem("+Allocate", type, name, source.From));
                context.Store.Add(new InstructionItem("Reference", type + "*", name, source.From));     // Needs to be here because it gets popped if not used
                if (context.Children.Count > 0)
                {
                    context.PassThrough();
                    //context.Store.Add(new InstructionItem("Conform", type, type));
                    context.Store.Add(new InstructionItem("Assign", type, "~" + name, source.From));
                }
            };
            nerfReturnRules.Build += delegate(ParseContext.Level context, SourceIterator source) {
                context.PassThrough();
                context.Store.Add(new InstructionItem("Pop", "void", null, source.From));
            };
            vAssignmentRule.Build += delegate(ParseContext.Level context, SourceIterator source) {
                string name = source.Match(nameToken);
                context.Store.Add(new InstructionItem("Reference", "auto*", name, source.From));
                context.PassThrough();
                //context.Store.Add(new InstructionItem("Conform", "auto", "auto", source.From));
                context.Store.Add(new InstructionItem("Assign", "auto", "~" + name, source.From));
            };
            Func <string, int, InstructionItem> GetInstructionFromString = (oper, loc) => {
                switch (oper)
                {
                case "&&": return(new InstructionItem("And", "bool", oper, loc));

                case "||": return(new InstructionItem("Or", "bool", oper, loc));

                case "<=": return(new InstructionItem("LEqual", "bool", oper, loc));

                case ">=": return(new InstructionItem("GEqual", "bool", oper, loc));

                case "<": return(new InstructionItem("Less", "bool", oper, loc));

                case ">": return(new InstructionItem("Greater", "bool", oper, loc));

                case "==": return(new InstructionItem("IsEqual", "bool", oper, loc));

                case "!=": return(new InstructionItem("IsNEqual", "bool", oper, loc));

                case "+": return(new InstructionItem("Add", "auto", oper, loc));

                case "-": return(new InstructionItem("Sub", "auto", oper, loc));

                case "*": return(new InstructionItem("Mul", "auto", oper, loc));

                case "/": return(new InstructionItem("Div", "auto", oper, loc));
                }
                return(new InstructionItem("+Error", "auto", "Unable to find operator for '" + oper + "'", loc));
            };

            andOrOperRule.Build += delegate(ParseContext.Level context, SourceIterator source) {
                string oper = source.TryMatch(andOrToken);
                context.PassThrough();
                context.Store.Add(GetInstructionFromString(oper, source.From));
            };
            mulDivOperRule.Build += delegate(ParseContext.Level context, SourceIterator source) {
                string oper = source.TryMatch(operatorToken);
                context.PassThrough();
                context.Store.Add(GetInstructionFromString(oper, source.From));
            };
            addSubOperRule.Build += mulDivOperRule.Build;
            compOperRule.Build   += delegate(ParseContext.Level context, SourceIterator source) {
                string oper = source.TryMatch(comparitorToken);
                context.PassThrough();
                context.Store.Add(GetInstructionFromString(oper, source.From));
            };

            paramRule.Build += delegate(ParseContext.Level context, SourceIterator source) {
                context.Store.Add(new InstructionItem("+Param", null, null, source.From));
                context.PassThrough();
            };
            callRule.Build += delegate(ParseContext.Level context, SourceIterator source) {
                string name   = source.Match(nameToken);
                int    paramC = 0;
                for (int c = 0; c < context.Children.Count; ++c)
                {
                    var child = context.Children[c];
                    if (child.Command == "+Param")
                    {
                        paramC++;
                    }
                    else
                    {
                        context.Store.Add(child);
                    }
                }
                //context.PassThrough();
                context.Store.Add(new InstructionItem("Call" + paramC, "auto", name, source.From));
            };
            statementRule.Build += delegate(ParseContext.Level context, SourceIterator source) {
                /*for (int c = 0; c < context.Children.Count; ++c) {
                 *  Debug.Assert(context.Children[c].Value != null,
                 *      "All statements should be converted to instructions!");
                 * }*/
                context.PassThrough();
                //context.Store.Add(new InstructionItem("RemoveItemIfNotVoid", "void", null, source.From));
            };
            conditionRule.Build += delegate(ParseContext.Level context, SourceIterator source) {
                context.PassThrough();
                context.Store.Add(new InstructionItem("+CondEnd", source.From));
            };
            pDeclrRule.Build += delegate(ParseContext.Level context, SourceIterator source) {
                string type = ParserUtil.GetCleanTypeName(source.Match(typeToken));
                string name = source.Match(nameToken);
                FInternal.Parameter param = new FInternal.Parameter();
                if (context.Children.Count > 0)
                {
                    Debug.Assert(context.Children.Count == 1 && context.Children[0].Command == "Constant",
                                 "Parameter types must be constant");
                    param.Default = context.Children[0].Value;
                }
                param.Name = name;
                context.Store.Add(new InstructionItem("+Parameter", type, param, source.From));
                // Do nothing
            };
            fDeclrRule.Build += delegate(ParseContext.Level context, SourceIterator source) {
                string type = ParserUtil.GetCleanTypeName(source.Match(typeToken));
                string name = source.Match(nameToken);
                int    id   = (++uid);
                context.Store.Add(new InstructionItem("+Allocate", "fn", name, source.From));
                context.Store.Add(new InstructionItem("Reference", "fn*", name, source.From));

                var fn = new FInternal()
                {
                    Name = name + id
                };
                List <FInternal.Parameter> parms = new List <FInternal.Parameter>();
                context.Store.Add(new InstructionItem("Function", "fn", fn, source.From));
                context.Store.Add(new InstructionItem("Marker", "void", name + id + "_start", source.From));
                for (int c = 0; c < context.Children.Count; ++c)
                {
                    var child = context.Children[c];
                    if (child.Command == "+Parameter")
                    {
                        parms.Add((FInternal.Parameter)child.Value);
                    }
                    else if (child.Command == "+Return")
                    {
                        context.Store.Add(new InstructionItem("Constant", "int", 0, source.From));
                        context.Store.Add(new InstructionItem("Return", "fn", name + id, source.From));
                    }
                    else
                    {
                        context.Store.Add(child);
                    }
                }
                fn.Parameters = parms.ToArray();
                //context.PassThrough();
                context.Store.Add(new InstructionItem("Constant", "int", 0, source.From));
                context.Store.Add(new InstructionItem("Return", "fn", name + id, source.From));
                context.Store.Add(new InstructionItem("Marker", "void", name + id + "_end", source.From));

                context.Store.Add(new InstructionItem("Assign", "fn", "~" + name, source.From));
            };
            forConditionRule.Build += (level, source) => {
                level.Store.Add(new InstructionItem("+ContBeg", source.From));
                string comparison = source.TryMatch(comparitorToken);
                level.PassThrough();
                if (comparison != null)
                {
                    level.Store.Add(GetInstructionFromString(comparison, source.From));
                }
                level.Store.Add(new InstructionItem("+ContEnd", source.From));
            };
            forRule.Build += delegate(ParseContext.Level context, SourceIterator source) {
                int id      = (++uid);
                int contBeg = context.FindIndexInChildrenOnce("+ContBeg");
                int contEnd = context.FindIndexInChildrenOnce("+ContEnd");
                int varRef  = context.FindIndexInChildrenOnce("Reference", contBeg);
                Debug.Assert(varRef >= 0,
                             "A single assignment should exist before the condition");
                var    varRefI = context.Children[varRef];
                string varName = (string)varRefI.Value;
                string varType = ParserUtil.StripStars(varRefI.Type);
                int    arAloc  = context.FindIndexInChildrenOnce("Allocate", varRef);
                if (arAloc >= 0)
                {
                    Debug.Assert(context.Children[arAloc].Value.Equals(varRefI.Value),
                                 "Assumption that the allocation and reference will always be the same value");
                }
                else
                {
                    if (varType == "auto")
                    {
                        varType = "int";
                    }
                    context.Store.Add(new InstructionItem("+AllocateIfRequired", varType, varName, source.From));
                }
                context.PassRange(0, contBeg);
                context.Store.Add(new InstructionItem("Marker", "void", "for" + id + "_beg", source.From));
                context.Store.Add(new InstructionItem("Variable", varType, varName, source.From));
                context.PassRange(contBeg + 1, contEnd);
                context.Store.Add(new InstructionItem("JumpIfFalse", "void", "for" + id + "_end", source.From));
                for (int c = contEnd + 1; c < context.Children.Count; ++c)
                {
                    var child = context.Children[c];
                    if (child.Command == "+Break")
                    {
                        child = new InstructionItem("JumpTo", "void", "for" + id + "_end", child.Location);
                    }
                    else if (child.Command == "+Continue")
                    {
                        child = new InstructionItem("JumpTo", "void", "for" + id + "_inc", child.Location);
                    }
                    context.Store.Add(child);
                }
                //context.PassRange(contEnd + 1, context.Children.Count);
                context.Store.Add(new InstructionItem("Marker", "void", "for" + id + "_inc", source.From));
                context.Store.Add(new InstructionItem("Reference", "int*", varRefI.Value, source.From));
                context.Store.Add(new InstructionItem("Variable", "int", varRefI.Value, source.From));
                context.Store.Add(new InstructionItem("Constant", "int", 1, source.From));
                context.Store.Add(new InstructionItem("Add", "int", "", source.From));
                context.Store.Add(new InstructionItem("Assign", "int", "~" + (string)varRefI.Value, source.From));
                context.Store.Add(new InstructionItem("Pop", "void", "", source.From));
                context.Store.Add(new InstructionItem("JumpTo", "void", "for" + id + "_beg", source.From));
                context.Store.Add(new InstructionItem("Marker", "void", "for" + id + "_end", source.From));
            };
            flowControlRule.Build += delegate(ParseContext.Level context, SourceIterator source) {
                Debug.Assert(context.Children.Count == 0,
                             "For control statements dont support child elements, yet.");
                context.PassThrough();
                string flow = source.Match(flowControlToken);
                switch (flow)
                {
                case "break": context.Store.Add(new InstructionItem("+Break", source.From)); break;

                case "continue": context.Store.Add(new InstructionItem("+Continue", source.From)); break;

                case "return": context.Store.Add(new InstructionItem("+Return", source.From)); break;
                }
            };
            ifRule.Build += delegate(ParseContext.Level context, SourceIterator source) {
                int id        = (++uid);
                int condEnd   = context.FindIndexInChildrenOnce("+CondEnd");
                int elseStart = context.FindIndexInChildrenOnce("+Else");
                int elseEnd   = context.FindIndexInChildrenOnce("+EndElse");
                context.PassRange(0, condEnd);
                context.Store.Add(new InstructionItem("JumpIfFalse", "void", "if" + id, source.From));
                if (elseStart >= 0)
                {
                    Debug.Assert(elseEnd >= 0,
                                 "Else needs to have a start and end!");
                    context.PassRange(condEnd + 1, elseStart);
                    context.Store.Add(new InstructionItem("JumpTo", "void", "if_else" + id, source.From));
                    context.Store.Add(new InstructionItem("Marker", "void", "if" + id, source.From));
                    context.PassRange(elseStart + 1, elseEnd);
                    context.Store.Add(new InstructionItem("Marker", "void", "if_else" + id, source.From));
                }
                else
                {
                    context.PassRange(condEnd + 1, context.Children.Count);
                    context.Store.Add(new InstructionItem("Marker", "void", "if" + id, source.From));
                }
                Debug.Assert(condEnd >= 0,
                             "Unable to determine where condition ends!");
            };

            elseRule.Build += delegate(ParseContext.Level context, SourceIterator source) {
                int id = (++uid);
                context.Store.Add(new InstructionItem("+Else", "void", id, source.From));
                context.PassThrough();
                context.Store.Add(new InstructionItem("+EndElse", "void", id, source.From));
            };

            blockRule.Build += delegate(ParseContext.Level context, SourceIterator source) {
                var instructions = context.Children;
                var destination  = context.Store;
                Dictionary <string, string> name2Type = new Dictionary <string, string>();

                destination.Add(new InstructionItem("BlockStart", "void", null, source.From));

                int destStart = destination.Count;

                for (int i = 0; i < instructions.Count; ++i)
                {
                    var instr = instructions[i];
                    if (instr.Command == "+AllocateIfRequired")
                    {
                        Debug.Assert(instr.Type != "auto",
                                     "Cant allocate a variable of unknown type!");
                        Debug.Assert(instr.Value is String,
                                     "Variable names should be strings!");
                        string name = (String)instr.Value;
                        if (!name2Type.ContainsKey(name))
                        {
                            name2Type.Add(name, instr.Type);
                        }
                    }
                    else if (instr.Command == "+Allocate")
                    {
                        Debug.Assert(instr.Type != "auto",
                                     "Cant allocate a variable of unknown type!");
                        Debug.Assert(instr.Value is String,
                                     "Variable names should be strings!");
                        string name = (String)instr.Value;
                        if (!name2Type.ContainsKey(name))
                        {
                            name2Type.Add(name, instr.Type);
                        }
                    }
                    else if (instr.Command == "Assign")
                    {
                        string name = ((String)instr.Value).Substring(1);
                        if (name2Type.ContainsKey(name))
                        {
                            instr.Type = name2Type[name];
                        }
                        //else instr.Type = "var";
                        destination.Add(instr);
                    }
                    else if (instr.Command == "Reference" || instr.Command == "Variable")
                    {
                        Debug.Assert(instr.Value is String,
                                     "Variable names should be strings!");
                        string name  = (String)instr.Value;
                        string stars = (instr.Command == "Variable" ? "" : "*");
                        if (instr.Type == "auto" + stars && name2Type.ContainsKey(name))
                        {
                            instr.Type = name2Type[(String)instr.Value] + stars;
                        }
                        destination.Add(instr);
                    }
                    else if (instr.Command.StartsWith("Call") && instr.Type == "auto")
                    {
                        instr.Type = "var";
                        destination.Add(instr);
                    }
                    else
                    {
                        destination.Add(instr);
                    }
                }
                foreach (var n2t in name2Type)
                {
                    destination.Insert(destStart, new InstructionItem("Allocate", n2t.Value, n2t.Key, source.From));
                }

                destination.Add(new InstructionItem("BlockEnd", "void", null, source.From));
            };
        }