예제 #1
0
        /// <summary>
        /// validates whether $ variables are corresponding to valid symbols
        /// errors are added to the tree Error object.
        /// </summary>
        /// <param name="nts">non terminal and its production rule</param>
        /// <returns>a formated codeblock</returns>
        private void ValidateCodeBlock(ParseTree tree, NonTerminalSymbol nts, ParseNode node)
        {
            if (nts == null)
            {
                return;
            }
            string codeblock = nts.CodeBlock;

            Regex var = new Regex(@"\$(?<var>[a-zA-Z_0-9]+)(\[(?<index>[^]]+)\])?", RegexOptions.Compiled);

            Symbols symbols = nts.DetermineProductionSymbols();


            MatchCollection matches = var.Matches(codeblock);

            foreach (Match match in matches)
            {
                Symbol s = symbols.Find(match.Groups["var"].Value);
                if (s == null)
                {
                    tree.Errors.Add(new ParseError("Variable $" + match.Groups["var"].Value + " cannot be matched.", 0x1016, node.Token.File, node.Token.StartPos + match.Groups["var"].Index, node.Token.StartPos + match.Groups["var"].Index, match.Groups["var"].Length));
                    break; // error situation
                }
            }
        }
예제 #2
0
        protected override object EvalProduction(ParseTree tree, params object[] paramlist)
        {
            Grammar g = (Grammar)paramlist[0];

            if (Nodes[2].Nodes[0].Token.Type == TokenType.STRING)
            {
                TerminalSymbol term = g.Symbols.Find(Nodes[0].Token.Text) as TerminalSymbol;
                if (term == null)
                {
                    tree.Errors.Add(new ParseError("Symbol '" + Nodes[0].Token.Text + "' is not declared. ", 0x1040, Nodes[0]));
                }
            }
            else
            {
                NonTerminalSymbol nts = g.Symbols.Find(Nodes[0].Token.Text) as NonTerminalSymbol;
                if (nts == null)
                {
                    tree.Errors.Add(new ParseError("Symbol '" + Nodes[0].Token.Text + "' is not declared. ", 0x1041, Nodes[0]));
                }
                Rule r = (Rule)Nodes[2].Eval(tree, g, nts);
                if (nts != null)
                {
                    nts.Rules.Add(r);
                }

                if (Nodes[3].Token.Type == TokenType.CODEBLOCK)
                {
                    string codeblock = Nodes[3].Token.Text;
                    nts.CodeBlock = codeblock;
                    ValidateCodeBlock(tree, nts, Nodes[3]);

                    // beautify the codeblock format
                    codeblock     = codeblock.Substring(1, codeblock.Length - 3).Trim();
                    nts.CodeBlock = codeblock;
                }
            }
            return(g);
        }
예제 #3
0
파일: Rule.cs 프로젝트: hobdrive/TinyPG
        internal bool DetermineFirstTerminals(Symbols FirstTerminals, int index)
        {
            // indicates if Nonterminal can evaluate to an empty terminal (e.g. in case T -> a? or T -> a*)
            // in which case the parent rule should continue scanning after this nonterminal for Firsts.
            bool containsEmpty = false;             // assume terminal is found

            switch (Type)
            {
            case RuleType.Terminal:
                if (Symbol == null)
                {
                    return(true);
                }

                if (!FirstTerminals.Exists(Symbol))
                {
                    FirstTerminals.Add(Symbol);
                }
                else
                {
                    Console.WriteLine("throw new Exception(\"Terminal already exists\");");
                }
                break;

            case RuleType.NonTerminal:
                if (Symbol == null)
                {
                    return(true);
                }

                NonTerminalSymbol nts = Symbol as NonTerminalSymbol;
                containsEmpty = nts.DetermineFirstTerminals();

                // add first symbols of the nonterminal if not already added
                foreach (TerminalSymbol t in nts.FirstTerminals)
                {
                    if (!FirstTerminals.Exists(t))
                    {
                        FirstTerminals.Add(t);
                    }
                    else
                    {
                        Console.WriteLine("throw new Exception(\"Terminal already exists\");");
                    }
                }
                break;

            case RuleType.Choice:
            {
                // all subrules must be evaluated to determine if they contain first terminals
                // if any subrule contains an empty, then this rule also contains an empty
                foreach (Rule r in Rules)
                {
                    containsEmpty |= r.DetermineFirstTerminals(FirstTerminals);
                }
                break;
            }

            case RuleType.OneOrMore:
            {
                // if a non-empty subrule was found, then stop further parsing.
                foreach (Rule r in Rules)
                {
                    containsEmpty = r.DetermineFirstTerminals(FirstTerminals);
                    if (!containsEmpty)                                     // found the final set of first terminals
                    {
                        break;
                    }
                }
                break;
            }

            case RuleType.Concat:
            {
                // if a non-empty subrule was found, then stop further parsing.
                // start scanning from Index

                for (int i = index; i < Rules.Count; i++)
                {
                    containsEmpty = Rules[i].DetermineFirstTerminals(FirstTerminals);
                    if (!containsEmpty)                                     // found the final set of first terminals
                    {
                        break;
                    }
                }

                // assign this concat rule to each terminal
                foreach (TerminalSymbol t in FirstTerminals)
                {
                    t.Rule = this;
                }

                break;
            }

            case RuleType.Option:
            case RuleType.ZeroOrMore:
            {
                // empty due to the nature of this rule (A? or A* can always be empty)
                containsEmpty = true;

                // if a non-empty subrule was found, then stop further parsing.
                foreach (Rule r in Rules)
                {
                    containsEmpty |= r.DetermineFirstTerminals(FirstTerminals);
                    if (!containsEmpty)                                     // found the final set of first terminals
                    {
                        break;
                    }
                }
                break;
            }

            default:
                throw new NotImplementedException();
            }
            return(containsEmpty);
        }
예제 #4
0
        /// <summary>
        /// EvalStart will first do a semantic check to see if symbols are declared correctly
        /// then it will also check for attributes and parse the directives
        /// after that it will complete the transformation to the grammar tree.
        /// </summary>
        /// <param name="tree"></param>
        /// <param name="paramlist"></param>
        /// <returns></returns>
        protected override object EvalStart(ParseTree tree, params object[] paramlist)
        {
            TerminalSymbol terminal   = null;
            bool           StartFound = false;
            Grammar        g          = new Grammar();

            foreach (ParseNode n in Nodes)
            {
                if (n.Token.Type == TokenType.Directive)
                {
                    EvalDirective(tree, new object[] { g, n });
                }
                if (n.Token.Type == TokenType.ExtProduction)
                {
                    if (n.Nodes[n.Nodes.Count - 1].Nodes[2].Nodes[0].Token.Type == TokenType.STRING)
                    {
                        try
                        {
                            terminal = new TerminalSymbol(n.Nodes[n.Nodes.Count - 1].Nodes[0].Token.Text, (string)n.Nodes[n.Nodes.Count - 1].Nodes[2].Nodes[0].Token.Text);
                            for (int i = 0; i < n.Nodes.Count - 1; i++)
                            {
                                if (n.Nodes[i].Token.Type == TokenType.Attribute)
                                {
                                    EvalAttribute(tree, new object[] { g, terminal, n.Nodes[i] });
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            tree.Errors.Add(new ParseError("regular expression for '" + n.Nodes[n.Nodes.Count - 1].Nodes[0].Token.Text + "' results in error: " + ex.Message, 0x1020, n.Nodes[0]));
                            continue;
                        }

                        if (terminal.Name == "Start")
                        {
                            tree.Errors.Add(new ParseError("'Start' symbol cannot be a regular expression.", 0x1021, n.Nodes[0]));
                        }

                        if (g.Symbols.Find(terminal.Name) == null)
                        {
                            g.Symbols.Add(terminal);
                        }
                        else
                        {
                            tree.Errors.Add(new ParseError("Terminal already declared: " + terminal.Name, 0x1022, n.Nodes[0]));
                        }
                    }
                    else
                    {
                        NonTerminalSymbol nts = new NonTerminalSymbol(n.Nodes[n.Nodes.Count - 1].Nodes[0].Token.Text);
                        if (g.Symbols.Find(nts.Name) == null)
                        {
                            g.Symbols.Add(nts);
                        }
                        else
                        {
                            tree.Errors.Add(new ParseError("Non terminal already declared: " + nts.Name, 0x1023, n.Nodes[0]));
                        }

                        for (int i = 0; i < n.Nodes.Count - 1; i++)
                        {
                            if (n.Nodes[i].Token.Type == TokenType.Attribute)
                            {
                                EvalAttribute(tree, new object[] { g, nts, n.Nodes[i] });
                            }
                        }

                        if (nts.Name == "Start")
                        {
                            StartFound = true;
                        }
                    }
                }
            }

            if (!StartFound)
            {
                tree.Errors.Add(new ParseError("The grammar requires 'Start' to be a production rule.", 0x0024));
                return(g);
            }

            foreach (ParseNode n in Nodes)
            {
                if (n.Token.Type == TokenType.ExtProduction)
                {
                    n.Eval(tree, g);
                }
            }

            return(g);
        }