예제 #1
0
        private static Grammar MakeParser()
        {
            // Literals
            var ws    = Terminals.WhiteSpace.Repeat(0);
            var comma = ws.Then(Terminals.Set(','), ws);
            var subExpressionAccess = ws.Then(Terminals.Set('.'), ws);
            var number = new NumberParser
            {
                AllowDecimal  = true,
                AllowExponent = true,
                AllowSign     = true,
                ValueType     = typeof(float)
            };

            var identifier = Terminals.Letter.Or(Terminals.Set(_identifierAllowedCharacters))
                             .Then(Terminals.LetterOrDigit.Or(Terminals.Set(_identifierAllowedCharacters)).Repeat(0));

            // Expressions
            var expression    = new UnaryParser();
            var subExpression = expression.Named(ElementAST.SubExpressionRoot)
                                .Then(subExpressionAccess, identifier.Named(ElementAST.SubExpressionName));
            var arguments = expression.Named(ElementAST.CallArgument).Repeat(0).SeparatedBy(comma);
            var call      = expression.Named(ElementAST.Callee)
                            .Then(ws, Terminals.Set('('), ws, arguments.Named(ElementAST.CallArguments), ws,
                                  Terminals.Set(')'));

            expression.Inner = new AlternativeParser(
                number.Named(ElementAST.NumberExpression),
                identifier.Named(ElementAST.VariableExpression),
                subExpression.Named(ElementAST.SubExpression),
                call.Named(ElementAST.CallExpression)
                );

            // Functions
            var portType = ws.Then(Terminals.Literal(":"), ws, identifier.Named(ElementAST.PortType)).Optional();
            var port     = identifier.Named(ElementAST.PortName).Then(portType).Named(ElementAST.Port);
            var ports    = port.Repeat(0).SeparatedBy(comma);
            var fnInputs = Terminals.Set('(')
                           .Then(ws, ports.Named(ElementAST.FunctionInputs), ws, Terminals.Set(')')).Optional();
            var fnOutputs   = Terminals.Literal("->").Then(ws, ports.Named(ElementAST.FunctionOutputs)).Or(portType);
            var fnSignature = identifier.Named(ElementAST.FunctionName).Then(ws, fnInputs, ws, fnOutputs, ws);

            // Statements
            var statement = new UnaryParser();
            var body      = Terminals.Set('{').Then(ws, statement.Then(ws).Repeat(0).Named(ElementAST.FunctionBody), ws,
                                                    Terminals.Set('}'));
            var assign = Terminals.Set('=').Then(ws, expression.Named(ElementAST.AssignmentStatement), ws,
                                                 Terminals.Set(';'));

            statement.Inner = fnSignature
                              .Then(body.Or(assign).Or(Terminals.Set(';').Named(ElementAST.TypeStatement)))
                              .Named(ElementAST.Statement);

            var start = ws.Then(statement, ws).Repeat(0);

            start.Until = Terminals.End;

            return(new Grammar(start));
        }
예제 #2
0
        public EbnfGrammar()
            : base("ebnf")
        {
            DefineCommonNonTerminals = true;
            GenerateSpecialSequences();

            // terminals
            AlternativeParser terminal_string = ("'" & (+Terminals.AnyChar).Until("'").WithName("value") & "'")
                                                | ("\"" & (+Terminals.AnyChar).Until("\"").WithName("value") & "\"")
                                                | ("’" & (+Terminals.AnyChar).Until("’").WithName("value") & "’");

            SequenceParser special_sequence =
                ("?" & (+Terminals.AnyChar).Until("?").WithName("name") & "?").WithName("special sequence");

            SequenceParser meta_identifier_terminal = Terminals.Letter & -(Terminals.LetterOrDigit | '_');
            var            integer = new NumberParser();

            Parser old = DefaultSeparator;

            DefaultSeparator = cws;

            // nonterminals
            var definition_list   = new UnaryParser("definition list");
            var single_definition = new UnaryParser("single definition");
            var term            = new UnaryParser("term");
            var primary         = new UnaryParser("primary");
            var exception       = new UnaryParser("exception");
            var factor          = new UnaryParser("factor");
            var meta_identifier = new UnaryParser("meta identifier");
            var syntax_rule     = new UnaryParser("syntax rule");
            var rule_equals     = new UnaryParser("equals");

            SequenceParser optional_sequence = ("[" & definition_list & "]").WithName("optional sequence");
            SequenceParser repeated_sequence = ("{" & definition_list & "}").WithName("repeated sequence");
            SequenceParser grouped_sequence  = ("(" & definition_list & ")").WithName("grouped sequence");

            // rules
            meta_identifier.Inner = (+meta_identifier_terminal).SeparatedBy(ws);
            primary.Inner         = optional_sequence | repeated_sequence
                                    | special_sequence | grouped_sequence
                                    | meta_identifier | terminal_string.Named("terminal string") | null;
            factor.Inner            = ~(integer.Named("integer") & "*") & primary;
            term.Inner              = factor & ~("-" & exception);
            exception.Inner         = term;
            single_definition.Inner = term & -("," & term);
            definition_list.Inner   = single_definition & -("|" & single_definition);
            rule_equals.Inner       = (Parser)"=" | ":=";
            syntax_rule.Inner       = meta_identifier & rule_equals & definition_list & ";";

            Inner = cws & +syntax_rule & cws;

            DefaultSeparator = old;

            AttachEvents();
        }
예제 #3
0
        public void TestInt32Values()
        {
            var sample = "123,+123,-123";

            var grammar = new Grammar();
            var num     = new NumberParser {
                AllowSign = true, AllowDecimal = true, ValueType = typeof(int)
            };

            grammar.Inner = (+num.Named("str")).SeparatedBy(",");

            var match = grammar.Match(sample);

            Assert.True(match.Success, match.ErrorMessage);
            Assert.Equal(new Int32[] { 123, 123, -123 }, match.Find("str").Select(m => (int)m.Value));
        }
예제 #4
0
        public void TestExponent()
        {
            var sample = "123E-02,123E+10,123.4567E+5,1234E2";

            var grammar = new Grammar();
            var num     = new NumberParser {
                AllowDecimal = true, AllowExponent = true
            };

            grammar.Inner = (+num.Named("str")).SeparatedBy(",");

            var match = grammar.Match(sample);

            Assert.True(match.Success, match.ErrorMessage);
            Assert.Equal(new object[] { 123E-2M, 123E+10M, 123.4567E+5M, 1234E+2M }, match.Find("str").Select(m => num.GetValue(m)));
        }
예제 #5
0
        public void TestSign()
        {
            var sample = "123.4567,+123.4567,-123.4567";

            var grammar = new Grammar();
            var num     = new NumberParser {
                AllowSign = true, AllowDecimal = true
            };

            grammar.Inner = (+num.Named("str")).SeparatedBy(",");

            var match = grammar.Match(sample);

            Assert.True(match.Success, match.ErrorMessage);
            Assert.Equal(new object[] { 123.4567M, 123.4567M, -123.4567M }, match.Find("str").Select(m => num.GetValue(m)));
        }
예제 #6
0
        public void TestDecimalValues()
        {
            var sample = "123.4567,+123.4567,-123.4567";

            var grammar = new Grammar();
            var num     = new NumberParser {
                AllowSign = true, AllowDecimal = true, ValueType = typeof(decimal)
            };

            grammar.Inner = (+num.Named("str")).SeparatedBy(",");

            var match = grammar.Match(sample);

            Assert.IsTrue(match.Success, match.ErrorMessage);
            CollectionAssert.AreEquivalent(new Decimal[] { 123.4567M, 123.4567M, -123.4567M }, match.Find("str").Select(m => (decimal)m.Value));
        }