summaryrefslogtreecommitdiffstats
path: root/tcllib/examples/page
diff options
context:
space:
mode:
authorWilliam Joye <wjoye@cfa.harvard.edu>2016-10-27 19:39:39 (GMT)
committerWilliam Joye <wjoye@cfa.harvard.edu>2016-10-27 19:39:39 (GMT)
commitea28451286d3ea4a772fa174483f9a7a66bb1ab3 (patch)
tree6ee9d8a7848333a7ceeee3b13d492e40225f8b86 /tcllib/examples/page
parentb5ca09bae0d6a1edce939eea03594dd56383f2c8 (diff)
parent7c621da28f07e449ad90c387344f07a453927569 (diff)
downloadblt-ea28451286d3ea4a772fa174483f9a7a66bb1ab3.zip
blt-ea28451286d3ea4a772fa174483f9a7a66bb1ab3.tar.gz
blt-ea28451286d3ea4a772fa174483f9a7a66bb1ab3.tar.bz2
Merge commit '7c621da28f07e449ad90c387344f07a453927569' as 'tcllib'
Diffstat (limited to 'tcllib/examples/page')
-rw-r--r--tcllib/examples/page/lemon.html892
-rw-r--r--tcllib/examples/page/lemon.peg141
-rw-r--r--tcllib/examples/page/parse.y995
-rw-r--r--tcllib/examples/page/sql.log18
-rw-r--r--tcllib/examples/page/sql.peg643
5 files changed, 2689 insertions, 0 deletions
diff --git a/tcllib/examples/page/lemon.html b/tcllib/examples/page/lemon.html
new file mode 100644
index 0000000..6a4d6db
--- /dev/null
+++ b/tcllib/examples/page/lemon.html
@@ -0,0 +1,892 @@
+<html>
+<head>
+<title>The Lemon Parser Generator</title>
+</head>
+<body bgcolor=white>
+<h1 align=center>The Lemon Parser Generator</h1>
+
+<p>Lemon is an LALR(1) parser generator for C or C++.
+It does the same job as ``bison'' and ``yacc''.
+But lemon is not another bison or yacc clone. It
+uses a different grammar syntax which is designed to
+reduce the number of coding errors. Lemon also uses a more
+sophisticated parsing engine that is faster than yacc and
+bison and which is both reentrant and thread-safe.
+Furthermore, Lemon implements features that can be used
+to eliminate resource leaks, making is suitable for use
+in long-running programs such as graphical user interfaces
+or embedded controllers.</p>
+
+<p>This document is an introduction to the Lemon
+parser generator.</p>
+
+<h2>Theory of Operation</h2>
+
+<p>The main goal of Lemon is to translate a context free grammar (CFG)
+for a particular language into C code that implements a parser for
+that language.
+The program has two inputs:
+<ul>
+<li>The grammar specification.
+<li>A parser template file.
+</ul>
+Typically, only the grammar specification is supplied by the programmer.
+Lemon comes with a default parser template which works fine for most
+applications. But the user is free to substitute a different parser
+template if desired.</p>
+
+<p>Depending on command-line options, Lemon will generate between
+one and three files of outputs.
+<ul>
+<li>C code to implement the parser.
+<li>A header file defining an integer ID for each terminal symbol.
+<li>An information file that describes the states of the generated parser
+ automaton.
+</ul>
+By default, all three of these output files are generated.
+The header file is suppressed if the ``-m'' command-line option is
+used and the report file is omitted when ``-q'' is selected.</p>
+
+<p>The grammar specification file uses a ``.y'' suffix, by convention.
+In the examples used in this document, we'll assume the name of the
+grammar file is ``gram.y''. A typical use of Lemon would be the
+following command:
+<pre>
+ lemon gram.y
+</pre>
+This command will generate three output files named ``gram.c'',
+``gram.h'' and ``gram.out''.
+The first is C code to implement the parser. The second
+is the header file that defines numerical values for all
+terminal symbols, and the last is the report that explains
+the states used by the parser automaton.</p>
+
+<h3>Command Line Options</h3>
+
+<p>The behavior of Lemon can be modified using command-line options.
+You can obtain a list of the available command-line options together
+with a brief explanation of what each does by typing
+<pre>
+ lemon -?
+</pre>
+As of this writing, the following command-line options are supported:
+<ul>
+<li><tt>-b</tt>
+<li><tt>-c</tt>
+<li><tt>-g</tt>
+<li><tt>-m</tt>
+<li><tt>-q</tt>
+<li><tt>-s</tt>
+<li><tt>-x</tt>
+</ul>
+The ``-b'' option reduces the amount of text in the report file by
+printing only the basis of each parser state, rather than the full
+configuration.
+The ``-c'' option suppresses action table compression. Using -c
+will make the parser a little larger and slower but it will detect
+syntax errors sooner.
+The ``-g'' option causes no output files to be generated at all.
+Instead, the input grammar file is printed on standard output but
+with all comments, actions and other extraneous text deleted. This
+is a useful way to get a quick summary of a grammar.
+The ``-m'' option causes the output C source file to be compatible
+with the ``makeheaders'' program.
+Makeheaders is a program that automatically generates header files
+from C source code. When the ``-m'' option is used, the header
+file is not output since the makeheaders program will take care
+of generated all header files automatically.
+The ``-q'' option suppresses the report file.
+Using ``-s'' causes a brief summary of parser statistics to be
+printed. Like this:
+<pre>
+ Parser statistics: 74 terminals, 70 nonterminals, 179 rules
+ 340 states, 2026 parser table entries, 0 conflicts
+</pre>
+Finally, the ``-x'' option causes Lemon to print its version number
+and then stops without attempting to read the grammar or generate a parser.</p>
+
+<h3>The Parser Interface</h3>
+
+<p>Lemon doesn't generate a complete, working program. It only generates
+a few subroutines that implement a parser. This section describes
+the interface to those subroutines. It is up to the programmer to
+call these subroutines in an appropriate way in order to produce a
+complete system.</p>
+
+<p>Before a program begins using a Lemon-generated parser, the program
+must first create the parser.
+A new parser is created as follows:
+<pre>
+ void *pParser = ParseAlloc( malloc );
+</pre>
+The ParseAlloc() routine allocates and initializes a new parser and
+returns a pointer to it.
+The actual data structure used to represent a parser is opaque --
+its internal structure is not visible or usable by the calling routine.
+For this reason, the ParseAlloc() routine returns a pointer to void
+rather than a pointer to some particular structure.
+The sole argument to the ParseAlloc() routine is a pointer to the
+subroutine used to allocate memory. Typically this means ``malloc()''.</p>
+
+<p>After a program is finished using a parser, it can reclaim all
+memory allocated by that parser by calling
+<pre>
+ ParseFree(pParser, free);
+</pre>
+The first argument is the same pointer returned by ParseAlloc(). The
+second argument is a pointer to the function used to release bulk
+memory back to the system.</p>
+
+<p>After a parser has been allocated using ParseAlloc(), the programmer
+must supply the parser with a sequence of tokens (terminal symbols) to
+be parsed. This is accomplished by calling the following function
+once for each token:
+<pre>
+ Parse(pParser, hTokenID, sTokenData, pArg);
+</pre>
+The first argument to the Parse() routine is the pointer returned by
+ParseAlloc().
+The second argument is a small positive integer that tells the parse the
+type of the next token in the data stream.
+There is one token type for each terminal symbol in the grammar.
+The gram.h file generated by Lemon contains #define statements that
+map symbolic terminal symbol names into appropriate integer values.
+(A value of 0 for the second argument is a special flag to the
+parser to indicate that the end of input has been reached.)
+The third argument is the value of the given token. By default,
+the type of the third argument is integer, but the grammar will
+usually redefine this type to be some kind of structure.
+Typically the second argument will be a broad category of tokens
+such as ``identifier'' or ``number'' and the third argument will
+be the name of the identifier or the value of the number.</p>
+
+<p>The Parse() function may have either three or four arguments,
+depending on the grammar. If the grammar specification file request
+it, the Parse() function will have a fourth parameter that can be
+of any type chosen by the programmer. The parser doesn't do anything
+with this argument except to pass it through to action routines.
+This is a convenient mechanism for passing state information down
+to the action routines without having to use global variables.</p>
+
+<p>A typical use of a Lemon parser might look something like the
+following:
+<pre>
+ 01 ParseTree *ParseFile(const char *zFilename){
+ 02 Tokenizer *pTokenizer;
+ 03 void *pParser;
+ 04 Token sToken;
+ 05 int hTokenId;
+ 06 ParserState sState;
+ 07
+ 08 pTokenizer = TokenizerCreate(zFilename);
+ 09 pParser = ParseAlloc( malloc );
+ 10 InitParserState(&sState);
+ 11 while( GetNextToken(pTokenizer, &hTokenId, &sToken) ){
+ 12 Parse(pParser, hTokenId, sToken, &sState);
+ 13 }
+ 14 Parse(pParser, 0, sToken, &sState);
+ 15 ParseFree(pParser, free );
+ 16 TokenizerFree(pTokenizer);
+ 17 return sState.treeRoot;
+ 18 }
+</pre>
+This example shows a user-written routine that parses a file of
+text and returns a pointer to the parse tree.
+(We've omitted all error-handling from this example to keep it
+simple.)
+We assume the existence of some kind of tokenizer which is created
+using TokenizerCreate() on line 8 and deleted by TokenizerFree()
+on line 16. The GetNextToken() function on line 11 retrieves the
+next token from the input file and puts its type in the
+integer variable hTokenId. The sToken variable is assumed to be
+some kind of structure that contains details about each token,
+such as its complete text, what line it occurs on, etc. </p>
+
+<p>This example also assumes the existence of structure of type
+ParserState that holds state information about a particular parse.
+An instance of such a structure is created on line 6 and initialized
+on line 10. A pointer to this structure is passed into the Parse()
+routine as the optional 4th argument.
+The action routine specified by the grammar for the parser can use
+the ParserState structure to hold whatever information is useful and
+appropriate. In the example, we note that the treeRoot field of
+the ParserState structure is left pointing to the root of the parse
+tree.</p>
+
+<p>The core of this example as it relates to Lemon is as follows:
+<pre>
+ ParseFile(){
+ pParser = ParseAlloc( malloc );
+ while( GetNextToken(pTokenizer,&hTokenId, &sToken) ){
+ Parse(pParser, hTokenId, sToken);
+ }
+ Parse(pParser, 0, sToken);
+ ParseFree(pParser, free );
+ }
+</pre>
+Basically, what a program has to do to use a Lemon-generated parser
+is first create the parser, then send it lots of tokens obtained by
+tokenizing an input source. When the end of input is reached, the
+Parse() routine should be called one last time with a token type
+of 0. This step is necessary to inform the parser that the end of
+input has been reached. Finally, we reclaim memory used by the
+parser by calling ParseFree().</p>
+
+<p>There is one other interface routine that should be mentioned
+before we move on.
+The ParseTrace() function can be used to generate debugging output
+from the parser. A prototype for this routine is as follows:
+<pre>
+ ParseTrace(FILE *stream, char *zPrefix);
+</pre>
+After this routine is called, a short (one-line) message is written
+to the designated output stream every time the parser changes states
+or calls an action routine. Each such message is prefaced using
+the text given by zPrefix. This debugging output can be turned off
+by calling ParseTrace() again with a first argument of NULL (0).</p>
+
+<h3>Differences With YACC and BISON</h3>
+
+<p>Programmers who have previously used the yacc or bison parser
+generator will notice several important differences between yacc and/or
+bison and Lemon.
+<ul>
+<li>In yacc and bison, the parser calls the tokenizer. In Lemon,
+ the tokenizer calls the parser.
+<li>Lemon uses no global variables. Yacc and bison use global variables
+ to pass information between the tokenizer and parser.
+<li>Lemon allows multiple parsers to be running simultaneously. Yacc
+ and bison do not.
+</ul>
+These differences may cause some initial confusion for programmers
+with prior yacc and bison experience.
+But after years of experience using Lemon, I firmly
+believe that the Lemon way of doing things is better.</p>
+
+<h2>Input File Syntax</h2>
+
+<p>The main purpose of the grammar specification file for Lemon is
+to define the grammar for the parser. But the input file also
+specifies additional information Lemon requires to do its job.
+Most of the work in using Lemon is in writing an appropriate
+grammar file.</p>
+
+<p>The grammar file for lemon is, for the most part, free format.
+It does not have sections or divisions like yacc or bison. Any
+declaration can occur at any point in the file.
+Lemon ignores whitespace (except where it is needed to separate
+tokens) and it honors the same commenting conventions as C and C++.</p>
+
+<h3>Terminals and Nonterminals</h3>
+
+<p>A terminal symbol (token) is any string of alphanumeric
+and underscore characters
+that begins with an upper case letter.
+A terminal can contain lower class letters after the first character,
+but the usual convention is to make terminals all upper case.
+A nonterminal, on the other hand, is any string of alphanumeric
+and underscore characters than begins with a lower case letter.
+Again, the usual convention is to make nonterminals use all lower
+case letters.</p>
+
+<p>In Lemon, terminal and nonterminal symbols do not need to
+be declared or identified in a separate section of the grammar file.
+Lemon is able to generate a list of all terminals and nonterminals
+by examining the grammar rules, and it can always distinguish a
+terminal from a nonterminal by checking the case of the first
+character of the name.</p>
+
+<p>Yacc and bison allow terminal symbols to have either alphanumeric
+names or to be individual characters included in single quotes, like
+this: ')' or '$'. Lemon does not allow this alternative form for
+terminal symbols. With Lemon, all symbols, terminals and nonterminals,
+must have alphanumeric names.</p>
+
+<h3>Grammar Rules</h3>
+
+<p>The main component of a Lemon grammar file is a sequence of grammar
+rules.
+Each grammar rule consists of a nonterminal symbol followed by
+the special symbol ``::='' and then a list of terminals and/or nonterminals.
+The rule is terminated by a period.
+The list of terminals and nonterminals on the right-hand side of the
+rule can be empty.
+Rules can occur in any order, except that the left-hand side of the
+first rule is assumed to be the start symbol for the grammar (unless
+specified otherwise using the <tt>%start</tt> directive described below.)
+A typical sequence of grammar rules might look something like this:
+<pre>
+ expr ::= expr PLUS expr.
+ expr ::= expr TIMES expr.
+ expr ::= LPAREN expr RPAREN.
+ expr ::= VALUE.
+</pre>
+</p>
+
+<p>There is one non-terminal in this example, ``expr'', and five
+terminal symbols or tokens: ``PLUS'', ``TIMES'', ``LPAREN'',
+``RPAREN'' and ``VALUE''.</p>
+
+<p>Like yacc and bison, Lemon allows the grammar to specify a block
+of C code that will be executed whenever a grammar rule is reduced
+by the parser.
+In Lemon, this action is specified by putting the C code (contained
+within curly braces <tt>{...}</tt>) immediately after the
+period that closes the rule.
+For example:
+<pre>
+ expr ::= expr PLUS expr. { printf("Doing an addition...\n"); }
+</pre>
+</p>
+
+<p>In order to be useful, grammar actions must normally be linked to
+their associated grammar rules.
+In yacc and bison, this is accomplished by embedding a ``$$'' in the
+action to stand for the value of the left-hand side of the rule and
+symbols ``$1'', ``$2'', and so forth to stand for the value of
+the terminal or nonterminal at position 1, 2 and so forth on the
+right-hand side of the rule.
+This idea is very powerful, but it is also very error-prone. The
+single most common source of errors in a yacc or bison grammar is
+to miscount the number of symbols on the right-hand side of a grammar
+rule and say ``$7'' when you really mean ``$8''.</p>
+
+<p>Lemon avoids the need to count grammar symbols by assigning symbolic
+names to each symbol in a grammar rule and then using those symbolic
+names in the action.
+In yacc or bison, one would write this:
+<pre>
+ expr -> expr PLUS expr { $$ = $1 + $3; };
+</pre>
+But in Lemon, the same rule becomes the following:
+<pre>
+ expr(A) ::= expr(B) PLUS expr(C). { A = B+C; }
+</pre>
+In the Lemon rule, any symbol in parentheses after a grammar rule
+symbol becomes a place holder for that symbol in the grammar rule.
+This place holder can then be used in the associated C action to
+stand for the value of that symbol.<p>
+
+<p>The Lemon notation for linking a grammar rule with its reduce
+action is superior to yacc/bison on several counts.
+First, as mentioned above, the Lemon method avoids the need to
+count grammar symbols.
+Secondly, if a terminal or nonterminal in a Lemon grammar rule
+includes a linking symbol in parentheses but that linking symbol
+is not actually used in the reduce action, then an error message
+is generated.
+For example, the rule
+<pre>
+ expr(A) ::= expr(B) PLUS expr(C). { A = B; }
+</pre>
+will generate an error because the linking symbol ``C'' is used
+in the grammar rule but not in the reduce action.</p>
+
+<p>The Lemon notation for linking grammar rules to reduce actions
+also facilitates the use of destructors for reclaiming memory
+allocated by the values of terminals and nonterminals on the
+right-hand side of a rule.</p>
+
+<h3>Precedence Rules</h3>
+
+<p>Lemon resolves parsing ambiguities in exactly the same way as
+yacc and bison. A shift-reduce conflict is resolved in favor
+of the shift, and a reduce-reduce conflict is resolved by reducing
+whichever rule comes first in the grammar file.</p>
+
+<p>Just like in
+yacc and bison, Lemon allows a measure of control
+over the resolution of paring conflicts using precedence rules.
+A precedence value can be assigned to any terminal symbol
+using the %left, %right or %nonassoc directives. Terminal symbols
+mentioned in earlier directives have a lower precedence that
+terminal symbols mentioned in later directives. For example:</p>
+
+<p><pre>
+ %left AND.
+ %left OR.
+ %nonassoc EQ NE GT GE LT LE.
+ %left PLUS MINUS.
+ %left TIMES DIVIDE MOD.
+ %right EXP NOT.
+</pre></p>
+
+<p>In the preceding sequence of directives, the AND operator is
+defined to have the lowest precedence. The OR operator is one
+precedence level higher. And so forth. Hence, the grammar would
+attempt to group the ambiguous expression
+<pre>
+ a AND b OR c
+</pre>
+like this
+<pre>
+ a AND (b OR c).
+</pre>
+The associativity (left, right or nonassoc) is used to determine
+the grouping when the precedence is the same. AND is left-associative
+in our example, so
+<pre>
+ a AND b AND c
+</pre>
+is parsed like this
+<pre>
+ (a AND b) AND c.
+</pre>
+The EXP operator is right-associative, though, so
+<pre>
+ a EXP b EXP c
+</pre>
+is parsed like this
+<pre>
+ a EXP (b EXP c).
+</pre>
+The nonassoc precedence is used for non-associative operators.
+So
+<pre>
+ a EQ b EQ c
+</pre>
+is an error.</p>
+
+<p>The precedence of non-terminals is transferred to rules as follows:
+The precedence of a grammar rule is equal to the precedence of the
+left-most terminal symbol in the rule for which a precedence is
+defined. This is normally what you want, but in those cases where
+you want to precedence of a grammar rule to be something different,
+you can specify an alternative precedence symbol by putting the
+symbol in square braces after the period at the end of the rule and
+before any C-code. For example:</p>
+
+<p><pre>
+ expr = MINUS expr. [NOT]
+</pre></p>
+
+<p>This rule has a precedence equal to that of the NOT symbol, not the
+MINUS symbol as would have been the case by default.</p>
+
+<p>With the knowledge of how precedence is assigned to terminal
+symbols and individual
+grammar rules, we can now explain precisely how parsing conflicts
+are resolved in Lemon. Shift-reduce conflicts are resolved
+as follows:
+<ul>
+<li> If either the token to be shifted or the rule to be reduced
+ lacks precedence information, then resolve in favor of the
+ shift, but report a parsing conflict.
+<li> If the precedence of the token to be shifted is greater than
+ the precedence of the rule to reduce, then resolve in favor
+ of the shift. No parsing conflict is reported.
+<li> If the precedence of the token it be shifted is less than the
+ precedence of the rule to reduce, then resolve in favor of the
+ reduce action. No parsing conflict is reported.
+<li> If the precedences are the same and the shift token is
+ right-associative, then resolve in favor of the shift.
+ No parsing conflict is reported.
+<li> If the precedences are the same the the shift token is
+ left-associative, then resolve in favor of the reduce.
+ No parsing conflict is reported.
+<li> Otherwise, resolve the conflict by doing the shift and
+ report the parsing conflict.
+</ul>
+Reduce-reduce conflicts are resolved this way:
+<ul>
+<li> If either reduce rule
+ lacks precedence information, then resolve in favor of the
+ rule that appears first in the grammar and report a parsing
+ conflict.
+<li> If both rules have precedence and the precedence is different
+ then resolve the dispute in favor of the rule with the highest
+ precedence and do not report a conflict.
+<li> Otherwise, resolve the conflict by reducing by the rule that
+ appears first in the grammar and report a parsing conflict.
+</ul>
+
+<h3>Special Directives</h3>
+
+<p>The input grammar to Lemon consists of grammar rules and special
+directives. We've described all the grammar rules, so now we'll
+talk about the special directives.</p>
+
+<p>Directives in lemon can occur in any order. You can put them before
+the grammar rules, or after the grammar rules, or in the mist of the
+grammar rules. It doesn't matter. The relative order of
+directives used to assign precedence to terminals is important, but
+other than that, the order of directives in Lemon is arbitrary.</p>
+
+<p>Lemon supports the following special directives:
+<ul>
+<li><tt>%code</tt>
+<li><tt>%default_destructor</tt>
+<li><tt>%default_type</tt>
+<li><tt>%destructor</tt>
+<li><tt>%extra_argument</tt>
+<li><tt>%include</tt>
+<li><tt>%left</tt>
+<li><tt>%name</tt>
+<li><tt>%nonassoc</tt>
+<li><tt>%parse_accept</tt>
+<li><tt>%parse_failure </tt>
+<li><tt>%right</tt>
+<li><tt>%stack_overflow</tt>
+<li><tt>%stack_size</tt>
+<li><tt>%start_symbol</tt>
+<li><tt>%syntax_error</tt>
+<li><tt>%token_destructor</tt>
+<li><tt>%token_prefix</tt>
+<li><tt>%token_type</tt>
+<li><tt>%type</tt>
+</ul>
+Each of these directives will be described separately in the
+following sections:</p>
+
+<h4>The <tt>%code</tt> directive</h4>
+
+<p>The %code directive is used to specify addition C/C++ code that
+is added to the end of the main output file. This is similar to
+the %include directive except that %include is inserted at the
+beginning of the main output file.</p>
+
+<p>%code is typically used to include some action routines or perhaps
+a tokenizer as part of the output file.</p>
+
+<h4>The <tt>%default_destructor</tt> directive</h4>
+
+<p>The %default_destructor directive specifies a destructor to
+use for non-terminals that do not have their own destructor
+specified by a separate %destructor directive. See the documentation
+on the %destructor directive below for additional information.</p>
+
+<p>In some grammers, many different non-terminal symbols have the
+same datatype and hence the same destructor. This directive is
+a convenience way to specify the same destructor for all those
+non-terminals using a single statement.</p>
+
+<h4>The <tt>%default_type</tt> directive</h4>
+
+<p>The %default_type directive specifies the datatype of non-terminal
+symbols that do no have their own datatype defined using a separate
+%type directive. See the documentation on %type below for addition
+information.</p>
+
+<h4>The <tt>%destructor</tt> directive</h4>
+
+<p>The %destructor directive is used to specify a destructor for
+a non-terminal symbol.
+(See also the %token_destructor directive which is used to
+specify a destructor for terminal symbols.)</p>
+
+<p>A non-terminal's destructor is called to dispose of the
+non-terminal's value whenever the non-terminal is popped from
+the stack. This includes all of the following circumstances:
+<ul>
+<li> When a rule reduces and the value of a non-terminal on
+ the right-hand side is not linked to C code.
+<li> When the stack is popped during error processing.
+<li> When the ParseFree() function runs.
+</ul>
+The destructor can do whatever it wants with the value of
+the non-terminal, but its design is to deallocate memory
+or other resources held by that non-terminal.</p>
+
+<p>Consider an example:
+<pre>
+ %type nt {void*}
+ %destructor nt { free($$); }
+ nt(A) ::= ID NUM. { A = malloc( 100 ); }
+</pre>
+This example is a bit contrived but it serves to illustrate how
+destructors work. The example shows a non-terminal named
+``nt'' that holds values of type ``void*''. When the rule for
+an ``nt'' reduces, it sets the value of the non-terminal to
+space obtained from malloc(). Later, when the nt non-terminal
+is popped from the stack, the destructor will fire and call
+free() on this malloced space, thus avoiding a memory leak.
+(Note that the symbol ``$$'' in the destructor code is replaced
+by the value of the non-terminal.)</p>
+
+<p>It is important to note that the value of a non-terminal is passed
+to the destructor whenever the non-terminal is removed from the
+stack, unless the non-terminal is used in a C-code action. If
+the non-terminal is used by C-code, then it is assumed that the
+C-code will take care of destroying it if it should really
+be destroyed. More commonly, the value is used to build some
+larger structure and we don't want to destroy it, which is why
+the destructor is not called in this circumstance.</p>
+
+<p>By appropriate use of destructors, it is possible to
+build a parser using Lemon that can be used within a long-running
+program, such as a GUI, that will not leak memory or other resources.
+To do the same using yacc or bison is much more difficult.</p>
+
+<h4>The <tt>%extra_argument</tt> directive</h4>
+
+The %extra_argument directive instructs Lemon to add a 4th parameter
+to the parameter list of the Parse() function it generates. Lemon
+doesn't do anything itself with this extra argument, but it does
+make the argument available to C-code action routines, destructors,
+and so forth. For example, if the grammar file contains:</p>
+
+<p><pre>
+ %extra_argument { MyStruct *pAbc }
+</pre></p>
+
+<p>Then the Parse() function generated will have an 4th parameter
+of type ``MyStruct*'' and all action routines will have access to
+a variable named ``pAbc'' that is the value of the 4th parameter
+in the most recent call to Parse().</p>
+
+<h4>The <tt>%include</tt> directive</h4>
+
+<p>The %include directive specifies C code that is included at the
+top of the generated parser. You can include any text you want --
+the Lemon parser generator copies it blindly. If you have multiple
+%include directives in your grammar file the value of the last
+%include directive overwrites all the others.</p.
+
+<p>The %include directive is very handy for getting some extra #include
+preprocessor statements at the beginning of the generated parser.
+For example:</p>
+
+<p><pre>
+ %include {#include &lt;unistd.h&gt;}
+</pre></p>
+
+<p>This might be needed, for example, if some of the C actions in the
+grammar call functions that are prototyed in unistd.h.</p>
+
+<h4>The <tt>%left</tt> directive</h4>
+
+The %left directive is used (along with the %right and
+%nonassoc directives) to declare precedences of terminal
+symbols. Every terminal symbol whose name appears after
+a %left directive but before the next period (``.'') is
+given the same left-associative precedence value. Subsequent
+%left directives have higher precedence. For example:</p>
+
+<p><pre>
+ %left AND.
+ %left OR.
+ %nonassoc EQ NE GT GE LT LE.
+ %left PLUS MINUS.
+ %left TIMES DIVIDE MOD.
+ %right EXP NOT.
+</pre></p>
+
+<p>Note the period that terminates each %left, %right or %nonassoc
+directive.</p>
+
+<p>LALR(1) grammars can get into a situation where they require
+a large amount of stack space if you make heavy use or right-associative
+operators. For this reason, it is recommended that you use %left
+rather than %right whenever possible.</p>
+
+<h4>The <tt>%name</tt> directive</h4>
+
+<p>By default, the functions generated by Lemon all begin with the
+five-character string ``Parse''. You can change this string to something
+different using the %name directive. For instance:</p>
+
+<p><pre>
+ %name Abcde
+</pre></p>
+
+<p>Putting this directive in the grammar file will cause Lemon to generate
+functions named
+<ul>
+<li> AbcdeAlloc(),
+<li> AbcdeFree(),
+<li> AbcdeTrace(), and
+<li> Abcde().
+</ul>
+The %name directive allows you to generator two or more different
+parsers and link them all into the same executable.
+</p>
+
+<h4>The <tt>%nonassoc</tt> directive</h4>
+
+<p>This directive is used to assign non-associative precedence to
+one or more terminal symbols. See the section on precedence rules
+or on the %left directive for additional information.</p>
+
+<h4>The <tt>%parse_accept</tt> directive</h4>
+
+<p>The %parse_accept directive specifies a block of C code that is
+executed whenever the parser accepts its input string. To ``accept''
+an input string means that the parser was able to process all tokens
+without error.</p>
+
+<p>For example:</p>
+
+<p><pre>
+ %parse_accept {
+ printf("parsing complete!\n");
+ }
+</pre></p>
+
+
+<h4>The <tt>%parse_failure</tt> directive</h4>
+
+<p>The %parse_failure directive specifies a block of C code that
+is executed whenever the parser fails complete. This code is not
+executed until the parser has tried and failed to resolve an input
+error using is usual error recovery strategy. The routine is
+only invoked when parsing is unable to continue.</p>
+
+<p><pre>
+ %parse_failure {
+ fprintf(stderr,"Giving up. Parser is hopelessly lost...\n");
+ }
+</pre></p>
+
+<h4>The <tt>%right</tt> directive</h4>
+
+<p>This directive is used to assign right-associative precedence to
+one or more terminal symbols. See the section on precedence rules
+or on the %left directive for additional information.</p>
+
+<h4>The <tt>%stack_overflow</tt> directive</h4>
+
+<p>The %stack_overflow directive specifies a block of C code that
+is executed if the parser's internal stack ever overflows. Typically
+this just prints an error message. After a stack overflow, the parser
+will be unable to continue and must be reset.</p>
+
+<p><pre>
+ %stack_overflow {
+ fprintf(stderr,"Giving up. Parser stack overflow\n");
+ }
+</pre></p>
+
+<p>You can help prevent parser stack overflows by avoiding the use
+of right recursion and right-precedence operators in your grammar.
+Use left recursion and and left-precedence operators instead, to
+encourage rules to reduce sooner and keep the stack size down.
+For example, do rules like this:
+<pre>
+ list ::= list element. // left-recursion. Good!
+ list ::= .
+</pre>
+Not like this:
+<pre>
+ list ::= element list. // right-recursion. Bad!
+ list ::= .
+</pre>
+
+<h4>The <tt>%stack_size</tt> directive</h4>
+
+<p>If stack overflow is a problem and you can't resolve the trouble
+by using left-recursion, then you might want to increase the size
+of the parser's stack using this directive. Put an positive integer
+after the %stack_size directive and Lemon will generate a parse
+with a stack of the requested size. The default value is 100.</p>
+
+<p><pre>
+ %stack_size 2000
+</pre></p>
+
+<h4>The <tt>%start_symbol</tt> directive</h4>
+
+<p>By default, the start-symbol for the grammar that Lemon generates
+is the first non-terminal that appears in the grammar file. But you
+can choose a different start-symbol using the %start_symbol directive.</p>
+
+<p><pre>
+ %start_symbol prog
+</pre></p>
+
+<h4>The <tt>%token_destructor</tt> directive</h4>
+
+<p>The %destructor directive assigns a destructor to a non-terminal
+symbol. (See the description of the %destructor directive above.)
+This directive does the same thing for all terminal symbols.</p>
+
+<p>Unlike non-terminal symbols which may each have a different data type
+for their values, terminals all use the same data type (defined by
+the %token_type directive) and so they use a common destructor. Other
+than that, the token destructor works just like the non-terminal
+destructors.</p>
+
+<h4>The <tt>%token_prefix</tt> directive</h4>
+
+<p>Lemon generates #defines that assign small integer constants
+to each terminal symbol in the grammar. If desired, Lemon will
+add a prefix specified by this directive
+to each of the #defines it generates.
+So if the default output of Lemon looked like this:
+<pre>
+ #define AND 1
+ #define MINUS 2
+ #define OR 3
+ #define PLUS 4
+</pre>
+You can insert a statement into the grammar like this:
+<pre>
+ %token_prefix TOKEN_
+</pre>
+to cause Lemon to produce these symbols instead:
+<pre>
+ #define TOKEN_AND 1
+ #define TOKEN_MINUS 2
+ #define TOKEN_OR 3
+ #define TOKEN_PLUS 4
+</pre>
+
+<h4>The <tt>%token_type</tt> and <tt>%type</tt> directives</h4>
+
+<p>These directives are used to specify the data types for values
+on the parser's stack associated with terminal and non-terminal
+symbols. The values of all terminal symbols must be of the same
+type. This turns out to be the same data type as the 3rd parameter
+to the Parse() function generated by Lemon. Typically, you will
+make the value of a terminal symbol by a pointer to some kind of
+token structure. Like this:</p>
+
+<p><pre>
+ %token_type {Token*}
+</pre></p>
+
+<p>If the data type of terminals is not specified, the default value
+is ``int''.</p>
+
+<p>Non-terminal symbols can each have their own data types. Typically
+the data type of a non-terminal is a pointer to the root of a parse-tree
+structure that contains all information about that non-terminal.
+For example:</p>
+
+<p><pre>
+ %type expr {Expr*}
+</pre></p>
+
+<p>Each entry on the parser's stack is actually a union containing
+instances of all data types for every non-terminal and terminal symbol.
+Lemon will automatically use the correct element of this union depending
+on what the corresponding non-terminal or terminal symbol is. But
+the grammar designer should keep in mind that the size of the union
+will be the size of its largest element. So if you have a single
+non-terminal whose data type requires 1K of storage, then your 100
+entry parser stack will require 100K of heap space. If you are willing
+and able to pay that price, fine. You just need to know.</p>
+
+<h3>Error Processing</h3>
+
+<p>After extensive experimentation over several years, it has been
+discovered that the error recovery strategy used by yacc is about
+as good as it gets. And so that is what Lemon uses.</p>
+
+<p>When a Lemon-generated parser encounters a syntax error, it
+first invokes the code specified by the %syntax_error directive, if
+any. It then enters its error recovery strategy. The error recovery
+strategy is to begin popping the parsers stack until it enters a
+state where it is permitted to shift a special non-terminal symbol
+named ``error''. It then shifts this non-terminal and continues
+parsing. But the %syntax_error routine will not be called again
+until at least three new tokens have been successfully shifted.</p>
+
+<p>If the parser pops its stack until the stack is empty, and it still
+is unable to shift the error symbol, then the %parse_failed routine
+is invoked and the parser resets itself to its start state, ready
+to begin parsing a new file. This is what will happen at the very
+first syntax error, of course, if there are no instances of the
+``error'' non-terminal in your grammar.</p>
+
+</body>
+</html>
diff --git a/tcllib/examples/page/lemon.peg b/tcllib/examples/page/lemon.peg
new file mode 100644
index 0000000..b0ca105
--- /dev/null
+++ b/tcllib/examples/page/lemon.peg
@@ -0,0 +1,141 @@
+# -* text -*-
+## PE grammar for the grammar specification language accepted by the
+## LEMON parser generator.
+
+
+## Questions:
+## Are directives always at the beginning of a line ?
+## Or can they start within a line ?
+
+## The ifdef/ifndef/endif directives are not documented.
+## Nor are the cmdline options
+
+
+PEG pg::peg::lemon (LemonGrammar)
+
+LemonGrammar <- SPACE Statement + EOF;
+
+Statement <- ( Directive
+ / Rule
+ ) SPACE;
+
+Rule <- Identifier Label? ASSIGN Definition DOT Precedence? Codeblock? ;
+Definition <- (Identifier Label?)* ;
+Label <- LPAREN Identifier RPAREN;
+Precedence <- LBRACKET Identifier RBRACKET;
+
+Directive <- DINTRO ( Code / DefaultDestructor
+ / DefaultType / Destructor
+ / ExtraArgument / Include
+ / Left / Name
+ / Nonassoc / ParseAccept
+ / ParseFailure / Right
+ / StackOverflow / Stacksize
+ / StartSymbol / SyntaxError
+ / TokenDestructor / TokenPrefix
+ / TokenType / Type
+ / Fallback
+ );
+
+Code <- DCODE Codeblock;
+DefaultDestructor <- DDEFDEST Identifier Codeblock;
+DefaultType <- DDEFTYPE Codeblock;
+Destructor <- DDEST Identifier Codeblock;
+ExtraArgument <- DEXTRA Codeblock;
+Include <- DINCL Codeblock;
+Left <- DLEFT Identifier+ DOT;
+Name <- DNAME Identifier ;
+Nonassoc <- DNON Identifier+ DOT;
+ParseAccept <- DPACC Codeblock;
+ParseFailure <- DPFAIL Codeblock;
+Right <- DRIGHT Identifier+ DOT;
+StackOverflow <- DSTKOVER Codeblock;
+Stacksize <- DSTKSZ NaturalNumber;
+StartSymbol <- DSTART Identifier;
+SyntaxError <- DSYNERR Codeblock;
+TokenDestructor <- DTOKDEST Identifier Codeblock;
+TokenPrefix <- DTOKPFX Identifier;
+TokenType <- DTOKTYPE Codeblock;
+Type <- DTYPE Identifier Codeblock;
+Fallback <- DFALLBK Identifier+ DOT;
+
+
+# Lexical layer
+
+match: Codeblock <- LBRACE ( Codeblock
+ / C_COMMENT
+ / Cplusplus_COMMENT
+ / (!RBRACE .)
+ )* RBRACE ;
+
+ Identifier <- Ident SPACE;
+match: Ident <- (<alpha>/'_') (<alnum>/'_')*;
+
+ NaturalNumber <- NatNum SPACE;
+match: NatNum <- [0-9]+;
+
+void: ASSIGN <- '::=' SPACE;
+void: DOT <- '.' SPACE;
+void: LPAREN <- '(' SPACE;
+void: RPAREN <- ')' SPACE;
+void: LBRACKET <- '[' SPACE;
+void: RBRACKET <- ']' SPACE;
+void: LBRACE <- '{';
+void: RBRACE <- '}';
+
+void: DINTRO <- '%';
+void: DCODE <- 'code' SPACE;
+void: DDEFDEST <- 'default_destructor' SPACE;
+void: DDEFTYPE <- 'default_type' SPACE;
+void: DDEST <- 'destructor' SPACE;
+void: DEXTRA <- 'extra_argument' SPACE;
+void: DINCL <- 'include' SPACE;
+void: DLEFT <- 'left' SPACE;
+void: DNAME <- 'name' SPACE;
+void: DNON <- 'nonassoc' SPACE;
+void: DPACC <- 'parse_accept' SPACE;
+void: DPFAIL <- 'parse_failure' SPACE;
+void: DRIGHT <- 'right' SPACE;
+void: DSTKOVER <- 'stack_overflow' SPACE;
+void: DSTKSZ <- 'stack_size' SPACE;
+void: DSTART <- 'start_symbol' SPACE;
+void: DSYNERR <- 'syntax_error' SPACE;
+void: DTOKDEST <- 'token_destructor' SPACE;
+void: DTOKPFX <- 'token_prefix' SPACE;
+void: DTOKTYPE <- 'token_type' SPACE;
+void: DTYPE <- 'type' SPACE;
+void: DFALLBK <- 'fallback' SPACE;
+
+# These have % in their definition because they
+# are not part of the regular directives.
+void: DIFDEF <- '%ifdef' SPACE;
+void: DIFNDEF <- '%ifndef' SPACE;
+void: DENDIF <- '%endif' SPACE;
+
+# Directives we do not really know about. They are in the SQLite
+# parse.y file, but are not documented for LEMON. We treat them as
+# whitespace for now, see below.
+
+Ifdef <- DIFDEF Identifier;
+Ifndef <- DIFNDEF Identifier;
+Endif <- DENDIF;
+
+
+# Whitespace
+
+void: SPACE <- ( [ \t\n\r]
+ / C_COMMENT
+ / Cplusplus_COMMENT
+ / Ifndef / Ifdef / Endif
+ )*;
+
+C_COMMENT <- CCOM_OPEN (!CCOM_CLOSE .)* CCOM_CLOSE;
+CCOM_OPEN <- '/*';
+CCOM_CLOSE <- '*/';
+
+Cplusplus_COMMENT <- '//' (!EOL .)* EOL;
+EOL <- '\r\n' / '\r' / '\n';
+
+EOF <- !.;
+
+END;
diff --git a/tcllib/examples/page/parse.y b/tcllib/examples/page/parse.y
new file mode 100644
index 0000000..5ecbb2e
--- /dev/null
+++ b/tcllib/examples/page/parse.y
@@ -0,0 +1,995 @@
+/*
+** 2001 September 15
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This file contains SQLite's grammar for SQL. Process this file
+** using the lemon parser generator to generate C code that runs
+** the parser. Lemon will also generate a header file containing
+** numeric codes for all of the tokens.
+**
+** @(#) $Id: parse.y,v 1.1 2005/09/28 04:51:19 andreas_kupries Exp $
+*/
+%token_prefix TK_
+%token_type {Token}
+%default_type {Token}
+%extra_argument {Parse *pParse}
+%syntax_error {
+ if( pParse->zErrMsg==0 ){
+ if( TOKEN.z[0] ){
+ sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
+ }else{
+ sqlite3ErrorMsg(pParse, "incomplete SQL statement");
+ }
+ }
+}
+%name sqlite3Parser
+%include {
+#include "sqliteInt.h"
+#include "parse.h"
+
+/*
+** An instance of this structure holds information about the
+** LIMIT clause of a SELECT statement.
+*/
+struct LimitVal {
+ Expr *pLimit; /* The LIMIT expression. NULL if there is no limit */
+ Expr *pOffset; /* The OFFSET expression. NULL if there is none */
+};
+
+/*
+** An instance of this structure is used to store the LIKE,
+** GLOB, NOT LIKE, and NOT GLOB operators.
+*/
+struct LikeOp {
+ int opcode; /* Either TK_GLOB or TK_LIKE */
+ int not; /* True if the NOT keyword is present */
+};
+
+/*
+** An instance of the following structure describes the event of a
+** TRIGGER. "a" is the event type, one of TK_UPDATE, TK_INSERT,
+** TK_DELETE, or TK_INSTEAD. If the event is of the form
+**
+** UPDATE ON (a,b,c)
+**
+** Then the "b" IdList records the list "a,b,c".
+*/
+struct TrigEvent { int a; IdList * b; };
+
+/*
+** An instance of this structure holds the ATTACH key and the key type.
+*/
+struct AttachKey { int type; Token key; };
+
+} // end %include
+
+// These are extra tokens used by the lexer but never seen by the
+// parser. We put them in a rule so that the parser generator will
+// add them to the parse.h output file.
+//
+%nonassoc END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION
+ COLUMN AGG_FUNCTION.
+
+// Input is a single SQL command
+input ::= cmdlist.
+cmdlist ::= cmdlist ecmd.
+cmdlist ::= ecmd.
+cmdx ::= cmd. { sqlite3FinishCoding(pParse); }
+ecmd ::= SEMI.
+ecmd ::= explain cmdx SEMI.
+explain ::= . { sqlite3BeginParse(pParse, 0); }
+%ifndef SQLITE_OMIT_EXPLAIN
+explain ::= EXPLAIN. { sqlite3BeginParse(pParse, 1); }
+%endif
+
+///////////////////// Begin and end transactions. ////////////////////////////
+//
+
+cmd ::= BEGIN transtype(Y) trans_opt. {sqlite3BeginTransaction(pParse, Y);}
+trans_opt ::= .
+trans_opt ::= TRANSACTION.
+trans_opt ::= TRANSACTION nm.
+%type transtype {int}
+transtype(A) ::= . {A = TK_DEFERRED;}
+transtype(A) ::= DEFERRED(X). {A = @X;}
+transtype(A) ::= IMMEDIATE(X). {A = @X;}
+transtype(A) ::= EXCLUSIVE(X). {A = @X;}
+cmd ::= COMMIT trans_opt. {sqlite3CommitTransaction(pParse);}
+cmd ::= END trans_opt. {sqlite3CommitTransaction(pParse);}
+cmd ::= ROLLBACK trans_opt. {sqlite3RollbackTransaction(pParse);}
+
+///////////////////// The CREATE TABLE statement ////////////////////////////
+//
+cmd ::= create_table create_table_args.
+create_table ::= CREATE(X) temp(T) TABLE nm(Y) dbnm(Z). {
+ sqlite3StartTable(pParse,&X,&Y,&Z,T,0);
+}
+%type temp {int}
+%ifndef SQLITE_OMIT_TEMPDB
+temp(A) ::= TEMP. {A = 1;}
+%endif
+temp(A) ::= . {A = 0;}
+create_table_args ::= LP columnlist conslist_opt(X) RP(Y). {
+ sqlite3EndTable(pParse,&X,&Y,0);
+}
+create_table_args ::= AS select(S). {
+ sqlite3EndTable(pParse,0,0,S);
+ sqlite3SelectDelete(S);
+}
+columnlist ::= columnlist COMMA column.
+columnlist ::= column.
+
+// About the only information used for a column is the name of the
+// column. The type is always just "text". But the code will accept
+// an elaborate typename. Perhaps someday we'll do something with it.
+//
+column(A) ::= columnid(X) type carglist. {
+ A.z = X.z;
+ A.n = (pParse->sLastToken.z-X.z) + pParse->sLastToken.n;
+}
+columnid(A) ::= nm(X). {
+ sqlite3AddColumn(pParse,&X);
+ A = X;
+}
+
+
+// An IDENTIFIER can be a generic identifier, or one of several
+// keywords. Any non-standard keyword can also be an identifier.
+//
+%type id {Token}
+id(A) ::= ID(X). {A = X;}
+
+// The following directive causes tokens ABORT, AFTER, ASC, etc. to
+// fallback to ID if they will not parse as their original value.
+// This obviates the need for the "id" nonterminal.
+//
+%fallback ID
+ ABORT AFTER ASC ATTACH BEFORE BEGIN CASCADE CONFLICT
+ DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR
+ GLOB IGNORE IMMEDIATE INITIALLY INSTEAD LIKE MATCH KEY
+ OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW STATEMENT
+ TEMP TRIGGER VACUUM VIEW
+%ifdef SQLITE_OMIT_COMPOUND_SELECT
+ EXCEPT INTERSECT UNION
+%endif
+ REINDEX RENAME CDATE CTIME CTIMESTAMP ALTER
+ .
+
+// Define operator precedence early so that this is the first occurance
+// of the operator tokens in the grammer. Keeping the operators together
+// causes them to be assigned integer values that are close together,
+// which keeps parser tables smaller.
+//
+// The token values assigned to these symbols is determined by the order
+// in which lemon first sees them. It must be the case that ISNULL/NOTNULL,
+// NE/EQ, GT/LE, and GE/LT are separated by only a single value. See
+// the sqlite3ExprIfFalse() routine for additional information on this
+// constraint.
+//
+%left OR.
+%left AND.
+%right NOT.
+%left IS LIKE GLOB BETWEEN IN ISNULL NOTNULL NE EQ.
+%left GT LE LT GE.
+%right ESCAPE.
+%left BITAND BITOR LSHIFT RSHIFT.
+%left PLUS MINUS.
+%left STAR SLASH REM.
+%left CONCAT.
+%right UMINUS UPLUS BITNOT.
+
+// And "ids" is an identifer-or-string.
+//
+%type ids {Token}
+ids(A) ::= ID(X). {A = X;}
+ids(A) ::= STRING(X). {A = X;}
+
+// The name of a column or table can be any of the following:
+//
+%type nm {Token}
+nm(A) ::= ID(X). {A = X;}
+nm(A) ::= STRING(X). {A = X;}
+nm(A) ::= JOIN_KW(X). {A = X;}
+
+type ::= .
+type ::= typename(X). {sqlite3AddColumnType(pParse,&X,&X);}
+type ::= typename(X) LP signed RP(Y). {sqlite3AddColumnType(pParse,&X,&Y);}
+type ::= typename(X) LP signed COMMA signed RP(Y).
+ {sqlite3AddColumnType(pParse,&X,&Y);}
+%type typename {Token}
+typename(A) ::= ids(X). {A = X;}
+typename(A) ::= typename(X) ids(Y). {A.z=X.z; A.n=Y.n+(Y.z-X.z);}
+%type signed {int}
+signed(A) ::= plus_num(X). { A = atoi(X.z); }
+signed(A) ::= minus_num(X). { A = -atoi(X.z); }
+carglist ::= carglist carg.
+carglist ::= .
+carg ::= CONSTRAINT nm ccons.
+carg ::= ccons.
+carg ::= DEFAULT term(X). {sqlite3AddDefaultValue(pParse,X);}
+carg ::= DEFAULT PLUS term(X). {sqlite3AddDefaultValue(pParse,X);}
+carg ::= DEFAULT MINUS term(X). {
+ Expr *p = sqlite3Expr(TK_UMINUS, X, 0, 0);
+ sqlite3AddDefaultValue(pParse,p);
+}
+carg ::= DEFAULT id(X). {
+ Expr *p = sqlite3Expr(TK_STRING, 0, 0, &X);
+ sqlite3AddDefaultValue(pParse,p);
+}
+
+// In addition to the type name, we also care about the primary key and
+// UNIQUE constraints.
+//
+ccons ::= NULL onconf.
+ccons ::= NOT NULL onconf(R). {sqlite3AddNotNull(pParse, R);}
+ccons ::= PRIMARY KEY sortorder onconf(R) autoinc(I).
+ {sqlite3AddPrimaryKey(pParse,0,R,I);}
+ccons ::= UNIQUE onconf(R). {sqlite3CreateIndex(pParse,0,0,0,0,R,0,0);}
+ccons ::= CHECK LP expr(X) RP onconf. {sqlite3ExprDelete(X);}
+ccons ::= REFERENCES nm(T) idxlist_opt(TA) refargs(R).
+ {sqlite3CreateForeignKey(pParse,0,&T,TA,R);}
+ccons ::= defer_subclause(D). {sqlite3DeferForeignKey(pParse,D);}
+ccons ::= COLLATE id(C). {sqlite3AddCollateType(pParse, C.z, C.n);}
+
+// The optional AUTOINCREMENT keyword
+%type autoinc {int}
+autoinc(X) ::= . {X = 0;}
+autoinc(X) ::= AUTOINCR. {X = 1;}
+
+// The next group of rules parses the arguments to a REFERENCES clause
+// that determine if the referential integrity checking is deferred or
+// or immediate and which determine what action to take if a ref-integ
+// check fails.
+//
+%type refargs {int}
+refargs(A) ::= . { A = OE_Restrict * 0x010101; }
+refargs(A) ::= refargs(X) refarg(Y). { A = (X & Y.mask) | Y.value; }
+%type refarg {struct {int value; int mask;}}
+refarg(A) ::= MATCH nm. { A.value = 0; A.mask = 0x000000; }
+refarg(A) ::= ON DELETE refact(X). { A.value = X; A.mask = 0x0000ff; }
+refarg(A) ::= ON UPDATE refact(X). { A.value = X<<8; A.mask = 0x00ff00; }
+refarg(A) ::= ON INSERT refact(X). { A.value = X<<16; A.mask = 0xff0000; }
+%type refact {int}
+refact(A) ::= SET NULL. { A = OE_SetNull; }
+refact(A) ::= SET DEFAULT. { A = OE_SetDflt; }
+refact(A) ::= CASCADE. { A = OE_Cascade; }
+refact(A) ::= RESTRICT. { A = OE_Restrict; }
+%type defer_subclause {int}
+defer_subclause(A) ::= NOT DEFERRABLE init_deferred_pred_opt(X). {A = X;}
+defer_subclause(A) ::= DEFERRABLE init_deferred_pred_opt(X). {A = X;}
+%type init_deferred_pred_opt {int}
+init_deferred_pred_opt(A) ::= . {A = 0;}
+init_deferred_pred_opt(A) ::= INITIALLY DEFERRED. {A = 1;}
+init_deferred_pred_opt(A) ::= INITIALLY IMMEDIATE. {A = 0;}
+
+// For the time being, the only constraint we care about is the primary
+// key and UNIQUE. Both create indices.
+//
+conslist_opt(A) ::= . {A.n = 0; A.z = 0;}
+conslist_opt(A) ::= COMMA(X) conslist. {A = X;}
+conslist ::= conslist COMMA tcons.
+conslist ::= conslist tcons.
+conslist ::= tcons.
+tcons ::= CONSTRAINT nm.
+tcons ::= PRIMARY KEY LP idxlist(X) autoinc(I) RP onconf(R).
+ {sqlite3AddPrimaryKey(pParse,X,R,I);}
+tcons ::= UNIQUE LP idxlist(X) RP onconf(R).
+ {sqlite3CreateIndex(pParse,0,0,0,X,R,0,0);}
+tcons ::= CHECK expr onconf.
+tcons ::= FOREIGN KEY LP idxlist(FA) RP
+ REFERENCES nm(T) idxlist_opt(TA) refargs(R) defer_subclause_opt(D). {
+ sqlite3CreateForeignKey(pParse, FA, &T, TA, R);
+ sqlite3DeferForeignKey(pParse, D);
+}
+%type defer_subclause_opt {int}
+defer_subclause_opt(A) ::= . {A = 0;}
+defer_subclause_opt(A) ::= defer_subclause(X). {A = X;}
+
+// The following is a non-standard extension that allows us to declare the
+// default behavior when there is a constraint conflict.
+//
+%type onconf {int}
+%type orconf {int}
+%type resolvetype {int}
+onconf(A) ::= . {A = OE_Default;}
+onconf(A) ::= ON CONFLICT resolvetype(X). {A = X;}
+orconf(A) ::= . {A = OE_Default;}
+orconf(A) ::= OR resolvetype(X). {A = X;}
+resolvetype(A) ::= raisetype(X). {A = X;}
+resolvetype(A) ::= IGNORE. {A = OE_Ignore;}
+resolvetype(A) ::= REPLACE. {A = OE_Replace;}
+
+////////////////////////// The DROP TABLE /////////////////////////////////////
+//
+cmd ::= DROP TABLE fullname(X). {
+ sqlite3DropTable(pParse, X, 0);
+}
+
+///////////////////// The CREATE VIEW statement /////////////////////////////
+//
+%ifndef SQLITE_OMIT_VIEW
+cmd ::= CREATE(X) temp(T) VIEW nm(Y) dbnm(Z) AS select(S). {
+ sqlite3CreateView(pParse, &X, &Y, &Z, S, T);
+}
+cmd ::= DROP VIEW fullname(X). {
+ sqlite3DropTable(pParse, X, 1);
+}
+%endif // SQLITE_OMIT_VIEW
+
+//////////////////////// The SELECT statement /////////////////////////////////
+//
+cmd ::= select(X). {
+ sqlite3Select(pParse, X, SRT_Callback, 0, 0, 0, 0, 0);
+ sqlite3SelectDelete(X);
+}
+
+%type select {Select*}
+%destructor select {sqlite3SelectDelete($$);}
+%type oneselect {Select*}
+%destructor oneselect {sqlite3SelectDelete($$);}
+
+select(A) ::= oneselect(X). {A = X;}
+%ifndef SQLITE_OMIT_COMPOUND_SELECT
+select(A) ::= select(X) multiselect_op(Y) oneselect(Z). {
+ if( Z ){
+ Z->op = Y;
+ Z->pPrior = X;
+ }
+ A = Z;
+}
+%type multiselect_op {int}
+multiselect_op(A) ::= UNION(OP). {A = @OP;}
+multiselect_op(A) ::= UNION ALL. {A = TK_ALL;}
+multiselect_op(A) ::= INTERSECT(OP). {A = @OP;}
+multiselect_op(A) ::= EXCEPT(OP). {A = @OP;}
+%endif // SQLITE_OMIT_COMPOUND_SELECT
+oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y)
+ groupby_opt(P) having_opt(Q) orderby_opt(Z) limit_opt(L). {
+ A = sqlite3SelectNew(W,X,Y,P,Q,Z,D,L.pLimit,L.pOffset);
+}
+
+// The "distinct" nonterminal is true (1) if the DISTINCT keyword is
+// present and false (0) if it is not.
+//
+%type distinct {int}
+distinct(A) ::= DISTINCT. {A = 1;}
+distinct(A) ::= ALL. {A = 0;}
+distinct(A) ::= . {A = 0;}
+
+// selcollist is a list of expressions that are to become the return
+// values of the SELECT statement. The "*" in statements like
+// "SELECT * FROM ..." is encoded as a special expression with an
+// opcode of TK_ALL.
+//
+%type selcollist {ExprList*}
+%destructor selcollist {sqlite3ExprListDelete($$);}
+%type sclp {ExprList*}
+%destructor sclp {sqlite3ExprListDelete($$);}
+sclp(A) ::= selcollist(X) COMMA. {A = X;}
+sclp(A) ::= . {A = 0;}
+selcollist(A) ::= sclp(P) expr(X) as(Y). {
+ A = sqlite3ExprListAppend(P,X,Y.n?&Y:0);
+}
+selcollist(A) ::= sclp(P) STAR. {
+ A = sqlite3ExprListAppend(P, sqlite3Expr(TK_ALL, 0, 0, 0), 0);
+}
+selcollist(A) ::= sclp(P) nm(X) DOT STAR. {
+ Expr *pRight = sqlite3Expr(TK_ALL, 0, 0, 0);
+ Expr *pLeft = sqlite3Expr(TK_ID, 0, 0, &X);
+ A = sqlite3ExprListAppend(P, sqlite3Expr(TK_DOT, pLeft, pRight, 0), 0);
+}
+
+// An option "AS <id>" phrase that can follow one of the expressions that
+// define the result set, or one of the tables in the FROM clause.
+//
+%type as {Token}
+as(X) ::= AS nm(Y). {X = Y;}
+as(X) ::= ids(Y). {X = Y;}
+as(X) ::= . {X.n = 0;}
+
+
+%type seltablist {SrcList*}
+%destructor seltablist {sqlite3SrcListDelete($$);}
+%type stl_prefix {SrcList*}
+%destructor stl_prefix {sqlite3SrcListDelete($$);}
+%type from {SrcList*}
+%destructor from {sqlite3SrcListDelete($$);}
+
+// A complete FROM clause.
+//
+from(A) ::= . {A = sqliteMalloc(sizeof(*A));}
+from(A) ::= FROM seltablist(X). {A = X;}
+
+// "seltablist" is a "Select Table List" - the content of the FROM clause
+// in a SELECT statement. "stl_prefix" is a prefix of this list.
+//
+stl_prefix(A) ::= seltablist(X) joinop(Y). {
+ A = X;
+ if( A && A->nSrc>0 ) A->a[A->nSrc-1].jointype = Y;
+}
+stl_prefix(A) ::= . {A = 0;}
+seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) on_opt(N) using_opt(U). {
+ A = sqlite3SrcListAppend(X,&Y,&D);
+ if( Z.n ) sqlite3SrcListAddAlias(A,&Z);
+ if( N ){
+ if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pOn = N; }
+ else { sqlite3ExprDelete(N); }
+ }
+ if( U ){
+ if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pUsing = U; }
+ else { sqlite3IdListDelete(U); }
+ }
+}
+%ifndef SQLITE_OMIT_SUBQUERY
+ seltablist(A) ::= stl_prefix(X) LP seltablist_paren(S) RP
+ as(Z) on_opt(N) using_opt(U). {
+ A = sqlite3SrcListAppend(X,0,0);
+ A->a[A->nSrc-1].pSelect = S;
+ if( Z.n ) sqlite3SrcListAddAlias(A,&Z);
+ if( N ){
+ if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pOn = N; }
+ else { sqlite3ExprDelete(N); }
+ }
+ if( U ){
+ if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pUsing = U; }
+ else { sqlite3IdListDelete(U); }
+ }
+ }
+
+ // A seltablist_paren nonterminal represents anything in a FROM that
+ // is contained inside parentheses. This can be either a subquery or
+ // a grouping of table and subqueries.
+ //
+ %type seltablist_paren {Select*}
+ %destructor seltablist_paren {sqlite3SelectDelete($$);}
+ seltablist_paren(A) ::= select(S). {A = S;}
+ seltablist_paren(A) ::= seltablist(F). {
+ A = sqlite3SelectNew(0,F,0,0,0,0,0,0,0);
+ }
+%endif // SQLITE_OMIT_SUBQUERY
+
+%type dbnm {Token}
+dbnm(A) ::= . {A.z=0; A.n=0;}
+dbnm(A) ::= DOT nm(X). {A = X;}
+
+%type fullname {SrcList*}
+%destructor fullname {sqlite3SrcListDelete($$);}
+fullname(A) ::= nm(X) dbnm(Y). {A = sqlite3SrcListAppend(0,&X,&Y);}
+
+%type joinop {int}
+%type joinop2 {int}
+joinop(X) ::= COMMA. { X = JT_INNER; }
+joinop(X) ::= JOIN. { X = JT_INNER; }
+joinop(X) ::= JOIN_KW(A) JOIN. { X = sqlite3JoinType(pParse,&A,0,0); }
+joinop(X) ::= JOIN_KW(A) nm(B) JOIN. { X = sqlite3JoinType(pParse,&A,&B,0); }
+joinop(X) ::= JOIN_KW(A) nm(B) nm(C) JOIN.
+ { X = sqlite3JoinType(pParse,&A,&B,&C); }
+
+%type on_opt {Expr*}
+%destructor on_opt {sqlite3ExprDelete($$);}
+on_opt(N) ::= ON expr(E). {N = E;}
+on_opt(N) ::= . {N = 0;}
+
+%type using_opt {IdList*}
+%destructor using_opt {sqlite3IdListDelete($$);}
+using_opt(U) ::= USING LP inscollist(L) RP. {U = L;}
+using_opt(U) ::= . {U = 0;}
+
+
+%type orderby_opt {ExprList*}
+%destructor orderby_opt {sqlite3ExprListDelete($$);}
+%type sortlist {ExprList*}
+%destructor sortlist {sqlite3ExprListDelete($$);}
+%type sortitem {Expr*}
+%destructor sortitem {sqlite3ExprDelete($$);}
+
+orderby_opt(A) ::= . {A = 0;}
+orderby_opt(A) ::= ORDER BY sortlist(X). {A = X;}
+sortlist(A) ::= sortlist(X) COMMA sortitem(Y) collate(C) sortorder(Z). {
+ A = sqlite3ExprListAppend(X,Y,C.n>0?&C:0);
+ if( A ) A->a[A->nExpr-1].sortOrder = Z;
+}
+sortlist(A) ::= sortitem(Y) collate(C) sortorder(Z). {
+ A = sqlite3ExprListAppend(0,Y,C.n>0?&C:0);
+ if( A && A->a ) A->a[0].sortOrder = Z;
+}
+sortitem(A) ::= expr(X). {A = X;}
+
+%type sortorder {int}
+%type collate {Token}
+
+sortorder(A) ::= ASC. {A = SQLITE_SO_ASC;}
+sortorder(A) ::= DESC. {A = SQLITE_SO_DESC;}
+sortorder(A) ::= . {A = SQLITE_SO_ASC;}
+collate(C) ::= . {C.z = 0; C.n = 0;}
+collate(C) ::= COLLATE id(X). {C = X;}
+
+%type groupby_opt {ExprList*}
+%destructor groupby_opt {sqlite3ExprListDelete($$);}
+groupby_opt(A) ::= . {A = 0;}
+groupby_opt(A) ::= GROUP BY exprlist(X). {A = X;}
+
+%type having_opt {Expr*}
+%destructor having_opt {sqlite3ExprDelete($$);}
+having_opt(A) ::= . {A = 0;}
+having_opt(A) ::= HAVING expr(X). {A = X;}
+
+%type limit_opt {struct LimitVal}
+%destructor limit_opt {
+ sqlite3ExprDelete($$.pLimit);
+ sqlite3ExprDelete($$.pOffset);
+}
+limit_opt(A) ::= . {A.pLimit = 0; A.pOffset = 0;}
+limit_opt(A) ::= LIMIT expr(X). {A.pLimit = X; A.pOffset = 0;}
+limit_opt(A) ::= LIMIT expr(X) OFFSET expr(Y).
+ {A.pLimit = X; A.pOffset = Y;}
+limit_opt(A) ::= LIMIT expr(X) COMMA expr(Y).
+ {A.pOffset = X; A.pLimit = Y;}
+
+/////////////////////////// The DELETE statement /////////////////////////////
+//
+cmd ::= DELETE FROM fullname(X) where_opt(Y). {sqlite3DeleteFrom(pParse,X,Y);}
+
+%type where_opt {Expr*}
+%destructor where_opt {sqlite3ExprDelete($$);}
+
+where_opt(A) ::= . {A = 0;}
+where_opt(A) ::= WHERE expr(X). {A = X;}
+
+%type setlist {ExprList*}
+%destructor setlist {sqlite3ExprListDelete($$);}
+
+////////////////////////// The UPDATE command ////////////////////////////////
+//
+cmd ::= UPDATE orconf(R) fullname(X) SET setlist(Y) where_opt(Z).
+ {sqlite3Update(pParse,X,Y,Z,R);}
+
+setlist(A) ::= setlist(Z) COMMA nm(X) EQ expr(Y).
+ {A = sqlite3ExprListAppend(Z,Y,&X);}
+setlist(A) ::= nm(X) EQ expr(Y). {A = sqlite3ExprListAppend(0,Y,&X);}
+
+////////////////////////// The INSERT command /////////////////////////////////
+//
+cmd ::= insert_cmd(R) INTO fullname(X) inscollist_opt(F)
+ VALUES LP itemlist(Y) RP.
+ {sqlite3Insert(pParse, X, Y, 0, F, R);}
+cmd ::= insert_cmd(R) INTO fullname(X) inscollist_opt(F) select(S).
+ {sqlite3Insert(pParse, X, 0, S, F, R);}
+
+%type insert_cmd {int}
+insert_cmd(A) ::= INSERT orconf(R). {A = R;}
+insert_cmd(A) ::= REPLACE. {A = OE_Replace;}
+
+
+%type itemlist {ExprList*}
+%destructor itemlist {sqlite3ExprListDelete($$);}
+
+itemlist(A) ::= itemlist(X) COMMA expr(Y). {A = sqlite3ExprListAppend(X,Y,0);}
+itemlist(A) ::= expr(X). {A = sqlite3ExprListAppend(0,X,0);}
+
+%type inscollist_opt {IdList*}
+%destructor inscollist_opt {sqlite3IdListDelete($$);}
+%type inscollist {IdList*}
+%destructor inscollist {sqlite3IdListDelete($$);}
+
+inscollist_opt(A) ::= . {A = 0;}
+inscollist_opt(A) ::= LP inscollist(X) RP. {A = X;}
+inscollist(A) ::= inscollist(X) COMMA nm(Y). {A = sqlite3IdListAppend(X,&Y);}
+inscollist(A) ::= nm(Y). {A = sqlite3IdListAppend(0,&Y);}
+
+/////////////////////////// Expression Processing /////////////////////////////
+//
+
+%type expr {Expr*}
+%destructor expr {sqlite3ExprDelete($$);}
+%type term {Expr*}
+%destructor term {sqlite3ExprDelete($$);}
+
+expr(A) ::= term(X). {A = X;}
+expr(A) ::= LP(B) expr(X) RP(E). {A = X; sqlite3ExprSpan(A,&B,&E); }
+term(A) ::= NULL(X). {A = sqlite3Expr(@X, 0, 0, &X);}
+expr(A) ::= ID(X). {A = sqlite3Expr(TK_ID, 0, 0, &X);}
+expr(A) ::= JOIN_KW(X). {A = sqlite3Expr(TK_ID, 0, 0, &X);}
+expr(A) ::= nm(X) DOT nm(Y). {
+ Expr *temp1 = sqlite3Expr(TK_ID, 0, 0, &X);
+ Expr *temp2 = sqlite3Expr(TK_ID, 0, 0, &Y);
+ A = sqlite3Expr(TK_DOT, temp1, temp2, 0);
+}
+expr(A) ::= nm(X) DOT nm(Y) DOT nm(Z). {
+ Expr *temp1 = sqlite3Expr(TK_ID, 0, 0, &X);
+ Expr *temp2 = sqlite3Expr(TK_ID, 0, 0, &Y);
+ Expr *temp3 = sqlite3Expr(TK_ID, 0, 0, &Z);
+ Expr *temp4 = sqlite3Expr(TK_DOT, temp2, temp3, 0);
+ A = sqlite3Expr(TK_DOT, temp1, temp4, 0);
+}
+term(A) ::= INTEGER(X). {A = sqlite3Expr(@X, 0, 0, &X);}
+term(A) ::= FLOAT(X). {A = sqlite3Expr(@X, 0, 0, &X);}
+term(A) ::= STRING(X). {A = sqlite3Expr(@X, 0, 0, &X);}
+term(A) ::= BLOB(X). {A = sqlite3Expr(@X, 0, 0, &X);}
+expr(A) ::= REGISTER(X). {A = sqlite3RegisterExpr(pParse, &X);}
+expr(A) ::= VARIABLE(X). {
+ Token *pToken = &X;
+ Expr *pExpr = A = sqlite3Expr(TK_VARIABLE, 0, 0, pToken);
+ sqlite3ExprAssignVarNumber(pParse, pExpr);
+}
+expr(A) ::= ID(X) LP exprlist(Y) RP(E). {
+ A = sqlite3ExprFunction(Y, &X);
+ sqlite3ExprSpan(A,&X,&E);
+}
+expr(A) ::= ID(X) LP STAR RP(E). {
+ A = sqlite3ExprFunction(0, &X);
+ sqlite3ExprSpan(A,&X,&E);
+}
+term(A) ::= CTIME(OP). {A = sqlite3Expr(@OP,0,0,0);}
+term(A) ::= CDATE(OP). {A = sqlite3Expr(@OP,0,0,0);}
+term(A) ::= CTIMESTAMP(OP). {A = sqlite3Expr(@OP,0,0,0);}
+expr(A) ::= expr(X) AND(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
+expr(A) ::= expr(X) OR(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
+expr(A) ::= expr(X) LT(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
+expr(A) ::= expr(X) GT(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
+expr(A) ::= expr(X) LE(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
+expr(A) ::= expr(X) GE(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
+expr(A) ::= expr(X) NE(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
+expr(A) ::= expr(X) EQ(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
+expr(A) ::= expr(X) BITAND(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
+expr(A) ::= expr(X) BITOR(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
+expr(A) ::= expr(X) LSHIFT(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
+expr(A) ::= expr(X) RSHIFT(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
+expr(A) ::= expr(X) PLUS(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
+expr(A) ::= expr(X) MINUS(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
+expr(A) ::= expr(X) STAR(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
+expr(A) ::= expr(X) SLASH(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
+expr(A) ::= expr(X) REM(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
+expr(A) ::= expr(X) CONCAT(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
+%type likeop {struct LikeOp}
+likeop(A) ::= LIKE. {A.opcode = TK_LIKE; A.not = 0;}
+likeop(A) ::= GLOB. {A.opcode = TK_GLOB; A.not = 0;}
+likeop(A) ::= NOT LIKE. {A.opcode = TK_LIKE; A.not = 1;}
+likeop(A) ::= NOT GLOB. {A.opcode = TK_GLOB; A.not = 1;}
+%type escape {Expr*}
+escape(X) ::= ESCAPE expr(A). [ESCAPE] {X = A;}
+escape(X) ::= . [ESCAPE] {X = 0;}
+expr(A) ::= expr(X) likeop(OP) expr(Y) escape(E). [LIKE] {
+ ExprList *pList = sqlite3ExprListAppend(0, Y, 0);
+ pList = sqlite3ExprListAppend(pList, X, 0);
+ if( E ){
+ pList = sqlite3ExprListAppend(pList, E, 0);
+ }
+ A = sqlite3ExprFunction(pList, 0);
+ if( A ) A->op = OP.opcode;
+ if( OP.not ) A = sqlite3Expr(TK_NOT, A, 0, 0);
+ sqlite3ExprSpan(A, &X->span, &Y->span);
+}
+
+expr(A) ::= expr(X) ISNULL(E). {
+ A = sqlite3Expr(TK_ISNULL, X, 0, 0);
+ sqlite3ExprSpan(A,&X->span,&E);
+}
+expr(A) ::= expr(X) IS NULL(E). {
+ A = sqlite3Expr(TK_ISNULL, X, 0, 0);
+ sqlite3ExprSpan(A,&X->span,&E);
+}
+expr(A) ::= expr(X) NOTNULL(E). {
+ A = sqlite3Expr(TK_NOTNULL, X, 0, 0);
+ sqlite3ExprSpan(A,&X->span,&E);
+}
+expr(A) ::= expr(X) NOT NULL(E). {
+ A = sqlite3Expr(TK_NOTNULL, X, 0, 0);
+ sqlite3ExprSpan(A,&X->span,&E);
+}
+expr(A) ::= expr(X) IS NOT NULL(E). {
+ A = sqlite3Expr(TK_NOTNULL, X, 0, 0);
+ sqlite3ExprSpan(A,&X->span,&E);
+}
+expr(A) ::= NOT(B) expr(X). {
+ A = sqlite3Expr(@B, X, 0, 0);
+ sqlite3ExprSpan(A,&B,&X->span);
+}
+expr(A) ::= BITNOT(B) expr(X). {
+ A = sqlite3Expr(@B, X, 0, 0);
+ sqlite3ExprSpan(A,&B,&X->span);
+}
+expr(A) ::= MINUS(B) expr(X). [UMINUS] {
+ A = sqlite3Expr(TK_UMINUS, X, 0, 0);
+ sqlite3ExprSpan(A,&B,&X->span);
+}
+expr(A) ::= PLUS(B) expr(X). [UPLUS] {
+ A = sqlite3Expr(TK_UPLUS, X, 0, 0);
+ sqlite3ExprSpan(A,&B,&X->span);
+}
+%type between_op {int}
+between_op(A) ::= BETWEEN. {A = 0;}
+between_op(A) ::= NOT BETWEEN. {A = 1;}
+expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
+ ExprList *pList = sqlite3ExprListAppend(0, X, 0);
+ pList = sqlite3ExprListAppend(pList, Y, 0);
+ A = sqlite3Expr(TK_BETWEEN, W, 0, 0);
+ if( A ) A->pList = pList;
+ if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0);
+ sqlite3ExprSpan(A,&W->span,&Y->span);
+}
+%ifndef SQLITE_OMIT_SUBQUERY
+ %type in_op {int}
+ in_op(A) ::= IN. {A = 0;}
+ in_op(A) ::= NOT IN. {A = 1;}
+ expr(A) ::= expr(X) in_op(N) LP exprlist(Y) RP(E). [IN] {
+ A = sqlite3Expr(TK_IN, X, 0, 0);
+ if( A ){
+ A->pList = Y;
+ }else{
+ sqlite3ExprListDelete(Y);
+ }
+ if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0);
+ sqlite3ExprSpan(A,&X->span,&E);
+ }
+ expr(A) ::= LP(B) select(X) RP(E). {
+ A = sqlite3Expr(TK_SELECT, 0, 0, 0);
+ if( A ) A->pSelect = X;
+ if( !A ) sqlite3SelectDelete(X);
+ sqlite3ExprSpan(A,&B,&E);
+ }
+ expr(A) ::= expr(X) in_op(N) LP select(Y) RP(E). [IN] {
+ A = sqlite3Expr(TK_IN, X, 0, 0);
+ if( A ) A->pSelect = Y;
+ if( !A ) sqlite3SelectDelete(Y);
+ if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0);
+ sqlite3ExprSpan(A,&X->span,&E);
+ }
+ expr(A) ::= expr(X) in_op(N) nm(Y) dbnm(Z). [IN] {
+ SrcList *pSrc = sqlite3SrcListAppend(0,&Y,&Z);
+ A = sqlite3Expr(TK_IN, X, 0, 0);
+ if( A ) A->pSelect = sqlite3SelectNew(0,pSrc,0,0,0,0,0,0,0);
+ if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0);
+ sqlite3ExprSpan(A,&X->span,Z.z?&Z:&Y);
+ }
+ expr(A) ::= EXISTS(B) LP select(Y) RP(E). {
+ Expr *p = A = sqlite3Expr(TK_EXISTS, 0, 0, 0);
+ if( p ){
+ p->pSelect = Y;
+ sqlite3ExprSpan(p,&B,&E);
+ }
+ if( !p ) sqlite3SelectDelete(Y);
+ }
+%endif // SQLITE_OMIT_SUBQUERY
+
+/* CASE expressions */
+expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
+ A = sqlite3Expr(TK_CASE, X, Z, 0);
+ if( A ) A->pList = Y;
+ sqlite3ExprSpan(A, &C, &E);
+}
+%type case_exprlist {ExprList*}
+%destructor case_exprlist {sqlite3ExprListDelete($$);}
+case_exprlist(A) ::= case_exprlist(X) WHEN expr(Y) THEN expr(Z). {
+ A = sqlite3ExprListAppend(X, Y, 0);
+ A = sqlite3ExprListAppend(A, Z, 0);
+}
+case_exprlist(A) ::= WHEN expr(Y) THEN expr(Z). {
+ A = sqlite3ExprListAppend(0, Y, 0);
+ A = sqlite3ExprListAppend(A, Z, 0);
+}
+%type case_else {Expr*}
+case_else(A) ::= ELSE expr(X). {A = X;}
+case_else(A) ::= . {A = 0;}
+%type case_operand {Expr*}
+case_operand(A) ::= expr(X). {A = X;}
+case_operand(A) ::= . {A = 0;}
+
+%type exprlist {ExprList*}
+%destructor exprlist {sqlite3ExprListDelete($$);}
+%type expritem {Expr*}
+%destructor expritem {sqlite3ExprDelete($$);}
+
+exprlist(A) ::= exprlist(X) COMMA expritem(Y).
+ {A = sqlite3ExprListAppend(X,Y,0);}
+exprlist(A) ::= expritem(X). {A = sqlite3ExprListAppend(0,X,0);}
+expritem(A) ::= expr(X). {A = X;}
+expritem(A) ::= . {A = 0;}
+
+///////////////////////////// The CREATE INDEX command ///////////////////////
+//
+cmd ::= CREATE(S) uniqueflag(U) INDEX nm(X) dbnm(D)
+ ON nm(Y) LP idxlist(Z) RP(E) onconf(R). {
+ if( U!=OE_None ) U = R;
+ if( U==OE_Default) U = OE_Abort;
+ sqlite3CreateIndex(pParse, &X, &D, sqlite3SrcListAppend(0,&Y,0),Z,U, &S, &E);
+}
+
+%type uniqueflag {int}
+uniqueflag(A) ::= UNIQUE. {A = OE_Abort;}
+uniqueflag(A) ::= . {A = OE_None;}
+
+%type idxlist {ExprList*}
+%destructor idxlist {sqlite3ExprListDelete($$);}
+%type idxlist_opt {ExprList*}
+%destructor idxlist_opt {sqlite3ExprListDelete($$);}
+%type idxitem {Token}
+
+idxlist_opt(A) ::= . {A = 0;}
+idxlist_opt(A) ::= LP idxlist(X) RP. {A = X;}
+idxlist(A) ::= idxlist(X) COMMA idxitem(Y) collate(C) sortorder. {
+ Expr *p = 0;
+ if( C.n>0 ){
+ p = sqlite3Expr(TK_COLUMN, 0, 0, 0);
+ if( p ) p->pColl = sqlite3LocateCollSeq(pParse, C.z, C.n);
+ }
+ A = sqlite3ExprListAppend(X, p, &Y);
+}
+idxlist(A) ::= idxitem(Y) collate(C) sortorder. {
+ Expr *p = 0;
+ if( C.n>0 ){
+ p = sqlite3Expr(TK_COLUMN, 0, 0, 0);
+ if( p ) p->pColl = sqlite3LocateCollSeq(pParse, C.z, C.n);
+ }
+ A = sqlite3ExprListAppend(0, p, &Y);
+}
+idxitem(A) ::= nm(X). {A = X;}
+
+
+///////////////////////////// The DROP INDEX command /////////////////////////
+//
+cmd ::= DROP INDEX fullname(X). {sqlite3DropIndex(pParse, X);}
+
+///////////////////////////// The VACUUM command /////////////////////////////
+//
+cmd ::= VACUUM. {sqlite3Vacuum(pParse,0);}
+cmd ::= VACUUM nm. {sqlite3Vacuum(pParse,0);}
+
+///////////////////////////// The PRAGMA command /////////////////////////////
+//
+%ifndef SQLITE_OMIT_PRAGMA
+cmd ::= PRAGMA nm(X) dbnm(Z) EQ nm(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
+cmd ::= PRAGMA nm(X) dbnm(Z) EQ ON(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
+cmd ::= PRAGMA nm(X) dbnm(Z) EQ plus_num(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
+cmd ::= PRAGMA nm(X) dbnm(Z) EQ minus_num(Y). {
+ sqlite3Pragma(pParse,&X,&Z,&Y,1);
+}
+cmd ::= PRAGMA nm(X) dbnm(Z) LP nm(Y) RP. {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
+cmd ::= PRAGMA nm(X) dbnm(Z). {sqlite3Pragma(pParse,&X,&Z,0,0);}
+%endif // SQLITE_OMIT_PRAGMA
+plus_num(A) ::= plus_opt number(X). {A = X;}
+minus_num(A) ::= MINUS number(X). {A = X;}
+number(A) ::= INTEGER(X). {A = X;}
+number(A) ::= FLOAT(X). {A = X;}
+plus_opt ::= PLUS.
+plus_opt ::= .
+
+//////////////////////////// The CREATE TRIGGER command /////////////////////
+
+%ifndef SQLITE_OMIT_TRIGGER
+
+cmd ::= CREATE trigger_decl(A) BEGIN trigger_cmd_list(S) END(Z). {
+ Token all;
+ all.z = A.z;
+ all.n = (Z.z - A.z) + Z.n;
+ sqlite3FinishTrigger(pParse, S, &all);
+}
+
+trigger_decl(A) ::= temp(T) TRIGGER nm(B) dbnm(Z) trigger_time(C)
+ trigger_event(D)
+ ON fullname(E) foreach_clause(F) when_clause(G). {
+ sqlite3BeginTrigger(pParse, &B, &Z, C, D.a, D.b, E, F, G, T);
+ A = (Z.n==0?B:Z);
+}
+
+%type trigger_time {int}
+trigger_time(A) ::= BEFORE. { A = TK_BEFORE; }
+trigger_time(A) ::= AFTER. { A = TK_AFTER; }
+trigger_time(A) ::= INSTEAD OF. { A = TK_INSTEAD;}
+trigger_time(A) ::= . { A = TK_BEFORE; }
+
+%type trigger_event {struct TrigEvent}
+%destructor trigger_event {sqlite3IdListDelete($$.b);}
+trigger_event(A) ::= DELETE(OP). {A.a = @OP; A.b = 0;}
+trigger_event(A) ::= INSERT(OP). {A.a = @OP; A.b = 0;}
+trigger_event(A) ::= UPDATE(OP). {A.a = @OP; A.b = 0;}
+trigger_event(A) ::= UPDATE OF inscollist(X). {A.a = TK_UPDATE; A.b = X;}
+
+%type foreach_clause {int}
+foreach_clause(A) ::= . { A = TK_ROW; }
+foreach_clause(A) ::= FOR EACH ROW. { A = TK_ROW; }
+foreach_clause(A) ::= FOR EACH STATEMENT. { A = TK_STATEMENT; }
+
+%type when_clause {Expr*}
+when_clause(A) ::= . { A = 0; }
+when_clause(A) ::= WHEN expr(X). { A = X; }
+
+%type trigger_cmd_list {TriggerStep*}
+%destructor trigger_cmd_list {sqlite3DeleteTriggerStep($$);}
+trigger_cmd_list(A) ::= trigger_cmd(X) SEMI trigger_cmd_list(Y). {
+ X->pNext = Y;
+ A = X;
+}
+trigger_cmd_list(A) ::= . { A = 0; }
+
+%type trigger_cmd {TriggerStep*}
+%destructor trigger_cmd {sqlite3DeleteTriggerStep($$);}
+// UPDATE
+trigger_cmd(A) ::= UPDATE orconf(R) nm(X) SET setlist(Y) where_opt(Z).
+ { A = sqlite3TriggerUpdateStep(&X, Y, Z, R); }
+
+// INSERT
+trigger_cmd(A) ::= insert_cmd(R) INTO nm(X) inscollist_opt(F)
+ VALUES LP itemlist(Y) RP.
+ {A = sqlite3TriggerInsertStep(&X, F, Y, 0, R);}
+
+trigger_cmd(A) ::= insert_cmd(R) INTO nm(X) inscollist_opt(F) select(S).
+ {A = sqlite3TriggerInsertStep(&X, F, 0, S, R);}
+
+// DELETE
+trigger_cmd(A) ::= DELETE FROM nm(X) where_opt(Y).
+ {A = sqlite3TriggerDeleteStep(&X, Y);}
+
+// SELECT
+trigger_cmd(A) ::= select(X). {A = sqlite3TriggerSelectStep(X); }
+
+// The special RAISE expression that may occur in trigger programs
+expr(A) ::= RAISE(X) LP IGNORE RP(Y). {
+ A = sqlite3Expr(TK_RAISE, 0, 0, 0);
+ A->iColumn = OE_Ignore;
+ sqlite3ExprSpan(A, &X, &Y);
+}
+expr(A) ::= RAISE(X) LP raisetype(T) COMMA nm(Z) RP(Y). {
+ A = sqlite3Expr(TK_RAISE, 0, 0, &Z);
+ A->iColumn = T;
+ sqlite3ExprSpan(A, &X, &Y);
+}
+%endif // !SQLITE_OMIT_TRIGGER
+
+%type raisetype {int}
+raisetype(A) ::= ROLLBACK. {A = OE_Rollback;}
+raisetype(A) ::= ABORT. {A = OE_Abort;}
+raisetype(A) ::= FAIL. {A = OE_Fail;}
+
+
+//////////////////////// DROP TRIGGER statement //////////////////////////////
+%ifndef SQLITE_OMIT_TRIGGER
+cmd ::= DROP TRIGGER fullname(X). {
+ sqlite3DropTrigger(pParse,X);
+}
+%endif // !SQLITE_OMIT_TRIGGER
+
+//////////////////////// ATTACH DATABASE file AS name /////////////////////////
+cmd ::= ATTACH database_kw_opt ids(F) AS nm(D) key_opt(K). {
+ sqlite3Attach(pParse, &F, &D, K.type, &K.key);
+}
+%type key_opt {struct AttachKey}
+key_opt(A) ::= . { A.type = 0; }
+key_opt(A) ::= KEY ids(X). { A.type=1; A.key = X; }
+key_opt(A) ::= KEY BLOB(X). { A.type=2; A.key = X; }
+
+database_kw_opt ::= DATABASE.
+database_kw_opt ::= .
+
+//////////////////////// DETACH DATABASE name /////////////////////////////////
+cmd ::= DETACH database_kw_opt nm(D). {
+ sqlite3Detach(pParse, &D);
+}
+
+////////////////////////// REINDEX collation //////////////////////////////////
+%ifndef SQLITE_OMIT_REINDEX
+cmd ::= REINDEX. {sqlite3Reindex(pParse, 0, 0);}
+cmd ::= REINDEX nm(X) dbnm(Y). {sqlite3Reindex(pParse, &X, &Y);}
+%endif
+
+//////////////////////// ALTER TABLE table ... ////////////////////////////////
+%ifndef SQLITE_OMIT_ALTERTABLE
+cmd ::= ALTER TABLE fullname(X) RENAME TO nm(Z). {
+ sqlite3AlterRenameTable(pParse,X,&Z);
+}
+cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column(Y). {
+ sqlite3AlterFinishAddColumn(pParse, &Y);
+}
+add_column_fullname ::= fullname(X). {
+ sqlite3AlterBeginAddColumn(pParse, X);
+}
+kwcolumn_opt ::= .
+kwcolumn_opt ::= COLUMNKW.
+%endif
diff --git a/tcllib/examples/page/sql.log b/tcllib/examples/page/sql.log
new file mode 100644
index 0000000..644931b
--- /dev/null
+++ b/tcllib/examples/page/sql.log
@@ -0,0 +1,18 @@
+Reading grammar from file ../parse.y [Lemon specification]
+.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|.........|.........|.........|.........|.........*.........|.........|.........|.........|.........|......
+Stats ME. Microseconds: 27550504
+ . Seconds: 27.550504
+ . Characters: 35565
+ . Microsec/Char: 774.652158021
+ . Char/Seconds: 1290.90197406
+<Name: sqlite3Parser
+*TD
+Startsymbol: input
+REALf>
+
+Read 35565 characters
+Writing to file examples/pg/sql.peg [Canonical PEG]
+
+real 1m0.781s
+user 0m58.870s
+sys 0m0.140s
diff --git a/tcllib/examples/page/sql.peg b/tcllib/examples/page/sql.peg
new file mode 100644
index 0000000..e5f11a5
--- /dev/null
+++ b/tcllib/examples/page/sql.peg
@@ -0,0 +1,643 @@
+# -*- text -*-
+## Parsing Expression Grammar 'sqlite3Parser'.
+## Layouted by the PG backend 'PEGwriter'.
+
+PEG sqlite3Parser (input)
+
+leaf: ABORT <- 'A' 'B' 'O' 'R' 'T' ;
+
+leaf: ADD <- 'A' 'D' 'D' ;
+
+ add_column_fullname <- fullname ;
+
+leaf: AFTER <- 'A' 'F' 'T' 'E' 'R' ;
+
+leaf: ALL <- 'A' 'L' 'L' ;
+
+leaf: ALTER <- 'A' 'L' 'T' 'E' 'R' ;
+
+leaf: AND <- 'A' 'N' 'D' ;
+
+leaf: AS <- 'A' 'S' ;
+
+ as <- ( AS nm
+ / ids)? ;
+
+leaf: ASC <- 'A' 'S' 'C' ;
+
+leaf: ATTACH <- 'A' 'T' 'T' 'A' 'C' 'H' ;
+
+ autoinc <- AUTOINCR? ;
+
+leaf: AUTOINCR <- 'A' 'U' 'T' 'O' 'I' 'N' 'C' 'R' ;
+
+leaf: BEFORE <- 'B' 'E' 'F' 'O' 'R' 'E' ;
+
+leaf: BEGIN <- 'B' 'E' 'G' 'I' 'N' ;
+
+leaf: BETWEEN <- 'B' 'E' 'T' 'W' 'E' 'E' 'N' ;
+
+ between_op <- BETWEEN
+ / NOT BETWEEN ;
+
+leaf: BITAND <- 'B' 'I' 'T' 'A' 'N' 'D' ;
+
+leaf: BITNOT <- 'B' 'I' 'T' 'N' 'O' 'T' ;
+
+leaf: BITOR <- 'B' 'I' 'T' 'O' 'R' ;
+
+leaf: BLOB <- 'B' 'L' 'O' 'B' ;
+
+leaf: BY <- 'B' 'Y' ;
+
+ carg <- CONSTRAINT nm ccons
+ / ccons
+ / DEFAULT term
+ / DEFAULT PLUS term
+ / DEFAULT MINUS term
+ / DEFAULT id ;
+
+ carglist <- (carglist carg)? ;
+
+leaf: CASCADE <- 'C' 'A' 'S' 'C' 'A' 'D' 'E' ;
+
+leaf: CASE <- 'C' 'A' 'S' 'E' ;
+
+ case_else <- (ELSE expr)? ;
+
+ case_exprlist <- case_exprlist WHEN expr THEN expr
+ / WHEN expr THEN expr ;
+
+ case_operand <- expr? ;
+
+ ccons <- NULL onconf
+ / NOT NULL onconf
+ / PRIMARY KEY sortorder onconf autoinc
+ / UNIQUE onconf
+ / CHECK LP expr RP onconf
+ / REFERENCES nm idxlist_opt refargs
+ / defer_subclause
+ / COLLATE id ;
+
+leaf: CDATE <- 'C' 'D' 'A' 'T' 'E' ;
+
+leaf: CHECK <- 'C' 'H' 'E' 'C' 'K' ;
+
+ cmd <- BEGIN transtype trans_opt
+ / COMMIT trans_opt
+ / END trans_opt
+ / ROLLBACK trans_opt
+ / create_table create_table_args
+ / DROP TABLE fullname
+ / CREATE temp VIEW nm dbnm AS select
+ / DROP VIEW fullname
+ / select
+ / DELETE FROM fullname where_opt
+ / UPDATE orconf fullname SET setlist where_opt
+ / insert_cmd INTO fullname inscollist_opt VALUES
+ LP itemlist RP
+ / insert_cmd INTO fullname inscollist_opt select
+ / CREATE uniqueflag INDEX nm dbnm ON nm LP idxlist
+ RP onconf
+ / DROP INDEX fullname
+ / VACUUM
+ / VACUUM nm
+ / PRAGMA nm dbnm EQ nm
+ / PRAGMA nm dbnm EQ ON
+ / PRAGMA nm dbnm EQ plus_num
+ / PRAGMA nm dbnm EQ minus_num
+ / PRAGMA nm dbnm LP nm RP
+ / PRAGMA nm dbnm
+ / CREATE trigger_decl BEGIN trigger_cmd_list END
+ / DROP TRIGGER fullname
+ / ATTACH database_kw_opt ids AS nm key_opt
+ / DETACH database_kw_opt nm
+ / REINDEX
+ / REINDEX nm dbnm
+ / ALTER TABLE fullname RENAME TO nm
+ / ALTER TABLE add_column_fullname ADD kwcolumn_opt
+ column ;
+
+ cmdlist <- cmdlist ecmd
+ / ecmd ;
+
+ cmdx <- cmd ;
+
+leaf: COLLATE <- 'C' 'O' 'L' 'L' 'A' 'T' 'E' ;
+
+ collate <- (COLLATE id)? ;
+
+ column <- columnid type carglist ;
+
+ columnid <- nm ;
+
+leaf: COLUMNKW <- 'C' 'O' 'L' 'U' 'M' 'N' 'K' 'W' ;
+
+ columnlist <- columnlist COMMA column
+ / column ;
+
+leaf: COMMA <- 'C' 'O' 'M' 'M' 'A' ;
+
+leaf: COMMIT <- 'C' 'O' 'M' 'M' 'I' 'T' ;
+
+leaf: CONCAT <- 'C' 'O' 'N' 'C' 'A' 'T' ;
+
+leaf: CONFLICT <- 'C' 'O' 'N' 'F' 'L' 'I' 'C' 'T' ;
+
+ conslist <- conslist COMMA tcons
+ / conslist tcons
+ / tcons ;
+
+ conslist_opt <- (COMMA conslist)? ;
+
+leaf: CONSTRAINT <- 'C' 'O' 'N' 'S' 'T' 'R' 'A' 'I' 'N' 'T' ;
+
+leaf: CREATE <- 'C' 'R' 'E' 'A' 'T' 'E' ;
+
+ create_table <- CREATE temp TABLE nm dbnm ;
+
+ create_table_args <- LP columnlist conslist_opt RP
+ / AS select ;
+
+leaf: CTIME <- 'C' 'T' 'I' 'M' 'E' ;
+
+leaf: CTIMESTAMP <- 'C' 'T' 'I' 'M' 'E' 'S' 'T' 'A' 'M' 'P' ;
+
+leaf: DATABASE <- 'D' 'A' 'T' 'A' 'B' 'A' 'S' 'E' ;
+
+ database_kw_opt <- DATABASE? ;
+
+ dbnm <- (DOT nm)? ;
+
+leaf: DEFAULT <- 'D' 'E' 'F' 'A' 'U' 'L' 'T' ;
+
+ defer_subclause <- NOT DEFERRABLE init_deferred_pred_opt
+ / DEFERRABLE init_deferred_pred_opt ;
+
+ defer_subclause_opt <- defer_subclause? ;
+
+leaf: DEFERRABLE <- 'D' 'E' 'F' 'E' 'R' 'R' 'A' 'B' 'L' 'E' ;
+
+leaf: DEFERRED <- 'D' 'E' 'F' 'E' 'R' 'R' 'E' 'D' ;
+
+leaf: DELETE <- 'D' 'E' 'L' 'E' 'T' 'E' ;
+
+leaf: DESC <- 'D' 'E' 'S' 'C' ;
+
+leaf: DETACH <- 'D' 'E' 'T' 'A' 'C' 'H' ;
+
+leaf: DISTINCT <- 'D' 'I' 'S' 'T' 'I' 'N' 'C' 'T' ;
+
+ distinct <- ( DISTINCT
+ / ALL)? ;
+
+leaf: DOT <- 'D' 'O' 'T' ;
+
+leaf: DROP <- 'D' 'R' 'O' 'P' ;
+
+leaf: EACH <- 'E' 'A' 'C' 'H' ;
+
+ ecmd <- SEMI
+ / explain cmdx SEMI ;
+
+leaf: ELSE <- 'E' 'L' 'S' 'E' ;
+
+leaf: END <- 'E' 'N' 'D' ;
+
+leaf: EQ <- 'E' 'Q' ;
+
+leaf: ESCAPE <- 'E' 'S' 'C' 'A' 'P' 'E' ;
+
+ escape <- (ESCAPE expr)? ;
+
+leaf: EXCEPT <- 'E' 'X' 'C' 'E' 'P' 'T' ;
+
+leaf: EXCLUSIVE <- 'E' 'X' 'C' 'L' 'U' 'S' 'I' 'V' 'E' ;
+
+leaf: EXISTS <- 'E' 'X' 'I' 'S' 'T' 'S' ;
+
+leaf: EXPLAIN <- 'E' 'X' 'P' 'L' 'A' 'I' 'N' ;
+
+ explain <- EXPLAIN? ;
+
+ expr <- term
+ / LP expr RP
+ / ID
+ / JOIN_KW
+ / nm DOT nm
+ / nm DOT nm DOT nm
+ / REGISTER
+ / VARIABLE
+ / ID LP exprlist RP
+ / ID LP STAR RP
+ / expr AND expr
+ / expr OR expr
+ / expr LT expr
+ / expr GT expr
+ / expr LE expr
+ / expr GE expr
+ / expr NE expr
+ / expr EQ expr
+ / expr BITAND expr
+ / expr BITOR expr
+ / expr LSHIFT expr
+ / expr RSHIFT expr
+ / expr PLUS expr
+ / expr MINUS expr
+ / expr STAR expr
+ / expr SLASH expr
+ / expr REM expr
+ / expr CONCAT expr
+ / expr likeop expr escape
+ / expr ISNULL
+ / expr IS NULL
+ / expr NOTNULL
+ / expr NOT NULL
+ / expr IS NOT NULL
+ / NOT expr
+ / BITNOT expr
+ / MINUS expr
+ / PLUS expr
+ / expr between_op expr AND expr
+ / expr in_op LP exprlist RP
+ / LP select RP
+ / expr in_op LP select RP
+ / expr in_op nm dbnm
+ / EXISTS LP select RP
+ / CASE case_operand case_exprlist case_else END
+ / RAISE LP IGNORE RP
+ / RAISE LP raisetype COMMA nm RP ;
+
+ expritem <- expr? ;
+
+ exprlist <- exprlist COMMA expritem
+ / expritem ;
+
+leaf: FAIL <- 'F' 'A' 'I' 'L' ;
+
+leaf: FLOAT <- 'F' 'L' 'O' 'A' 'T' ;
+
+leaf: FOR <- 'F' 'O' 'R' ;
+
+ foreach_clause <- ( FOR EACH ROW
+ / FOR EACH STATEMENT)? ;
+
+leaf: FOREIGN <- 'F' 'O' 'R' 'E' 'I' 'G' 'N' ;
+
+leaf: FROM <- 'F' 'R' 'O' 'M' ;
+
+ from <- (FROM seltablist)? ;
+
+ fullname <- nm dbnm ;
+
+leaf: GE <- 'G' 'E' ;
+
+leaf: GLOB <- 'G' 'L' 'O' 'B' ;
+
+leaf: GROUP <- 'G' 'R' 'O' 'U' 'P' ;
+
+ groupby_opt <- (GROUP BY exprlist)? ;
+
+leaf: GT <- 'G' 'T' ;
+
+leaf: HAVING <- 'H' 'A' 'V' 'I' 'N' 'G' ;
+
+ having_opt <- (HAVING expr)? ;
+
+leaf: ID <- 'I' 'D' ;
+
+ id <- ID ;
+
+ ids <- ID
+ / STRING ;
+
+ idxitem <- nm ;
+
+ idxlist <- idxlist COMMA idxitem collate sortorder
+ / idxitem collate sortorder ;
+
+ idxlist_opt <- (LP idxlist RP)? ;
+
+leaf: IGNORE <- 'I' 'G' 'N' 'O' 'R' 'E' ;
+
+leaf: IMMEDIATE <- 'I' 'M' 'M' 'E' 'D' 'I' 'A' 'T' 'E' ;
+
+leaf: IN <- 'I' 'N' ;
+
+ in_op <- IN
+ / NOT IN ;
+
+leaf: INDEX <- 'I' 'N' 'D' 'E' 'X' ;
+
+ init_deferred_pred_opt <- ( INITIALLY DEFERRED
+ / INITIALLY IMMEDIATE)? ;
+
+leaf: INITIALLY <- 'I' 'N' 'I' 'T' 'I' 'A' 'L' 'L' 'Y' ;
+
+ input <- cmdlist ;
+
+ inscollist <- inscollist COMMA nm
+ / nm ;
+
+ inscollist_opt <- (LP inscollist RP)? ;
+
+leaf: INSERT <- 'I' 'N' 'S' 'E' 'R' 'T' ;
+
+ insert_cmd <- INSERT orconf
+ / REPLACE ;
+
+leaf: INSTEAD <- 'I' 'N' 'S' 'T' 'E' 'A' 'D' ;
+
+leaf: INTEGER <- 'I' 'N' 'T' 'E' 'G' 'E' 'R' ;
+
+leaf: INTERSECT <- 'I' 'N' 'T' 'E' 'R' 'S' 'E' 'C' 'T' ;
+
+leaf: INTO <- 'I' 'N' 'T' 'O' ;
+
+leaf: IS <- 'I' 'S' ;
+
+leaf: ISNULL <- 'I' 'S' 'N' 'U' 'L' 'L' ;
+
+ itemlist <- itemlist COMMA expr
+ / expr ;
+
+leaf: JOIN <- 'J' 'O' 'I' 'N' ;
+
+leaf: JOIN_KW <- 'J' 'O' 'I' 'N' '_' 'K' 'W' ;
+
+ joinop <- COMMA
+ / JOIN
+ / JOIN_KW JOIN
+ / JOIN_KW nm JOIN
+ / JOIN_KW nm nm JOIN ;
+
+leaf: KEY <- 'K' 'E' 'Y' ;
+
+ key_opt <- ( KEY ids
+ / KEY BLOB)? ;
+
+ kwcolumn_opt <- COLUMNKW? ;
+
+leaf: LE <- 'L' 'E' ;
+
+leaf: LIKE <- 'L' 'I' 'K' 'E' ;
+
+ likeop <- LIKE
+ / GLOB
+ / NOT LIKE
+ / NOT GLOB ;
+
+leaf: LIMIT <- 'L' 'I' 'M' 'I' 'T' ;
+
+ limit_opt <- ( LIMIT expr
+ / LIMIT expr OFFSET expr
+ / LIMIT expr COMMA expr)? ;
+
+leaf: LP <- 'L' 'P' ;
+
+leaf: LSHIFT <- 'L' 'S' 'H' 'I' 'F' 'T' ;
+
+leaf: LT <- 'L' 'T' ;
+
+leaf: MATCH <- 'M' 'A' 'T' 'C' 'H' ;
+
+leaf: MINUS <- 'M' 'I' 'N' 'U' 'S' ;
+
+ minus_num <- MINUS number ;
+
+ multiselect_op <- UNION
+ / UNION ALL
+ / INTERSECT
+ / EXCEPT ;
+
+leaf: NE <- 'N' 'E' ;
+
+ nm <- ID
+ / STRING
+ / JOIN_KW ;
+
+leaf: NOT <- 'N' 'O' 'T' ;
+
+leaf: NOTNULL <- 'N' 'O' 'T' 'N' 'U' 'L' 'L' ;
+
+leaf: NULL <- 'N' 'U' 'L' 'L' ;
+
+ number <- INTEGER
+ / FLOAT ;
+
+leaf: OF <- 'O' 'F' ;
+
+leaf: OFFSET <- 'O' 'F' 'F' 'S' 'E' 'T' ;
+
+leaf: ON <- 'O' 'N' ;
+
+ on_opt <- (ON expr)? ;
+
+ onconf <- (ON CONFLICT resolvetype)? ;
+
+ oneselect <- SELECT distinct selcollist from where_opt
+ groupby_opt having_opt orderby_opt limit_opt ;
+
+leaf: OR <- 'O' 'R' ;
+
+ orconf <- (OR resolvetype)? ;
+
+leaf: ORDER <- 'O' 'R' 'D' 'E' 'R' ;
+
+ orderby_opt <- (ORDER BY sortlist)? ;
+
+leaf: PLUS <- 'P' 'L' 'U' 'S' ;
+
+ plus_num <- plus_opt number ;
+
+ plus_opt <- PLUS? ;
+
+leaf: PRAGMA <- 'P' 'R' 'A' 'G' 'M' 'A' ;
+
+leaf: PRIMARY <- 'P' 'R' 'I' 'M' 'A' 'R' 'Y' ;
+
+leaf: RAISE <- 'R' 'A' 'I' 'S' 'E' ;
+
+ raisetype <- ROLLBACK
+ / ABORT
+ / FAIL ;
+
+ refact <- SET NULL
+ / SET DEFAULT
+ / CASCADE
+ / RESTRICT ;
+
+ refarg <- MATCH nm
+ / ON DELETE refact
+ / ON UPDATE refact
+ / ON INSERT refact ;
+
+ refargs <- (refargs refarg)? ;
+
+leaf: REFERENCES <- 'R' 'E' 'F' 'E' 'R' 'E' 'N' 'C' 'E' 'S' ;
+
+leaf: REGISTER <- 'R' 'E' 'G' 'I' 'S' 'T' 'E' 'R' ;
+
+leaf: REINDEX <- 'R' 'E' 'I' 'N' 'D' 'E' 'X' ;
+
+leaf: REM <- 'R' 'E' 'M' ;
+
+leaf: RENAME <- 'R' 'E' 'N' 'A' 'M' 'E' ;
+
+leaf: REPLACE <- 'R' 'E' 'P' 'L' 'A' 'C' 'E' ;
+
+ resolvetype <- raisetype
+ / IGNORE
+ / REPLACE ;
+
+leaf: RESTRICT <- 'R' 'E' 'S' 'T' 'R' 'I' 'C' 'T' ;
+
+leaf: ROLLBACK <- 'R' 'O' 'L' 'L' 'B' 'A' 'C' 'K' ;
+
+leaf: ROW <- 'R' 'O' 'W' ;
+
+leaf: RP <- 'R' 'P' ;
+
+leaf: RSHIFT <- 'R' 'S' 'H' 'I' 'F' 'T' ;
+
+ sclp <- (selcollist COMMA)? ;
+
+ selcollist <- sclp expr as
+ / sclp STAR
+ / sclp nm DOT STAR ;
+
+leaf: SELECT <- 'S' 'E' 'L' 'E' 'C' 'T' ;
+
+ select <- oneselect
+ / select multiselect_op oneselect ;
+
+ seltablist <- stl_prefix nm dbnm as on_opt using_opt
+ / stl_prefix LP seltablist_paren RP as on_opt
+ using_opt ;
+
+ seltablist_paren <- select
+ / seltablist ;
+
+leaf: SEMI <- 'S' 'E' 'M' 'I' ;
+
+leaf: SET <- 'S' 'E' 'T' ;
+
+ setlist <- setlist COMMA nm EQ expr
+ / nm EQ expr ;
+
+ signed <- plus_num
+ / minus_num ;
+
+leaf: SLASH <- 'S' 'L' 'A' 'S' 'H' ;
+
+ sortitem <- expr ;
+
+ sortlist <- sortlist COMMA sortitem collate sortorder
+ / sortitem collate sortorder ;
+
+ sortorder <- ( ASC
+ / DESC)? ;
+
+leaf: STAR <- 'S' 'T' 'A' 'R' ;
+
+leaf: STATEMENT <- 'S' 'T' 'A' 'T' 'E' 'M' 'E' 'N' 'T' ;
+
+ stl_prefix <- (seltablist joinop)? ;
+
+leaf: STRING <- 'S' 'T' 'R' 'I' 'N' 'G' ;
+
+leaf: TABLE <- 'T' 'A' 'B' 'L' 'E' ;
+
+ tcons <- CONSTRAINT nm
+ / PRIMARY KEY LP idxlist autoinc RP onconf
+ / UNIQUE LP idxlist RP onconf
+ / CHECK expr onconf
+ / FOREIGN KEY LP idxlist RP REFERENCES nm
+ idxlist_opt refargs defer_subclause_opt ;
+
+leaf: TEMP <- 'T' 'E' 'M' 'P' ;
+
+ temp <- TEMP? ;
+
+ term <- NULL
+ / INTEGER
+ / FLOAT
+ / STRING
+ / BLOB
+ / CTIME
+ / CDATE
+ / CTIMESTAMP ;
+
+leaf: THEN <- 'T' 'H' 'E' 'N' ;
+
+leaf: TO <- 'T' 'O' ;
+
+ trans_opt <- ( TRANSACTION
+ / TRANSACTION nm)? ;
+
+leaf: TRANSACTION <- 'T' 'R' 'A' 'N' 'S' 'A' 'C' 'T' 'I' 'O' 'N' ;
+
+ transtype <- ( DEFERRED
+ / IMMEDIATE
+ / EXCLUSIVE)? ;
+
+leaf: TRIGGER <- 'T' 'R' 'I' 'G' 'G' 'E' 'R' ;
+
+ trigger_cmd <- UPDATE orconf nm SET setlist where_opt
+ / insert_cmd INTO nm inscollist_opt VALUES LP
+ itemlist RP
+ / insert_cmd INTO nm inscollist_opt select
+ / DELETE FROM nm where_opt
+ / select ;
+
+ trigger_cmd_list <- (trigger_cmd SEMI trigger_cmd_list)? ;
+
+ trigger_decl <- temp TRIGGER nm dbnm trigger_time trigger_event
+ ON fullname foreach_clause when_clause ;
+
+ trigger_event <- DELETE
+ / INSERT
+ / UPDATE
+ / UPDATE OF inscollist ;
+
+ trigger_time <- ( BEFORE
+ / AFTER
+ / INSTEAD OF)? ;
+
+ type <- ( typename
+ / typename LP signed RP
+ / typename LP signed COMMA signed RP)? ;
+
+ typename <- ids
+ / typename ids ;
+
+leaf: UNION <- 'U' 'N' 'I' 'O' 'N' ;
+
+leaf: UNIQUE <- 'U' 'N' 'I' 'Q' 'U' 'E' ;
+
+ uniqueflag <- UNIQUE? ;
+
+leaf: UPDATE <- 'U' 'P' 'D' 'A' 'T' 'E' ;
+
+leaf: USING <- 'U' 'S' 'I' 'N' 'G' ;
+
+ using_opt <- (USING LP inscollist RP)? ;
+
+leaf: VACUUM <- 'V' 'A' 'C' 'U' 'U' 'M' ;
+
+leaf: VALUES <- 'V' 'A' 'L' 'U' 'E' 'S' ;
+
+leaf: VARIABLE <- 'V' 'A' 'R' 'I' 'A' 'B' 'L' 'E' ;
+
+leaf: VIEW <- 'V' 'I' 'E' 'W' ;
+
+leaf: WHEN <- 'W' 'H' 'E' 'N' ;
+
+ when_clause <- (WHEN expr)? ;
+
+leaf: WHERE <- 'W' 'H' 'E' 'R' 'E' ;
+
+ where_opt <- (WHERE expr)? ;
+
+END;
+