Select correct non-terminal problem

Jun 22, 2015 at 5:43 PM
I have the following grammar:
StringLiteral STRING = new StringLiteral("string", "'", StringOptions.AllowsDoubledQuote);
KeyTerm WITH = ToTerm("WITH");
KeyTerm LIKE = ToTerm("like");
KeyTerm AND = ToTerm("AND");
KeyTerm OR = ToTerm("OR");
KeyTerm BY = ToTerm("BY");

NonTerminal expression = new NonTerminal("expression");

IdentifierTerminal rootTable = new IdentifierTerminal("rootTable");
IdentifierTerminal table = new IdentifierTerminal("table");
IdentifierTerminal column = new IdentifierTerminal("column");

NonTerminal filterList = new NonTerminal("filterList");
NonTerminal filter = new NonTerminal("filter");

NonTerminal connectionFilter = new NonTerminal("connectionFilter");

NonTerminal stringFilter = new NonTerminal("stringFilter");
NonTerminal stringQuery = new NonTerminal("stringQuery");
NonTerminal stringOperator = new NonTerminal("stringOperator");

connectionFilter.Rule = column + BY + table | WITH + table;

stringFilter.Rule = column + stringQuery | 
                    WITH + column + stringQuery;
stringQuery.Rule = STRING |
                stringOperator + STRING;
stringOperator.Rule = LIKE;

linker.Rule = AND | OR | Empty;

filterList.Rule = MakePlusRule(filterList, linker, filter);

filter.Rule = connectionFilter |
           stringFilter;
              
expression.Rule = rootTable + filterList;             

Root = expression;
Feeding it an input like "Orders with employee with address like 'abc'", I would like to get back:
"Orders [with employee (1)] [with address like 'abc' (2)]"
(1). connectionFilter: with "employee" as table name
(2). string filter: with "address" as "column" and 'abc' = stringQuery operator

Instead I get: "Orders [with employee (1)] [with address (2)] [like 'abc' (3)]"
  1. connectionFilter: with "employee" as table name
  2. connectionFilter:: with "address" as "table name" and 'abc' = stringQuery operator
  3. stringFilter: with "like" as "column name" and 'abc' as stringQuery
I know for a fact that tableName or columnName cannot contain predefined key terms (like "like").

How can I enforce this rule in my grammar?
Jun 22, 2015 at 7:02 PM
Edited Jun 22, 2015 at 7:09 PM
You have three identifier terminals, but Irony's tokenizer cannot choose for you between them.

If you use the grammar explorer and use the trace you will see how it tokenizes the string:
Orders       with employee with address like 'abc'
rootTable    with table    with table   like string
While you want:
rootTable    with table    with column  like string
But Irony can't decide for you if an identifier terminal is a table or column, you'll have to use one terminal and make the right production rules.

Something like this:
           StringLiteral STRING = new StringLiteral("string", "'", StringOptions.AllowsDoubledQuote);
            KeyTerm WITH = ToTerm("WITH");
            KeyTerm LIKE = ToTerm("LIKE");
            KeyTerm AND = ToTerm("AND");
            KeyTerm OR = ToTerm("OR");
            KeyTerm BY = ToTerm("BY");

            NonTerminal expression = new NonTerminal("expression");

            IdentifierTerminal id = new IdentifierTerminal("id");

            NonTerminal filterList = new NonTerminal("filterList");
            NonTerminal filter = new NonTerminal("filter");

            NonTerminal connectionFilter = new NonTerminal("connectionFilter");

            NonTerminal stringFilter = new NonTerminal("stringFilter");
            NonTerminal stringQuery = new NonTerminal("stringQuery");
            NonTerminal stringOperator = new NonTerminal("stringOperator");

            var Column = new NonTerminal("Column", id);
            var Table = new NonTerminal("Table", id);

            connectionFilter.Rule = Column + BY + Table | WITH + Table;

            stringFilter.Rule = Column + stringQuery
                              | WITH + Column + stringQuery;

            stringQuery.Rule = STRING
                             | LIKE + STRING;

            var linker = new NonTerminal("linker", AND | OR | Empty);

            filterList.Rule = MakePlusRule(filterList, linker, filter);

            filter.Rule = connectionFilter | stringFilter;

            var RootTable = new NonTerminal("RootTable", id);

            expression.Rule = RootTable + filterList;

            

            Root = expression;
Jun 22, 2015 at 7:44 PM
Works like a charm.
Thanks a lot!