예제 #1
0
        public void SingleToken()
        {
            var grammar  = $@"
abc = ""abc"";

root = abc;
";
            var settings = new ParserSettings
            {
                Algorithm   = Parser.Algorithm.LL,
                NestingType = Parser.NestingType.Stack,
                Unit        = Parser.Unit.Character,
            };
            Parser parser = parserGen.SpawnParser(settings, grammar);

            parser.AttachAction("abc", (branch, recurse) =>
            {
                var value      = branch.Leaf.MatchedText;
                var startIndex = branch.Leaf.StartIndex;

                return(new LeafSemanticNode(0, startIndex, value));
            });

            parser.AttachAction("root", (branch, recurse) =>
            {
                return(recurse(branch.GetDescendant(0)));
            });

            parser.Lock();

            ISemanticNode result = parser.Parse("abc");
        }
예제 #2
0
        public void Ebnf()
        {
            var parserGen = new ParserGenerator();

            var grammar  = $@"
{RuleName.Equals} = ""="";
{RuleName.Pipe} = ""|"";
{RuleName.Asterisk} = ""*"";
{RuleName.QuestionMark} = ""?"";
{RuleName.ExclamationPoint} = ""!"";
{RuleName.Semicolon} = "";"";
{RuleName.LeftParenthesis} = ""("";
{RuleName.RightParenthesis} = "")"";

{RuleName.Whitespace} = /\s+/;
{RuleName.Identifier} = /\w(?:\w|\d)*/;
{RuleName.String} = /""(\\\\[^""]|\\\\""|[^""])*""/;
{RuleName.Regex} = /\/(\\\\[^\/]|\\\\\/|[^\/])+\//;
{RuleName.LineComment} = /\/\/[^{"\r\n"}]*(?=[{"\r\n"}])/;

{RuleName.And} = {RuleName.SimpleExpression} {RuleName.Expression};
{RuleName.Or} = {RuleName.SimpleExpression} {RuleName.Pipe} {RuleName.Expression};
{RuleName.Not} = {RuleName.ExclamationPoint} {RuleName.Expression};
{RuleName.Optional} = {RuleName.QuestionMark} {RuleName.Expression};
{RuleName.Repeat} = {RuleName.Asterisk} {RuleName.Expression};
{RuleName.Group} = {RuleName.LeftParenthesis} {RuleName.Expression} {RuleName.RightParenthesis};

{RuleName.Literal} = {RuleName.String} | {RuleName.Regex};
{RuleName.SimpleExpression} = {RuleName.Not} | {RuleName.Optional} | {RuleName.Repeat} | {RuleName.Group} | {RuleName.Identifier};
{RuleName.Expression} = {RuleName.Or} | {RuleName.And} | {RuleName.SimpleExpression};

{RuleName.Token} = {RuleName.Identifier} {RuleName.Equals} {RuleName.Literal} {RuleName.Semicolon};
{RuleName.Rule} = {RuleName.Identifier} {RuleName.Equals} {RuleName.Expression} {RuleName.Semicolon};

// This is a comment.
{RuleName.Root} = *({RuleName.Token} | {RuleName.Rule});
";
            var settings = new ParserSettings
            {
                Algorithm   = Parser.Algorithm.LL,
                NestingType = Parser.NestingType.Recursion,
                Unit        = Parser.Unit.Lexeme,
            };
            Parser parser = parserGen.SpawnParser(settings, grammar, RuleName.Whitespace, RuleName.LineComment);

            parser.Lock();

            BranchParseNode result = parser.ParseSyntax(grammar);

            Assert.AreEqual(grammar, result.MatchedText);
        }
예제 #3
0
        public CommandParser(Parameters parameters)
        {
            command = new Command("", parameters);

            var grammar = $@"
equals = ""="";

shortOptions = /(?<= )-[_\w]+/;
shortOption = /(?<= )-[_\w]/;
longOption = /(?<= )--[_\w][-_\w]*/;
endOptions = /(?<= )--(?= )/;
doubleString = /""(?:\\\\""|\\\\[^""]|[^""\\\\])*""/;
singleString = /'(?:\\\\'|\\\\[^']|[^'\\\\])*'/;
identifier = /[_\w][-_\w]*/;
literal = /.+/;
ws = /\s+/;
path = /(([A-Za-z]:)?[\/\\\\])?[-_\\w.]+([\/\\\\][-_\\w.]+)*[\/\\\\]?/;

string = doubleString | singleString;
shortOptionWithValue = shortOption equals (identifier | string);
longOptionWithValue = longOption equals (identifier | string);

options = *(shortOptionWithValue | longOptionWithValue | shortOptions | longOption | identifier | string);

details = options ?(endOptions literal);

root = (string | path) ?details;
";

            var parserGen = new ParserGenerator();
            var settings  = new ParserSettings
            {
                Algorithm   = Algorithm.LL,
                NestingType = NestingType.Stack,
                Unit        = Unit.Character,
            };

            parser = parserGen.SpawnParser(settings, grammar, "ws");

            parser.AttachAction("shortOptions", (branch, recurse) =>
            {
                var startIndex = branch.Leaf.StartIndex;
                IEnumerable <BranchSemanticNode> nodes = branch.Leaf.MatchedText
                                                         .Skip(1)
                                                         .Select((c, i) =>
                {
                    return(new BranchSemanticNode((int)CommandNodeType.Argument,
                                                  new LeafSemanticNode((int)CommandNodeType.ShortOption, startIndex + 1 + i, c.ToString())));
                });

                return(new BranchSemanticNode((int)CommandNodeType.Arguments, startIndex, nodes));
            });

            parser.AttachAction("shortOption", (branch, recurse) =>
            {
                LeafParseNode nameNode = branch.Leaf;
                var startIndex         = nameNode.StartIndex;
                var name = nameNode.MatchedText[1].ToString();

                return(new BranchSemanticNode((int)CommandNodeType.Argument,
                                              new LeafSemanticNode((int)CommandNodeType.ShortOption, startIndex, name)));
            });

            parser.AttachAction("shortOptionWithValue", (branch, recurse) =>
            {
                LeafParseNode nameNode = branch.GetDescendant(0).Leaf;
                var startIndex         = nameNode.StartIndex;
                var name            = nameNode.MatchedText[1].ToString();
                ISemanticNode value = recurse(branch.GetDescendant(2));

                return(new BranchSemanticNode((int)CommandNodeType.Argument,
                                              new LeafSemanticNode((int)CommandNodeType.ShortOption, startIndex, name),
                                              value));
            });

            parser.AttachAction("longOption", (branch, recurse) =>
            {
                LeafParseNode nameNode = branch.Leaf;
                var startIndex         = nameNode.StartIndex;
                var name = nameNode.MatchedText.Substring(2);

                return(new BranchSemanticNode((int)CommandNodeType.Argument,
                                              new LeafSemanticNode((int)CommandNodeType.LongOption, startIndex, name)));
            });

            parser.AttachAction("longOptionWithValue", (branch, recurse) =>
            {
                LeafParseNode nameNode = branch.GetDescendant(0).Leaf;
                var startIndex         = nameNode.StartIndex;
                var name            = nameNode.MatchedText.Substring(2);
                ISemanticNode value = recurse(branch.GetDescendant(2));

                return(new BranchSemanticNode((int)CommandNodeType.Argument,
                                              new LeafSemanticNode((int)CommandNodeType.LongOption, startIndex, name),
                                              value));
            });

            parser.AttachAction("identifier", (branch, recurse) =>
            {
                LeafParseNode nameNode = branch.Leaf;
                var startIndex         = nameNode.StartIndex;
                var name = nameNode.MatchedText;

                return(new LeafSemanticNode((int)CommandNodeType.String, startIndex, name));
            });

            parser.AttachAction("doubleString", (branch, recurse) =>
            {
                var text = branch.Leaf.MatchedText;
                text     = text
                           .Substring(1, text.Length - 2)
                           .Replace(@"\\", @"\")
                           .Replace(@"\""", @"""");
                var startIndex = branch.Leaf.StartIndex;

                return(new LeafSemanticNode((int)CommandNodeType.String, startIndex, text));
            });

            parser.AttachAction("singleString", (branch, recurse) =>
            {
                var text = branch.Leaf.MatchedText;
                text     = text
                           .Substring(1, text.Length - 2)
                           .Replace(@"\\", @"\")
                           .Replace(@"\'", @"'");
                var startIndex = branch.Leaf.StartIndex;

                return(new LeafSemanticNode((int)CommandNodeType.String, startIndex, text));
            });

            parser.AttachAction("string", (branch, recurse) => recurse(branch.GetDescendant(0)));

            parser.AttachAction("options", (branch, recurse) =>
            {
                IEnumerable <ISemanticNode> options = branch.GetDescendant(0)
                                                      ?.Elements
                                                      ?.Select(recurse);

                return(new BranchSemanticNode((int)CommandNodeType.Options, branch.StartIndex, options ?? new ISemanticNode[0]));
            });

            parser.AttachAction("literal", (branch, recurse) =>
            {
                var value = branch.Leaf.MatchedText;

                return(new LeafSemanticNode((int)CommandNodeType.String, branch.StartIndex, value));
            });

            parser.AttachAction("details", (branch, recurse) =>
            {
                BranchParseNode optionsNode = branch.GetDescendant(0);
                BranchParseNode literalNode = branch.GetDescendant(1, 1);

                var results = new List <ISemanticNode>();

                if (optionsNode != null)
                {
                    results.Add(recurse(optionsNode));
                }
                if (literalNode != null)
                {
                    results.Add(recurse(literalNode));
                }

                return(new BranchSemanticNode((int)CommandNodeType.Details, branch.StartIndex, results));
            });

            parser.AttachAction("path", (branch, recurse) =>
            {
                var value = branch.MatchedText;

                return(new LeafSemanticNode((int)CommandNodeType.String, branch.StartIndex, value));
            });

            parser.AttachAction("root", (branch, recurse) =>
            {
                ISemanticNode path    = recurse(branch.GetDescendant(0));
                ISemanticNode details = recurse(branch.GetDescendant(1));

                return(new BranchSemanticNode((int)CommandNodeType.Root, path, details));
            });
        }