Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Help understanding syntax error with non-terminal, ok with terminal #12

Open
InfinitiesLoop opened this issue Sep 18, 2018 · 4 comments

Comments

@InfinitiesLoop
Copy link

Here's a complete repro if the issue I'm trying to resolve. The output will be:
Error:Syntax error, expected: > ((1:10))

If all you do is comment out the line marked fails and uncomment the line marked succeeds, the expression parses successfully.

There's an ambuguity with "<" in that it might be part of an 'infix' expression or the beginning of a part of a 'componentAccess' expression, but I expected Irony to work it out since the componentAccess rule won't be met, whereas infix is. It seems to be able to do that when the infixOp is removed as a non-terminal and a pure terminal used instead.

Either this indicative of a bug or I just need help understanding this behavior, and whether or not its possible to have a grammar parsed successfully this way. I've played with grammar hints to no avail. This is a simplified version of the actual grammar I'm using, for demonstration purposes.

    class Program
    {
        static void Main(string[] args)
        {
            Try("abc < xyz");

            Console.ReadLine();
        }

        private static void Try(string expr)
        {
            var p = new Parser(new ExpressionGrammar());
            var result = p.Parse(expr);
            Console.WriteLine(result.Status + ":" + string.Join("\n", result.ParserMessages.Select(m => $"{m.Message} ({m.Location})")));
        }

        public class ExpressionGrammar : Grammar
        {
            public ExpressionGrammar() : base(false)
            {
                var formula = new NonTerminal("formula");
                var infix = new NonTerminal("infix");
                var infixOp = new NonTerminal("infixOp");
                var componentAccess = new NonTerminal("componentaccess");
                var identifier = new NonTerminal("identifier");

                Root = formula;

                formula.Rule =
                    identifier
                    | componentAccess
                    | infix
                    ;

                identifier.Rule = ToTerm("abc") | ToTerm("xyz");
                infixOp.Rule = ToTerm("<");
                // e.g.: abc<xyz>.abc
                componentAccess.Rule = formula + "<" + identifier + ">" + "." + identifier;

                // fails
                infix.Rule = formula + infixOp + formula;
                // succeeds (inlining infixOp)
                //infix.Rule = formula + ToTerm("<") + formula;
            }
        }
    }
@InfinitiesLoop
Copy link
Author

For what it's worth I found a workaround, which is to have a special version of the infix rule that is specifically for the < case. The code that handles the parse tree just has to account for this possibility. Would really really love to know of a more correct way, or know if this is a bug.

    class Program
    {
        static void Main(string[] args)
        {
            Try("abc < xyz");
            Try("abc > xyz");
            Try("abc<xyz>.abc");
            Try("abc<xyz>.abc > abc<xyz>.abc");
            Try("abc<xyz>.abc < abc<xyz>.abc");

            Console.ReadLine();
        }

        private static void Try(string expr)
        {
            var p = new Parser(new ExpressionGrammar());
            var result = p.Parse(expr);
            Console.WriteLine(result.Status + ":" + string.Join("\n", result.ParserMessages.Select(m => $"{m.Message} ({m.Location})")));
        }

        public class ExpressionGrammar : Grammar
        {
            public ExpressionGrammar() : base(false)
            {
                var formula = new NonTerminal("formula");
                var infix = new NonTerminal("infix");
                var infixLt = new NonTerminal("infixLt");
                var infixOp = new NonTerminal("infixOp");
                var componentAccess = new NonTerminal("componentaccess");
                var identifier = new NonTerminal("identifier");

                Root = formula;

                formula.Rule =
                    identifier
                    | componentAccess
                    | infixLt // workaround
                    | infix
                    ;

                identifier.Rule = ToTerm("abc") | ToTerm("xyz");
                infixOp.Rule = ToTerm("<") | ToTerm(">");
                componentAccess.Rule = formula + "<" + identifier + ">" + "." + identifier;

                // 2 rules to work around it
                infixLt.Rule = formula + ToTerm("<") + formula;
                infix.Rule = formula + infixOp + formula;
            }
        }
    }

@sebastienros
Copy link
Contributor

Small world ...

@InfinitiesLoop
Copy link
Author

@sebastienros Didn't know you were here! HAI!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants