You can define a grammar for Jaql using a top-down approach, starting with the grammar
select = "select" variables "from" classNames optionalWhere;
If your users are familiar with SQL, the words select and from will be familiar to them. For your own query language, you can use other words such as show or present. As a language designer, you should determine the keywords of your language according to the effect they will have on your users.
As a first cut, you can model variables and classNames as repetitions of words, separated by commas:
select = "select" variables "from" classNames optionalWhere; variables = commaList(variable); variable = Word; classNames = commaList(className); className = Word; optionalWhere = empty "where" comparisons; comparisons = commaList(comparison); commaList(p) = p (',' p)*;
Now let's enhance this grammar to allow more interesting terms in the select list. For example, let's allow the user to select a discounted price, such as
select PricePerBag * 0.9 from chip where PricePerBag > 10
You can allow this by allowing a selectTerm to be an expression involving numbers , words, and variables. You can write the grammar as follows :
select = "select" selectTerms "from" classNames optionalWhere; selectTerms = commaList(selectTerm); selectTerm = expression; variable = Word; classNames = commaList(className); className = Word; optionalWhere = empty "where" comparisons; comparisons = commaList(comparison); commaList(p) = p (',' p)*;
This grammar now relies on some other source for expression and for comparison . A grammar to supply these subparsers is similar to the arithmetic grammar presented in Chapter 7, "Parsing Arithmetic":
comparison = arg operator arg; arg = expression QuotedString; expression = term ('+' term '-' term)*; term = factor ('*' factor '/' factor)*; factor = '(' expression ')' Num variable; variable = Word; operator = "<" ">" "=" "<=" ">=" "!=";
The Jaql grammar has no knowledge of chip company data, so the language is fairly reusable. The work it would take to use Jaql on other object models is primarily the creation of fact and query conversion methods specific to each new object model.
To help simplify the Jaql parser, the package sjm.examples.query has a separate parser for comparisons and uses it in the Jaql parser. This reduces the size of the parser class that implements the grammar. It also demonstrates the flexibility you have in how you store the objects that can be composed into a parser.