コード例 #1
0
        /// <summary>
        /// Operates on a Token stream using the ParsingTable
        /// </summary>
        /// <param name="tokens"></param>
        /// <param name="generateScript"></param>
        /// <returns></returns>
        public static IEnumerator <object> Execute <T>(string inputString) where T : IOrbLanguage
        {
            Debug.Log("Execute");
            //Create an instance of the language we are going to work with.
            IOrbLanguage language = (IOrbLanguage)System.Activator.CreateInstance(typeof(T));
            //Create a place to store out input tokens (nullable so null = EOF when processing)
            List <ProcessedToken?> inputTokens = null;

            //Call scan, to get our list of beginning tokens.
            yield return(OrbLexer.Scan(language, inputString, (object d) => { inputTokens = (List <ProcessedToken?>)d; }));

            Debug.Log("Scanning Finished");

            OrbUtils.PrintList <ProcessedToken?>(inputTokens);

            List <object> TERMINALS    = language.GetTERMINALS();
            List <object> nonTerminals = language.GetNonTerminals();

            ParserInstruction[][] ParseTable = language.GetParseTable();

            //The parsing stack
            List <ParseStackElement> parsingStack = new List <ParseStackElement>();

            //Place state 0 onto the stack
            parsingStack.Add(new ParseStackElement(ParseStackElement.Type.State, 0));

            //The current location in the parse
            int currencyIndicator = 0;

            //Begin the Looop!
            while (true)
            {
                yield return(null);


                Debug.Log(OrbUtils.PrintList(parsingStack, false) + "|\\|/| -> " + inputTokens[currencyIndicator]);

                ParseStackElement top = parsingStack[parsingStack.Count - 1];
                //Look at top of stack, if it is a Token, then we need to do a GoTo,
                if (top.type == ParseStackElement.Type.Token)
                {
                    //Debug.Log("GoTo");

                    //DO A GOTO
                    ParseStackElement previousState = parsingStack[parsingStack.Count - 2];

                    //Debug.Log(previousState);
                    if (previousState.type != ParseStackElement.Type.State)
                    {
                        Debug.LogError("Stack parsing has broken due to invalid GoTo");
                        yield break;
                    }

                    //Calculate the column for the Token that is on top of the stack.
                    int tokenColumn = TERMINALS.Count + top.scannedToken.tokenSymbolLocation;

                    //Push onto the stack the state we are supposed to GoTo.
                    parsingStack.Add(new ParseStackElement(ParseStackElement.Type.State, (int)ParseTable[previousState.parserStateIndex][tokenColumn].value));
                }
                else
                {
                    //Otherwise we look at the current state and the currency indiciator

                    //Get the input token we are looking at
                    ProcessedToken currentInputToken = (ProcessedToken)inputTokens[currencyIndicator];

                    //It can (should) only be a non terminal, so calculate its column on the parse table.
                    int tokenColumn = currentInputToken.tokenSymbolLocation;

                    Debug.Log(currentInputToken.data);
                    Debug.Log(tokenColumn + "/" + (nonTerminals.Count + TERMINALS.Count));
                    ParserInstruction targetInstruction = ParseTable[top.parserStateIndex][tokenColumn];

                    if (targetInstruction.instruction == ParserInstruction.Instruction.ACCEPT)
                    {
                        ProcessedToken finalToken = (ProcessedToken)parsingStack[parsingStack.Count - 2].scannedToken;
                        //Execute the final rule.
                        language.StartLangCoroutine(finalToken.rule, new CoroutineWrapper(language, finalToken, (object data) => { }));
                        break;
                    }
                    else if (targetInstruction.instruction == ParserInstruction.Instruction.SHIFT)
                    {
                        Debug.Log("Shift");
                        //If it is a shift, we put this token on the stack,
                        parsingStack.Add(new ParseStackElement(ParseStackElement.Type.Token, 0, currentInputToken));

                        //advance the currency token,
                        currencyIndicator++;

                        //then the new state on the stack.
                        parsingStack.Add(new ParseStackElement(ParseStackElement.Type.State, (int)targetInstruction.value));
                    }
                    else if (targetInstruction.instruction == ParserInstruction.Instruction.REDUCE)
                    {
                        //If it is reduce, we... reduce

                        ProductionRule productionRule = language.GetProductionRules()[targetInstruction.value];
                        int            removalCount   = productionRule.rhsSize * 2;
                        //We pop off twice as many tokens as the rhs of the reduce instruction.
                        List <ParseStackElement> poppedList = parsingStack.GetRange(parsingStack.Count - removalCount, removalCount);
                        parsingStack.RemoveRange(parsingStack.Count - removalCount, removalCount);

                        //Create a list of all of the ScannedTokens
                        List <ProcessedToken> scannedTokensList = new List <ProcessedToken>();
                        for (int i = 0; i < poppedList.Count; i++)
                        {
                            if (poppedList[i].type == ParseStackElement.Type.Token)
                            {
                                scannedTokensList.Add(poppedList[i].scannedToken);
                            }
                        }

                        //Call the appropriate operation (Performi the Reduction)
                        ProcessedToken resultingToken = new ProcessedToken(productionRule.result, productionRule.coroutineName, scannedTokensList);

                        //Put the resulting LHS token onto the stack.
                        parsingStack.Add(new ParseStackElement(ParseStackElement.Type.Token, 0, resultingToken));
                    }
                    else
                    {
                        OrbUtils.PrintList(parsingStack);
                        Debug.Log(currentInputToken);
                        inputTokens.RemoveRange(0, currencyIndicator);
                        //PrintList(inputTokens);
                        Debug.LogError("Stack parsing has broken due to invalid Instruction: " + System.Enum.GetName(typeof(ParserInstruction.Instruction), targetInstruction.instruction));
                        yield break;
                    }
                }
            }
            Debug.Log("EndExecute");
        }
コード例 #2
0
        /// <summary>
        /// Scans a string into a token stream
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static IEnumerator <object> Scan(IOrbLanguage enviroment, string input, Callback callback)
        {
            List <ProcessedToken?> tokens = new List <ProcessedToken?>();

            List <object> TERMINALS = enviroment.GetTERMINALS();

            SymbolStringTuple[] tuples = enviroment.GetRegexPairs();

            string remainder   = input;
            string text        = "";
            string testingText = "";
            Regex  regex;

            while (remainder.Length > 0)
            {
                //Debug.Log("Top of While");
                ProcessedToken?token = null;
                int            i     = 0;
                for (; i < TERMINALS.Count; i++)
                {
                    //Debug.Log("For1: " + tuples[i].str);
                    text        = "";
                    testingText = "";                     // Track the current testing string.
                    regex       = new Regex(tuples[i].str);
                    //Debug.Log(regex);
                    for (int k = 0; k < remainder.Length; k++)
                    {
                        //Debug.Log("For2: " + remainder.Length + " | " + k);
                        testingText += remainder[k];
                        if (regex.IsMatch(testingText))
                        {
                            text = testingText;                             // Store our string since we know that this is the valid string.
                            //Debug.Log("Is Match: " + regex + " => " + testingText);
                            //Create the processedtoken
                            token = new ProcessedToken(i, null, text);
                            //Execute the code for reading this token.
                            yield return(enviroment.StartLangCoroutine(tuples[i].coroutineName, new CoroutineWrapper(enviroment, (ProcessedToken)token, (object d) => { })));
                        }
                    }

                    if (token != null)
                    {
                        //Debug.Log("Breaking.");
                        break;
                    }
                }

                if (token != null)
                {
                    if (tuples[i].ignorable)
                    {
                        //We have ignored this section
                    }
                    else
                    {
                        //Debug.Log(text + " | " + token);
                        tokens.Add(token);
                    }
                    //Debug.Log("Pre<"+remainder+">");
                    remainder = remainder.Substring(text.Length);
                    //Debug.Log("Post<" + remainder + ">");
                    text = "";
                }
                else
                {
                    //Log ERROR
                    Debug.LogError("Syntax Read Error: '" + testingText + "'");
                }

                //pause before continuing
                yield return(null);
            }

            tokens.Add(null);
            callback(tokens);
        }