public string Match(TokenType token) {
     var res = TryMatch(token);
     Debug.Assert(res != null,
         "Token didnt match!");
     return res;
 }
 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);
 }
        public void MarkError(int charI, TokenType token) {
            if (charI < MaxParseChar) return;
            if (charI > MaxParseChar) {
                ExpectedTokens.Clear();
                MaxParseChar = charI;
            }
            TokenType[] expectedTokens = null;
            if (ExpectedTokens.ContainsKey(ParsingAs)) expectedTokens = ExpectedTokens[ParsingAs];
            if (expectedTokens != null) expectedTokens = expectedTokens.Concat(new[] { token }).ToArray();
            else expectedTokens = new[] { token };
            if (!ExpectedTokens.ContainsKey(ParsingAs)) ExpectedTokens.Add(ParsingAs, expectedTokens);
            else ExpectedTokens[ParsingAs] = expectedTokens;

            if (BreakOnError) {
                Debug.Assert(false,
                    "Script compile error!");
            }
        }
 public GrammarElementT(TokenType token) { TokenType = token; }
Example #5
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));

            };
        }