Need a lil help with custom Query Language

Jun 28, 2009 at 1:21 AM

Similiar to 'vilx' a couple discussions down I am currently fiddling with the grammar of a custom query language that mimics SQL's where statement.

Here's an example:

TYPE = ‘Some Specified Type Value’ and (status = ‘- CHAPTER -’ or status = ‘Accepted’ or status = ‘Deferred’ or status = ‘ToBeReviewed’) and (hierarchy >= ‘2’ or hierarchy >= ‘10’) and ((Some Attribute like ‘%VA10A%’) or (Some Other Attribute like ‘%VA11A%’) or (Some third Attribute > '5' and Some fourth Attribute not like '%DEF%'))

 

The criterias are basically pretty simple:

  • Everything's case insensitive
  • X conditions can be chained together with the tpyical and / or keywords
  • Infinite subconditioning with and in ( and ) is possible
  • Values are all in single or double quotes (' or " ... ignore the weird quotes in the example)
  • In case of a (not) like condition, the values to compare against are post/prefixed with %'s
  • Everything's that's left to a comparison operator (= >= <= != etc) is the identifier and these identifiers are not surrounded by quotes and can be multiple words/numbers.
  • It's always just one line... no multiline input is allowed

 

So what I have right now is the following:

 

 

using Irony.CompilerServices;

namespace DocFactoryFilter
{
    [Language("DocFactory Filter", "1.0", "Irony.Net Grammar for the darn DocFactory")]
    internal class Grammar : Irony.CompilerServices.Grammar
    {
        internal Grammar()
            : base(false)
        {
            var xBetween = new NonTerminal("Between");

            var xEquals = new NonTerminal("Equals");
            var xNotEquals = new NonTerminal("NotEquals");
            var xGreater = new NonTerminal("Greater");
            var xGreaterEqual = new NonTerminal("GreaterEqual");
            var xLess = new NonTerminal("Less");
            var xLessEqual = new NonTerminal("LessEqual");
            var xBeginsWith = new NonTerminal("BeginsWith");
            var xNotBeginsWith = new NonTerminal("NotBeginsWith");
            var xLike = new NonTerminal("Like");
            var xNotLike = new NonTerminal("NotLike");


            
            var xIdentifier = new IdentifierTerminal("AttributeIdentifier");

            var xValue = new NonTerminal("Value")
                             {
                                 Rule = new StringLiteral("String", "'",
                                                          StringFlags.AllowsAllEscapes |
                                                          StringFlags.AllowsDoubledQuote |
                                                          StringFlags.HasEscapes) |
                                                          new NumberLiteral("Number")
                             };

            xBetween.Rule = xIdentifier + ("between") + xValue + ("and") + xValue | xIdentifier + ("in") + xValue + ("and") + xValue;
            xEquals.Rule = xIdentifier + ("=") + xValue | xValue + ("=") + xIdentifier;
            xNotEquals.Rule = xIdentifier + ("!=") + xValue | xValue + ("!=") + xIdentifier | xIdentifier + ("<>") + xValue | xValue + ("<>") + xIdentifier;
            xGreater.Rule = xIdentifier + (">") + xValue | xValue + ("<") + xIdentifier;
            xGreaterEqual.Rule = xIdentifier + (">=") + xValue | xValue + ("<=") + xIdentifier;
            xLess.Rule = xIdentifier + ("<") + xValue | xValue + (">") + xIdentifier;
            xLessEqual.Rule = xIdentifier + ("<=") + xValue | xValue + (">=") + xIdentifier;
            xBeginsWith.Rule = xIdentifier + ("begins") + ("with") + xValue;
            xNotBeginsWith.Rule = xIdentifier + ("not") + ("begins") + ("with") + xValue;
            xLike.Rule = xIdentifier + ("like") + xValue;
            xNotLike.Rule = xIdentifier + ("not") + ("like") + xValue;


            var xComparison = new NonTerminal("Comparison")
                                  {
                                      Rule = xBetween
                                             | xEquals
                                             | xNotEquals
                                             | xGreater
                                             | xGreaterEqual
                                             | xLess
                                             | xLessEqual
                                             | xBeginsWith
                                             | xNotBeginsWith
                                             | xLike
                                             | xNotLike
                                  };


            var xExpression = new NonTerminal("Expression");
            var xOr = new NonTerminal("Or");
            var xAnd = new NonTerminal("And");
            var xNot = new NonTerminal("Not");
            var xParenthesis = new NonTerminal("Parenthesis");

            xParenthesis.SetOption(TermOptions.IsTransient);

            xOr.Rule = xExpression + ("or") + xExpression | xExpression + ("|") + xExpression;
            xAnd.Rule = xExpression + ("and") + xExpression | xExpression + ("&") + xExpression;
            xNot.Rule = ("NOT") + xExpression;

            xParenthesis.Rule = ("(") + xExpression + (")");
            xExpression.Rule = xComparison | xOr | xAnd | xNot | xParenthesis;


            RegisterOperators(6, "not");
            RegisterOperators(5, "and");
            RegisterOperators(4, "or");

            RegisterPunctuation("between", "and", "or", "not", "=", "!=", ">", "<", "<>", ">=", "<=", "begins", "with", "like", "in", "(", ")");

            Root = xExpression;
        }
    }
}

But when trying to parse that I get the error 'Syntax error, expected: between,in,=,!=,<>,>,>=,<,<=,begins,not,like,' and I am kinda lost right now. Does anyone know why this is happening and/or what I can do?

 

Any ideas/suggestions are highly appreciated :)

 

Cheers & thanks,

-Jörg

 

Coordinator
Jun 28, 2009 at 7:06 AM

Hi

In the grid with error message, double-click on state name - this will bring you to the parser state where error occurred. Examine the state, see what terms are expected in shift productions (after "dot") or as lookaheads of reduce actions (with dot at the end)

this would give you idea what maybe wrong with your grammar.

As a general note. Avoid using this auto-initialize syntax in constructors (with {Rule=...} ) initializers.

Make explicit non-terminals for string literal and number literal.

When defining expression, define it as:

expr.Rule = binExpr | unExpr | compareExpr;

binExpr.Rule = expr + binOp + expr;

binOp = Symbol("|") | "or" | "and" | "&";

and so on - my point, define binary operation with binOp nonterminal in the middle, then list all binary operators in its rule. Also don't forget register all operators - you register "and", "or", but forget about "|" and "&"

Roman