[llvm-commits] [test-suite] r48828 [1/2] - in /test-suite/trunk/MultiSource/Applications: ./ lemon/ sqlite3/

Evan Cheng evan.cheng at apple.com
Wed Mar 26 10:03:57 PDT 2008


Author: evancheng
Date: Wed Mar 26 12:03:57 2008
New Revision: 48828

URL: http://llvm.org/viewvc/llvm-project?rev=48828&view=rev
Log:
Added sqlite3 and lemon to llvm test suite. Thanks to Török Edwin!

Added:
    test-suite/trunk/MultiSource/Applications/lemon/
    test-suite/trunk/MultiSource/Applications/lemon/Makefile
    test-suite/trunk/MultiSource/Applications/lemon/README
    test-suite/trunk/MultiSource/Applications/lemon/copyright-release.html
    test-suite/trunk/MultiSource/Applications/lemon/ecmascript.y
    test-suite/trunk/MultiSource/Applications/lemon/example1.y
    test-suite/trunk/MultiSource/Applications/lemon/example2.y
    test-suite/trunk/MultiSource/Applications/lemon/example3.y
    test-suite/trunk/MultiSource/Applications/lemon/example4.y
    test-suite/trunk/MultiSource/Applications/lemon/example5.y
    test-suite/trunk/MultiSource/Applications/lemon/example_COPYING
    test-suite/trunk/MultiSource/Applications/lemon/lemon.c
    test-suite/trunk/MultiSource/Applications/lemon/lempar.c
    test-suite/trunk/MultiSource/Applications/lemon/lighttpd_COPYING
    test-suite/trunk/MultiSource/Applications/lemon/lighttpd_configparser.y
    test-suite/trunk/MultiSource/Applications/lemon/lighttpd_mod_ssi_exprparser.y
    test-suite/trunk/MultiSource/Applications/lemon/parse.y
    test-suite/trunk/MultiSource/Applications/lemon/wireshark_COPYING
    test-suite/trunk/MultiSource/Applications/lemon/wireshark_dtd_grammar.lemon
    test-suite/trunk/MultiSource/Applications/lemon/wireshark_grammar.lemon
    test-suite/trunk/MultiSource/Applications/lemon/wireshark_mate_grammar.lemon
    test-suite/trunk/MultiSource/Applications/lemon/xapian_COPYING
    test-suite/trunk/MultiSource/Applications/lemon/xapian_queryparser.lemony
    test-suite/trunk/MultiSource/Applications/sqlite3/
    test-suite/trunk/MultiSource/Applications/sqlite3/Makefile
    test-suite/trunk/MultiSource/Applications/sqlite3/README
    test-suite/trunk/MultiSource/Applications/sqlite3/VERSION
    test-suite/trunk/MultiSource/Applications/sqlite3/commands
    test-suite/trunk/MultiSource/Applications/sqlite3/copyright-release.html
    test-suite/trunk/MultiSource/Applications/sqlite3/shell.c
    test-suite/trunk/MultiSource/Applications/sqlite3/speedtest.tcl
    test-suite/trunk/MultiSource/Applications/sqlite3/sqlite3.c
Modified:
    test-suite/trunk/MultiSource/Applications/Makefile

Modified: test-suite/trunk/MultiSource/Applications/Makefile
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/Makefile?rev=48828&r1=48827&r2=48828&view=diff

==============================================================================
--- test-suite/trunk/MultiSource/Applications/Makefile (original)
+++ test-suite/trunk/MultiSource/Applications/Makefile Wed Mar 26 12:03:57 2008
@@ -5,7 +5,7 @@
 include $(LEVEL)/Makefile.config
 
 PARALLEL_DIRS  = Burg aha sgefa siod lambda-0.1.3 d spiff hbd treecc SPASS \
-                 hexxagon oggenc JM viterbi minisat SIBsim4 ClamAV
+                 hexxagon oggenc JM viterbi minisat SIBsim4 ClamAV sqlite3 lemon
 
 # Obsequi uses Linux-only features; need to fix that
 ifeq ($(OS),Linux)

Added: test-suite/trunk/MultiSource/Applications/lemon/Makefile
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/lemon/Makefile?rev=48828&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/lemon/Makefile (added)
+++ test-suite/trunk/MultiSource/Applications/lemon/Makefile Wed Mar 26 12:03:57 2008
@@ -0,0 +1,12 @@
+LEVEL = ../../../
+
+Source = lemon.c
+
+PROG = lemon
+RUN_OPTIONS = parse.y example1.y example2.y example3.y example4.y example5.y lighttpd_configparser.y lighttpd_mod_ssi_exprparser.y wireshark_dtd_grammar.lemon wireshark_grammar.lemon wireshark_mate_grammar.lemon xapian_queryparser.lemony ecmascript.y
+
+include $(LEVEL)/Makefile.config
+
+include ../../Makefile.multisrc
+DIFFPROG := $(PROGDIR)/DiffOutput.sh "diff "
+

Added: test-suite/trunk/MultiSource/Applications/lemon/README
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/lemon/README?rev=48828&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/lemon/README (added)
+++ test-suite/trunk/MultiSource/Applications/lemon/README Wed Mar 26 12:03:57 2008
@@ -0,0 +1,13 @@
+lemon.c, lempar.c, parse.y are from SQLite3, which is in the public domain (copyright-release.html)
+
+Homepage of lemon is http://www.hwaci.com/sw/lemon/lemon.html
+
+example[1-5].y is from the Lemon Parser Tutorial, covered by example_COPYING http://sourceforge.net/project/showfiles.php?group_id=79320&package_id=124528
+
+lighttpd_mod_ssi_exprparser.y, and lighttpd_configparser.y is from lighttpd-1.4.19,
+covered by lighttpd_COPYING
+
+wireshark_grammar.lemon, wireshark_dtd_grammar.lemon, wireshark_mate_grammar.lemon is from wireshark-0.99.8, covered by wireshark_COPYING
+
+xapian_queryparser.lemony is from xapian-core-1.0.5, covered by xapian_COPYING
+

Added: test-suite/trunk/MultiSource/Applications/lemon/copyright-release.html
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/lemon/copyright-release.html?rev=48828&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/lemon/copyright-release.html (added)
+++ test-suite/trunk/MultiSource/Applications/lemon/copyright-release.html Wed Mar 26 12:03:57 2008
@@ -0,0 +1,109 @@
+<html>
+<body bgcolor="white">
+<h1 align="center">
+Copyright Release for<br>
+Contributions To SQLite
+</h1>
+
+<p>
+SQLite is software that implements an embeddable SQL database engine.
+SQLite is available for free download from http://www.sqlite.org/.
+The principal author and maintainer of SQLite has disclaimed all
+copyright interest in his contributions to SQLite
+and thus released his contributions into the public domain.
+In order to keep the SQLite software unencumbered by copyright
+claims, the principal author asks others who may from time to
+time contribute changes and enhancements to likewise disclaim
+their own individual copyright interest.
+</p>
+
+<p>
+Because the SQLite software found at http://www.sqlite.org/ is in the
+public domain, anyone is free to download the SQLite software
+from that website, make changes to the software, use, distribute,
+or sell the modified software, under either the original name or
+under some new name, without any need to obtain permission, pay
+royalties, acknowledge the original source of the software, or
+in any other way compensate, identify, or notify the original authors.  
+Nobody is in any way compelled to contribute their SQLite changes and 
+enhancements back to the SQLite website.  This document concerns
+only changes and enhancements to SQLite that are intentionally and
+deliberately contributed back to the SQLite website.  
+</p>
+
+<p>
+For the purposes of this document, "SQLite software" shall mean any
+computer source code, documentation, makefiles, test scripts, or
+other information that is published on the SQLite website, 
+http://www.sqlite.org/.  Precompiled binaries are excluded from
+the definition of "SQLite software" in this document because the
+process of compiling the software may introduce information from
+outside sources which is not properly a part of SQLite.
+</p>
+
+<p>
+The header comments on the SQLite source files exhort the reader to
+share freely and to never take more than one gives.
+In the spirit of that exhortation I make the following declarations:
+</p>
+
+<ol>
+<li><p>
+I dedicate to the public domain 
+any and all copyright interest in the SQLite software that
+was publicly available on the SQLite website (http://www.sqlite.org/) prior
+to the date of the signature below and any changes or enhancements to
+the SQLite software 
+that I may cause to be published on that website in the future.
+I make this dedication for the benefit of the public at large and
+to the detriment of my heirs and successors.  I intend this
+dedication to be an overt act of relinquishment in perpetuity of
+all present and future rights to the SQLite software under copyright
+law.
+</p></li>
+
+<li><p>
+To the best of my knowledge and belief, the changes and enhancements that
+I have contributed to SQLite are either originally written by me
+or are derived from prior works which I have verified are also
+in the public domain and are not subject to claims of copyright
+by other parties.
+</p></li>
+
+<li><p>
+To the best of my knowledge and belief, no individual, business, organization,
+government, or other entity has any copyright interest
+in the SQLite software as it existed on the
+SQLite website as of the date on the signature line below.
+</p></li>
+
+<li><p>
+I agree never to publish any additional information
+to the SQLite website (by CVS, email, scp, FTP, or any other means) unless
+that information is an original work of authorship by me or is derived from 
+prior published versions of SQLite.
+I agree never to copy and paste code into the SQLite code base from
+other sources.
+I agree never to publish on the SQLite website any information that
+would violate a law or breach a contract.
+</p></li>
+</ol>
+
+<p>
+<table width="100%" cellpadding="0" cellspacing="0">
+<tr>
+<td width="60%" valign="top">
+Signature:
+<p> </p>
+<p> </p>
+<p> </p>
+</td><td valign="top" align="left">
+Date:
+</td></tr>
+<td colspan=2>
+Name (printed):
+</td>
+</tr>
+</table>
+</body>
+</html>

Added: test-suite/trunk/MultiSource/Applications/lemon/ecmascript.y
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/lemon/ecmascript.y?rev=48828&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/lemon/ecmascript.y (added)
+++ test-suite/trunk/MultiSource/Applications/lemon/ecmascript.y Wed Mar 26 12:03:57 2008
@@ -0,0 +1,270 @@
+%include {
+#include <stdlib.h>
+#include <string.h>
+#include "lexglobal.h"
+}
+%token_type{int}
+%nonassoc PRECEDENCE_KEYWORD PRECEDENCE_IDENTIFIER.
+
+program ::= source_elements.
+
+
+
+identifier ::= IDENTIFIER_NAME. [PRECEDENCE_IDENTIFIER]
+
+
+
+literal ::= NULL_LITERAL.
+literal ::= BOOLEAN_LITERAL.
+literal ::= NumericLiteral.
+literal ::= StringLiteral.
+
+primary_expression ::=  THIS.
+primary_expression ::=  identifier.
+primary_expression ::=  literal.
+primary_expression ::=  array_literal.
+primary_expression ::=  object_literal.
+primary_expression ::=  PAR_OPEN expression PAR_CLOSE.
+
+elision_opt ::= .
+elision_opt ::= elision.
+
+array_literal ::= BRACKET_OPEN elision_opt BRACKET_CLOSE
+	        |BRACKET_OPEN element_list BRACKET_CLOSE
+		|BRACKET_OPEN element_list COMMA elision_opt BRACKET_CLOSE.
+
+assignment_operator ::= EQUAL.
+assignment_operator ::= ASSIGNMENT_OPERATOR_NOEQUAL.
+
+elision ::= COMMA.
+elision ::= elision COMMA.
+
+element_list ::= elision_opt assignment_expression.
+element_list ::= element_list COMMA elision_opt  COMMA assignment_expression.
+
+object_literal ::= CURLY_BRACE_OPEN CURLY_BRACE_CLOSE
+		  |CURLY_BRACE_OPEN property_name_and_value_list CURLY_BRACE_CLOSE.
+
+property_name_and_value_list ::= property_name COLON assignment_expression.
+property_name_and_value_list ::= property_name_and_value_list COMMA property_name COLON assignment_expression.
+
+property_name ::= identifier.
+property_name ::= StringLiteral
+		|NumericLiteral.
+
+
+/*
+
+temp phony decls
+
+*/
+
+function_expression ::= .
+/*------------------*/
+member_expression ::= primary_expression.
+member_expression ::= function_expression.
+member_expression ::= member_expression BRACKET_OPEN expression BRACKET_CLOSE.
+member_expression ::= member_expression DOT identifier.
+member_expression ::= NEW member_expression arguments.
+
+new_expression ::= member_expression.
+new_expression ::= NEW new_expression.
+
+call_expression ::= member_expression arguments.
+call_expression ::= call_expression arguments.
+call_expression ::= call_expression BRACKET_OPEN expression BRACKET_CLOSE.
+call_expression ::= call_expression DOT identifier.
+
+arguments ::= PAR_OPEN PAR_CLOSE
+	     |PAR_OPEN arguments_list PAR_CLOSE.
+
+arguments_list ::= assignment_expression.
+arguments_list ::= arguments_list COMMA assignment_expression.
+
+lefthandside_expression ::= new_expression.
+lefthandside_expression ::= call_expression.
+
+postfix_expression ::= lefthandside_expression.
+postfix_expression ::= lefthandside_expression NOLF_PLUSPLUS.
+postfix_expression ::= lefthandside_expression NOLF_MINUSMINUS.
+
+unary_expression ::= postfix_expression.
+unary_expression ::= DELETE|VOID|TYPEOF|PLUSPLUS|MINUSMINUS|MINUS|TILDE|EXCLAMATION unary_expression.
+
+multiplicative_expression ::= unary_expression.
+multiplicative_expression ::= multiplicative_expression MULTIPLY|DIVIDE|PERCENT unary_expression.
+
+additive_expression ::= multiplicative_expression.
+additive_expression ::= additive_expression PLUS|MINUS multiplicative_expression.
+
+shift_expression ::= additive_expression.
+shift_expression ::= shift_expression SHIFT_LEFT|SHIFT_RIGHT|DOUBLESHIFT_RIGHT additive_expression.
+
+relational_expression ::= shift_expression.
+relational_expression ::= relational_expression LESS|GREATER|LESSEQUAL|GREATEREQUAL|INSTANCEOF|IN shift_expression.
+
+relational_expression_noin ::= shift_expression.
+relational_expression_noin ::= relational_expression LESS|GREATER|LESSEQUAL|GREATEREQUAL|INSTANCEOF shift_expression.
+
+equality_expression ::= relational_expression.
+equality_expression ::= equality_expression EQUAL_EQUAL|NOT_EQUAL|TRIPLE_EQUAL|NOT_DOUBLEEQUAL relational_expression.
+
+equality_expression_noin ::= relational_expression_noin.
+equality_expression_noin ::= equality_expression_noin EQUAL_EQUAL|NOT_EQUAL|TRIPLE_EQUAL|NOT_DOUBLEEQUAL relational_expression_noin.
+
+bitwise_and_expression ::= equality_expression.
+bitwise_and_expression ::= bitwise_and_expression AND equality_expression.
+
+bitwise_and_expression_noin ::= equality_expression_noin.
+bitwise_and_expression_noin ::= bitwise_and_expression_noin AND equality_expression_noin.
+
+bitwise_xor_expression ::= bitwise_and_expression.
+bitwise_xor_expression ::= bitwise_xor_expression XOR bitwise_and_expression.
+
+
+bitwise_xor_expression_noin ::= bitwise_and_expression_noin.
+bitwise_xor_expression_noin ::= bitwise_xor_expression_noin XOR bitwise_and_expression_noin.
+
+bitwise_or_expression ::= bitwise_xor_expression.
+bitwise_or_expression ::= bitwise_or_expression OR bitwise_xor_expression.
+
+
+bitwise_or_expression_noin ::= bitwise_xor_expression_noin.
+bitwise_or_expression_noin ::= bitwise_or_expression_noin OR bitwise_xor_expression_noin.
+
+logical_and_expression ::= bitwise_or_expression.
+logical_and_expression ::= logical_and_expression AND_AND bitwise_or_expression.
+
+logical_and_expression_noin ::= bitwise_or_expression_noin.
+logical_and_expression_noin ::= logical_and_expression_noin AND_AND bitwise_or_expression_noin.
+		       
+
+logical_or_expression ::= logical_and_expression.
+logical_or_expression ::= logical_or_expression OR_OR logical_and_expression.
+
+logical_or_expression_noin ::= logical_and_expression_noin.
+logical_or_expression_noin ::= logical_or_expression_noin OR_OR logical_and_expression_noin.
+
+conditional_expression ::= logical_or_expression.
+conditional_expression ::= logical_or_expression QUESTIONMARK assignment_expression COLON assignment_expression.
+
+conditional_expression_noin ::= logical_or_expression_noin.
+conditional_expression_noin ::= logical_or_expression_noin QUESTIONMARK assignment_expression_noin COLON assignment_expression_noin.
+
+assignment_expression ::= conditional_expression.
+assignment_expression ::= lefthandside_expression assignment_operator assignment_expression.
+
+assignment_expression_noin ::= conditional_expression_noin.
+assignment_expression_noin ::= lefthandside_expression assignment_operator assignment_expression_noin.
+		      
+expression ::= assignment_expression.
+expression ::= expression COMMA assignment_expression.
+expression_opt ::= expression.
+
+expression_noin_opt ::= expression.
+
+statement ::= block.
+statement ::= variable_statement.
+statement ::= empty_statement.
+statement ::= expression_statement.
+statement ::= if_statement.
+statement ::= iteration_statement.
+statement ::= continue_statement.
+statement ::= break_statement.
+statement ::= return_statement.
+statement ::= with_statement.
+statement ::= labelled_statement.
+statement ::= throw_statement.
+statement ::= try_statement.
+
+block ::= CURLY_BRACE_OPEN statement_list_opt CURLY_BRACE_CLOSE.
+
+statement_list_opt ::= .
+statement_list_opt ::= statement_list.
+
+statement_list ::= statement.
+statement_list ::= statement_list statement.
+
+variable_statement ::=  VAR variable_declaration_list SEMICOLON.
+
+variable_declaration_list ::= variable_declaration.		   
+variable_declaration_list ::= variable_declaration_list COMMA variable_declaration.
+
+variable_declaration_list_noin ::= variable_declaration_noin.
+variable_declaration_list_noin ::= variable_declaration_list_noin COMMA variable_declaration_noin.
+
+variable_declaration ::= identifier initialiser_opt.
+
+variable_declaration_noin ::= identifier initialiser_noin_opt.
+
+initialiser_opt ::= .
+
+initialiser_noin_opt ::= .
+initialiser_noin_opt ::= initaliser_noin.
+
+initaliser_noin ::= EQUAL assignment_expression_noin.
+
+empty_statement ::= SEMICOLON.
+
+expression_statement ::= expression SEMICOLON.
+		     /*TODO:IMPLEMENT THIS RULE: lookahead not-contains {, function*/
+		  
+if_statement ::= IF PAR_OPEN expression PAR_CLOSE ELSE statement.
+if_statement ::= IF PAR_OPEN expression PAR_CLOSE statement.
+
+
+iteration_statement ::= DO statement WHILE PAR_OPEN expression PAR_CLOSE SEMICOLON.
+iteration_statement ::= WHILE PAR_OPEN expression PAR_CLOSE statement.
+iteration_statement ::= FOR PAR_OPEN expression_noin_opt SEMICOLON expression_opt SEMICOLON expression_opt PAR_CLOSE statement.
+iteration_statement ::= FOR PAR_OPEN VAR variable_declaration_list_noin SEMICOLON expression_opt SEMICOLON expression_opt PAR_CLOSE statement.
+iteration_statement ::= FOR PAR_OPEN lefthandside_expression IN expression PAR_CLOSE statement.
+iteration_statement ::= FOR PAR_OPEN VAR variable_declaration_noin IN expression PAR_CLOSE statement.
+
+continue_statement ::= CONTINUE_NOLF identifier_opt SEMICOLON.
+
+break_statement ::= BREAK_NOLF identifier_opt SEMICOLON.
+
+return_statement ::= RETURN_NOLF expression_opt SEMICOLON.
+
+with_statement ::= WITH PAR_OPEN expression PAR_CLOSE statement.
+
+
+
+
+
+
+labelled_statement ::= identifier COLON statement.
+
+throw_statement ::= THROW_NOLF expression SEMICOLON.
+
+try_statement ::= TRY block catch.
+try_statement ::= TRY block finally.
+try_statement ::= TRY block catch finally.
+
+catch ::= CATCH PAR_OPEN identifier PAR_CLOSE block.
+
+finally ::= FINALLY block.
+
+identifier_opt ::= .
+identifier_opt ::= identifier.
+
+function_declaration ::= FUNCTION identifier PAR_OPEN formal_parameter_list_opt PAR_CLOSE CURLY_BRACE_OPEN function_body CURLY_BRACE_CLOSE.
+
+function_expression ::= FUNCTION identifier_opt PAR_OPEN formal_parameter_list_opt PAR_CLOSE CURLY_BRACE_OPEN function_body CURLY_BRACE_CLOSE.
+
+formal_parameter_list_opt ::= .
+formal_parameter_list_opt ::= formal_parameter_list.
+
+formal_parameter_list ::= identifier.
+formal_parameter_list ::= formal_parameter_list COMMA identifier.
+
+function_body ::= source_elements.
+
+
+source_elements ::= source_element.
+source_elements ::= source_elements source_element.
+
+source_element ::= statement.
+source_element ::= function_declaration.
+
+

Added: test-suite/trunk/MultiSource/Applications/lemon/example1.y
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/lemon/example1.y?rev=48828&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/lemon/example1.y (added)
+++ test-suite/trunk/MultiSource/Applications/lemon/example1.y Wed Mar 26 12:03:57 2008
@@ -0,0 +1,68 @@
+/* Copyright (GPL) 2004 mchirico at users.sourceforge.net or mchirico at comcast.net
+
+  Simple lemon parser  example.
+
+  
+    $ ./lemon example1.y                          
+
+  The above statement will create example1.c.
+
+  The command below  adds  main and the
+  necessary "Parse" calls to the
+  end of this example1.c.
+
+
+    $ cat <<EOF >>example1.c                      
+    int main()                                    
+    {                                             
+      void* pParser = ParseAlloc (malloc);        
+      Parse (pParser, INTEGER, 1);                
+      Parse (pParser, PLUS, 0);                   
+      Parse (pParser, INTEGER, 2);                
+      Parse (pParser, 0, 0);                      
+      ParseFree(pParser, free );                  
+     }                                            
+    EOF                                           
+            
+
+     $ g++ -o ex1 example1.c                                      
+     $ ./ex1
+
+  See the Makefile, as most all of this is
+  done automatically.
+  
+  Downloads:
+  http://prdownloads.sourceforge.net/souptonuts/lemon_examples.tar.gz?download
+
+*/
+
+%token_type {int}  
+   
+%left PLUS MINUS.   
+%left DIVIDE TIMES.  
+   
+%include {   
+#include <iostream>  
+#include "example1.h"
+}  
+   
+%syntax_error {  
+  std::cout << "Syntax error!" << std::endl;  
+}   
+   
+program ::= expr(A).   { std::cout << "Result=" << A << std::endl; }  
+   
+expr(A) ::= expr(B) MINUS  expr(C).   { A = B - C; }  
+expr(A) ::= expr(B) PLUS  expr(C).   { A = B + C; }  
+expr(A) ::= expr(B) TIMES  expr(C).   { A = B * C; }  
+expr(A) ::= expr(B) DIVIDE expr(C).  { 
+
+         if(C != 0){
+           A = B / C;
+          }else{
+           std::cout << "divide by zero" << std::endl;
+           }
+}  /* end of DIVIDE */
+
+expr(A) ::= INTEGER(B). { A = B; } 
+

Added: test-suite/trunk/MultiSource/Applications/lemon/example2.y
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/lemon/example2.y?rev=48828&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/lemon/example2.y (added)
+++ test-suite/trunk/MultiSource/Applications/lemon/example2.y Wed Mar 26 12:03:57 2008
@@ -0,0 +1,107 @@
+/* Copyright (GPL) 2004 mchirico at users.sourceforge.net or mchirico at comcast.net
+  Simple lemon parser  example.
+  
+  Download:
+  http://prdownloads.sourceforge.net/souptonuts/lemon_examples.tar.gz?download
+
+
+  To compile this example see the Makefile. Or
+  this is what is taking place.
+  
+    $ ./lemon example2.y                          
+    $ cat main_part2 >> example2.c
+    $ g++ -o ex2  -O2 -s -pipe example2.c
+
+  Next, run ./ex2
+
+    $ ./ex2
+
+  Which will give the following output:
+
+    Result.value=17  <---------------------------\       
+    Result.n=4        				 |
+    Result.value=-9   				 |
+    Result.n=4        				 |
+    Result.value=78   				 |
+    Result.n=10       				 |
+						 |
+  Now looking at a section of main_part2	 |
+  we can see how 4 PLUS 13 in implemented.	 |
+						 |
+      struct Token t0,t1;              		 |
+      struct Token mToken;         		 |
+                                   		 |
+      t0.value=4;                  		 |
+      t0.n=0;                      		 |
+                                   		 |
+      t1.value=13;                               |
+      t1.n=0;                                    |
+         // Below 4 PLUS 14    ----------------- /                         
+      Parse (pParser, NUM, t0);    
+      Parse (pParser, PLUS, t0);   
+      Parse (pParser, NUM, t1);    
+      Parse (pParser, 0, t0);      
+
+
+
+
+
+
+
+
+
+*/
+
+%include {   
+#include <iostream>  
+#include "ex2def.h"
+#include "example2.h"
+}  
+
+
+%token_type {Token}
+%default_type {Token}
+
+
+%type expr {Token}
+%type NUM {Token}
+   
+%left PLUS MINUS.   
+%left DIVIDE TIMES.  
+   
+
+   
+%syntax_error {  
+  std::cout << "Syntax error!" << std::endl;  
+}   
+   
+program ::= expr(A).   { 
+                        std::cout << "Result.value=" << A.value << std::endl; 
+                        std::cout << "Result.n=" << A.n << std::endl; 
+
+                         }  
+
+
+expr(A) ::= expr(B) MINUS  expr(C).   { A.value = B.value - C.value; 
+                                       A.n = B.n+1  + C.n+1;
+                                      }  
+
+expr(A) ::= expr(B) PLUS  expr(C).   { A.value = B.value + C.value; 
+                                       A.n = B.n+1  + C.n+1;
+                                      }  
+
+expr(A) ::= expr(B) TIMES  expr(C).   { A.value = B.value * C.value;
+                                        A.n = B.n+1  + C.n+1;
+
+                                         }  
+expr(A) ::= expr(B) DIVIDE expr(C).  { 
+
+         if(C.value != 0){
+           A.value = B.value / C.value;
+           A.n = B.n+1 + C.n+1;
+          }else{
+           std::cout << "divide by zero" << std::endl;
+           }
+}  /* end of DIVIDE */
+expr(A) ::= NUM(B). { A.value = B.value; A.n = B.n+1; }
+

Added: test-suite/trunk/MultiSource/Applications/lemon/example3.y
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/lemon/example3.y?rev=48828&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/lemon/example3.y (added)
+++ test-suite/trunk/MultiSource/Applications/lemon/example3.y Wed Mar 26 12:03:57 2008
@@ -0,0 +1,100 @@
+/* Copyright (GPL) 2004 mchirico at users.sourceforge.net or mchirico at comcast.net
+  Simple lemon parser  example.
+
+  
+    $ ./lemon example2.y                          
+    $ cat main_part2 >> example2.c
+    $ g++ -o ex2  -O2 -s -pipe example2.c
+
+  Now, to run the example.
+
+    $ ./ex2
+    
+  The output will be as follows:
+ 
+    
+    Result.value=17 <-------------------
+    Result.n=4          		|
+    Result.value=-9     		|
+    Result.n=4          		|
+    Result.value=78     		|
+    Result.n=10         		|
+					|
+  Take a look at main_part2		|
+					|
+					|
+      t0.value=4;                       | 
+      t0.n=0;                        	|
+                                        |
+      t1.value=13;                   	|
+      t1.n=0;                        	|
+                                     	|
+      //Note below is 4 PLUS 17   ------
+      Parse (pParser, NUM, t0);      	
+      Parse (pParser, PLUS, t0);     	
+      Parse (pParser, NUM, t1);      	
+      Parse (pParser, 0, t0);        	
+					
+*/					
+					
+%include {   
+#include <iostream>  
+#include "ex3def.h"
+#include "example3.h"
+
+  void token_destructor(Token t)
+    {
+      std::cout << "In token_destructor t.value= " << t.value << std::endl;
+      std::cout << "In token_destructor t.n= " << t.n << std::endl;
+    }
+
+}  
+
+%token_type {Token}
+%default_type {Token}
+%token_destructor { token_destructor($$); }
+
+%type expr {Token}
+%type id {Token}
+   
+%left PLUS MINUS.   
+%left DIVIDE TIMES.  
+   
+%parse_accept {
+  printf("parsing complete!\n\n\n");
+}
+   
+%syntax_error {  
+  std::cout << "Syntax error!" << std::endl;  
+}   
+   
+program ::= expr(A).   { 
+                        std::cout << "Result.value=" << A.value << std::endl; 
+                        std::cout << "Result.n=" << A.n << std::endl; 
+
+                         }  
+
+expr(A) ::= expr(B) MINUS  expr(C).   { A.value = B.value - C.value; 
+                                       A.n = B.n+1  + C.n+1;
+                                      }  
+
+expr(A) ::= expr(B) PLUS  expr(C).   { A.value = B.value + C.value; 
+                                       A.n = B.n+1  + C.n+1;
+                                      }  
+
+expr(A) ::= expr(B) TIMES  expr(C).   { A.value = B.value * C.value;
+                                        A.n = B.n+1  + C.n+1;
+
+                                         }  
+expr(A) ::= expr(B) DIVIDE expr(C).  { 
+
+         if(C.value != 0){
+           A.value = B.value / C.value;
+           A.n = B.n+1 + C.n+1;
+          }else{
+           std::cout << "divide by zero" << std::endl;
+           }
+}  /* end of DIVIDE */
+expr(A) ::= NUM(B). { A.value = B.value; A.n = B.n+1; }
+
+

Added: test-suite/trunk/MultiSource/Applications/lemon/example4.y
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/lemon/example4.y?rev=48828&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/lemon/example4.y (added)
+++ test-suite/trunk/MultiSource/Applications/lemon/example4.y Wed Mar 26 12:03:57 2008
@@ -0,0 +1,87 @@
+/* Copyright (GPL) 2004 mchirico at users.sourceforge.net or mchirico at comcast.net
+  Simple lemon parser  example.
+
+  
+    $ ./lemon example2.y                          
+
+  
+
+*/
+
+%include {   
+#include <iostream>  
+#include "ex4def.h"
+#include "example4.h"
+
+
+  void token_destructor(Token t)
+    {
+      std::cout << "In token_destructor t.value= " << t.value << std::endl;
+      std::cout << "In token_destructor t.n= " << t.n << std::endl;
+    }
+
+
+}  
+
+
+%token_type {Token}
+%default_type {Token}
+%token_destructor { token_destructor($$); }
+
+%type expr {Token}
+%type NUM {Token}
+
+
+
+   
+%left PLUS MINUS.   
+%left DIVIDE TIMES.  
+   
+%parse_accept {
+  printf("parsing complete!\n\n\n");
+}
+
+   
+%syntax_error {  
+  std::cout << "Syntax error!" << std::endl;  
+}   
+   
+/*  This is to terminate with a new line */
+main ::= in.
+in ::= .
+in ::= in state NEWLINE.
+
+
+
+state ::= expr(A).   { 
+                        std::cout << "Result.value=" << A.value << std::endl; 
+                        std::cout << "Result.n=" << A.n << std::endl; 
+
+                         }  
+
+
+
+expr(A) ::= expr(B) MINUS  expr(C).   { A.value = B.value - C.value; 
+                                       A.n = B.n+1  + C.n+1;
+                                      }  
+
+expr(A) ::= expr(B) PLUS  expr(C).   { A.value = B.value + C.value; 
+                                       A.n = B.n+1  + C.n+1;
+                                      }  
+
+expr(A) ::= expr(B) TIMES  expr(C).   { A.value = B.value * C.value;
+                                        A.n = B.n+1  + C.n+1;
+
+                                         }  
+expr(A) ::= expr(B) DIVIDE expr(C).  { 
+
+         if(C.value != 0){
+           A.value = B.value / C.value;
+           A.n = B.n+1 + C.n+1;
+          }else{
+           std::cout << "divide by zero" << std::endl;
+           }
+}  /* end of DIVIDE */
+expr(A) ::= NUM(B). { A.value = B.value; A.n = B.n+1; }
+
+

Added: test-suite/trunk/MultiSource/Applications/lemon/example5.y
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/lemon/example5.y?rev=48828&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/lemon/example5.y (added)
+++ test-suite/trunk/MultiSource/Applications/lemon/example5.y Wed Mar 26 12:03:57 2008
@@ -0,0 +1,95 @@
+/* Copyright (GPL) 2004 mchirico at users.sourceforge.net or mchirico at comcast.net
+  Simple lemon parser  example.
+
+  
+    $ ./lemon example2.y                          
+
+  
+
+*/
+
+%include {   
+#include <iostream>  
+#include "ex5def.h"
+#include "example5.h"
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include "lexglobal.h"
+#define BUFS 1024
+
+
+
+  void token_destructor(Token t)
+    {
+      std::cout << "In token_destructor t.value= " << t.value << std::endl;
+      std::cout << "In token_destructor t.n= " << t.n << std::endl;
+    }
+
+
+}  
+
+
+%token_type {Token}
+%default_type {Token}
+%token_destructor { token_destructor($$); }
+
+%type expr {Token}
+%type id {Token}
+
+
+
+   
+%left PLUS MINUS.   
+%left DIVIDE TIMES.  
+   
+%parse_accept {
+  printf("parsing complete!\n\n\n");
+}
+
+   
+%syntax_error {  
+  std::cout << "Syntax error!" << std::endl;  
+}   
+   
+/*  This is to terminate with a new line */
+main ::= in.
+in ::= .
+in ::= in state NEWLINE.
+
+
+
+state ::= expr(A).   { 
+                        std::cout << "Result.value=" << A.value << std::endl; 
+                        std::cout << "Result.n=" << A.n << std::endl; 
+
+                         }  
+
+
+
+expr(A) ::= expr(B) MINUS  expr(C).   { A.value = B.value - C.value; 
+                                       A.n = B.n+1  + C.n+1;
+                                      }  
+
+expr(A) ::= expr(B) PLUS  expr(C).   { A.value = B.value + C.value; 
+                                       A.n = B.n+1  + C.n+1;
+                                      }  
+
+expr(A) ::= expr(B) TIMES  expr(C).   { A.value = B.value * C.value;
+                                        A.n = B.n+1  + C.n+1;
+
+                                         }  
+expr(A) ::= expr(B) DIVIDE expr(C).  { 
+
+         if(C.value != 0){
+           A.value = B.value / C.value;
+           A.n = B.n+1 + C.n+1;
+          }else{
+           std::cout << "divide by zero" << std::endl;
+           }
+}  /* end of DIVIDE */
+expr(A) ::= NUM(B). { A.value = B.value; A.n = B.n+1; }
+
+

Added: test-suite/trunk/MultiSource/Applications/lemon/example_COPYING
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/lemon/example_COPYING?rev=48828&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/lemon/example_COPYING (added)
+++ test-suite/trunk/MultiSource/Applications/lemon/example_COPYING Wed Mar 26 12:03:57 2008
@@ -0,0 +1,298 @@
+Copyright (C) 2003  Mike Chirico mmc mchirico at users.sourceforge.net 
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+
+
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS

Added: test-suite/trunk/MultiSource/Applications/lemon/lemon.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/lemon/lemon.c?rev=48828&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/lemon/lemon.c (added)
+++ test-suite/trunk/MultiSource/Applications/lemon/lemon.c Wed Mar 26 12:03:57 2008
@@ -0,0 +1,4867 @@
+/*
+** This file contains all sources (including headers) to the LEMON
+** LALR(1) parser generator.  The sources have been combined into a
+** single file to make it easy to include LEMON in the source tree
+** and Makefile of another program.
+**
+** The author of this program disclaims copyright.
+*/
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#ifndef __WIN32__
+#   if defined(_WIN32) || defined(WIN32)
+#	define __WIN32__
+#   endif
+#endif
+
+#ifdef __WIN32__
+extern int access();
+#else
+#include <unistd.h>
+#endif
+
+/* #define PRIVATE static */
+#define PRIVATE
+
+#ifdef TEST
+#define MAXRHS 5       /* Set low to exercise exception code */
+#else
+#define MAXRHS 1000
+#endif
+
+static char *msort(char*,char**,int(*)(const char*,const char*));
+
+static struct action *Action_new(void);
+static struct action *Action_sort(struct action *);
+
+/********** From the file "build.h" ************************************/
+void FindRulePrecedences();
+void FindFirstSets();
+void FindStates();
+void FindLinks();
+void FindFollowSets();
+void FindActions();
+
+/********* From the file "configlist.h" *********************************/
+void Configlist_init(/* void */);
+struct config *Configlist_add(/* struct rule *, int */);
+struct config *Configlist_addbasis(/* struct rule *, int */);
+void Configlist_closure(/* void */);
+void Configlist_sort(/* void */);
+void Configlist_sortbasis(/* void */);
+struct config *Configlist_return(/* void */);
+struct config *Configlist_basis(/* void */);
+void Configlist_eat(/* struct config * */);
+void Configlist_reset(/* void */);
+
+/********* From the file "error.h" ***************************************/
+void ErrorMsg(const char *, int,const char *, ...);
+
+/****** From the file "option.h" ******************************************/
+struct s_options {
+  enum { OPT_FLAG=1,  OPT_INT,  OPT_DBL,  OPT_STR,
+         OPT_FFLAG, OPT_FINT, OPT_FDBL, OPT_FSTR} type;
+  char *label;
+  char *arg;
+  char *message;
+};
+int    OptInit(/* char**,struct s_options*,FILE* */);
+int    OptNArgs(/* void */);
+char  *OptArg(/* int */);
+void   OptErr(/* int */);
+void   OptPrint(/* void */);
+
+/******** From the file "parse.h" *****************************************/
+void Parse(/* struct lemon *lemp */);
+
+/********* From the file "plink.h" ***************************************/
+struct plink *Plink_new(/* void */);
+void Plink_add(/* struct plink **, struct config * */);
+void Plink_copy(/* struct plink **, struct plink * */);
+void Plink_delete(/* struct plink * */);
+
+/********** From the file "report.h" *************************************/
+void Reprint(/* struct lemon * */);
+void ReportOutput(/* struct lemon * */);
+void ReportTable(/* struct lemon * */);
+void ReportHeader(/* struct lemon * */);
+void CompressTables(/* struct lemon * */);
+void ResortStates(/* struct lemon * */);
+
+/********** From the file "set.h" ****************************************/
+void  SetSize(/* int N */);             /* All sets will be of size N */
+char *SetNew(/* void */);               /* A new set for element 0..N */
+void  SetFree(/* char* */);             /* Deallocate a set */
+
+int SetAdd(/* char*,int */);            /* Add element to a set */
+int SetUnion(/* char *A,char *B */);    /* A <- A U B, thru element N */
+
+#define SetFind(X,Y) (X[Y])       /* True if Y is in set X */
+
+/********** From the file "struct.h" *************************************/
+/*
+** Principal data structures for the LEMON parser generator.
+*/
+
+typedef enum {LEMON_FALSE=0, LEMON_TRUE} Boolean;
+
+/* Symbols (terminals and nonterminals) of the grammar are stored
+** in the following: */
+struct symbol {
+  char *name;              /* Name of the symbol */
+  int index;               /* Index number for this symbol */
+  enum {
+    TERMINAL,
+    NONTERMINAL,
+    MULTITERMINAL
+  } type;                  /* Symbols are all either TERMINALS or NTs */
+  struct rule *rule;       /* Linked list of rules of this (if an NT) */
+  struct symbol *fallback; /* fallback token in case this token doesn't parse */
+  int prec;                /* Precedence if defined (-1 otherwise) */
+  enum e_assoc {
+    LEFT,
+    RIGHT,
+    NONE,
+    UNK
+  } assoc;                 /* Associativity if predecence is defined */
+  char *firstset;          /* First-set for all rules of this symbol */
+  Boolean lambda;          /* True if NT and can generate an empty string */
+  int useCnt;              /* Number of times used */
+  char *destructor;        /* Code which executes whenever this symbol is
+                           ** popped from the stack during error processing */
+  int destructorln;        /* Line number of destructor code */
+  char *datatype;          /* The data type of information held by this
+                           ** object. Only used if type==NONTERMINAL */
+  int dtnum;               /* The data type number.  In the parser, the value
+                           ** stack is a union.  The .yy%d element of this
+                           ** union is the correct data type for this object */
+  /* The following fields are used by MULTITERMINALs only */
+  int nsubsym;             /* Number of constituent symbols in the MULTI */
+  struct symbol **subsym;  /* Array of constituent symbols */
+};
+
+/* Each production rule in the grammar is stored in the following
+** structure.  */
+struct rule {
+  struct symbol *lhs;      /* Left-hand side of the rule */
+  char *lhsalias;          /* Alias for the LHS (NULL if none) */
+  int lhsStart;            /* True if left-hand side is the start symbol */
+  int ruleline;            /* Line number for the rule */
+  int nrhs;                /* Number of RHS symbols */
+  struct symbol **rhs;     /* The RHS symbols */
+  char **rhsalias;         /* An alias for each RHS symbol (NULL if none) */
+  int line;                /* Line number at which code begins */
+  char *code;              /* The code executed when this rule is reduced */
+  struct symbol *precsym;  /* Precedence symbol for this rule */
+  int index;               /* An index number for this rule */
+  Boolean canReduce;       /* True if this rule is ever reduced */
+  struct rule *nextlhs;    /* Next rule with the same LHS */
+  struct rule *next;       /* Next rule in the global list */
+};
+
+/* A configuration is a production rule of the grammar together with
+** a mark (dot) showing how much of that rule has been processed so far.
+** Configurations also contain a follow-set which is a list of terminal
+** symbols which are allowed to immediately follow the end of the rule.
+** Every configuration is recorded as an instance of the following: */
+struct config {
+  struct rule *rp;         /* The rule upon which the configuration is based */
+  int dot;                 /* The parse point */
+  char *fws;               /* Follow-set for this configuration only */
+  struct plink *fplp;      /* Follow-set forward propagation links */
+  struct plink *bplp;      /* Follow-set backwards propagation links */
+  struct state *stp;       /* Pointer to state which contains this */
+  enum {
+    COMPLETE,              /* The status is used during followset and */
+    INCOMPLETE             /*    shift computations */
+  } status;
+  struct config *next;     /* Next configuration in the state */
+  struct config *bp;       /* The next basis configuration */
+};
+
+/* Every shift or reduce operation is stored as one of the following */
+struct action {
+  struct symbol *sp;       /* The look-ahead symbol */
+  enum e_action {
+    SHIFT,
+    ACCEPT,
+    REDUCE,
+    ERROR,
+    SSCONFLICT,              /* A shift/shift conflict */
+    SRCONFLICT,              /* Was a reduce, but part of a conflict */
+    RRCONFLICT,              /* Was a reduce, but part of a conflict */
+    SH_RESOLVED,             /* Was a shift.  Precedence resolved conflict */
+    RD_RESOLVED,             /* Was reduce.  Precedence resolved conflict */
+    NOT_USED                 /* Deleted by compression */
+  } type;
+  union {
+    struct state *stp;     /* The new state, if a shift */
+    struct rule *rp;       /* The rule, if a reduce */
+  } x;
+  struct action *next;     /* Next action for this state */
+  struct action *collide;  /* Next action with the same hash */
+};
+
+/* Each state of the generated parser's finite state machine
+** is encoded as an instance of the following structure. */
+struct state {
+  struct config *bp;       /* The basis configurations for this state */
+  struct config *cfp;      /* All configurations in this set */
+  int statenum;            /* Sequencial number for this state */
+  struct action *ap;       /* Array of actions for this state */
+  int nTknAct, nNtAct;     /* Number of actions on terminals and nonterminals */
+  int iTknOfst, iNtOfst;   /* yy_action[] offset for terminals and nonterms */
+  int iDflt;               /* Default action */
+};
+#define NO_OFFSET (-2147483647)
+
+/* A followset propagation link indicates that the contents of one
+** configuration followset should be propagated to another whenever
+** the first changes. */
+struct plink {
+  struct config *cfp;      /* The configuration to which linked */
+  struct plink *next;      /* The next propagate link */
+};
+
+/* The state vector for the entire parser generator is recorded as
+** follows.  (LEMON uses no global variables and makes little use of
+** static variables.  Fields in the following structure can be thought
+** of as begin global variables in the program.) */
+struct lemon {
+  struct state **sorted;   /* Table of states sorted by state number */
+  struct rule *rule;       /* List of all rules */
+  int nstate;              /* Number of states */
+  int nrule;               /* Number of rules */
+  int nsymbol;             /* Number of terminal and nonterminal symbols */
+  int nterminal;           /* Number of terminal symbols */
+  struct symbol **symbols; /* Sorted array of pointers to symbols */
+  int errorcnt;            /* Number of errors */
+  struct symbol *errsym;   /* The error symbol */
+  struct symbol *wildcard; /* Token that matches anything */
+  char *name;              /* Name of the generated parser */
+  char *arg;               /* Declaration of the 3th argument to parser */
+  char *tokentype;         /* Type of terminal symbols in the parser stack */
+  char *vartype;           /* The default type of non-terminal symbols */
+  char *start;             /* Name of the start symbol for the grammar */
+  char *stacksize;         /* Size of the parser stack */
+  char *include;           /* Code to put at the start of the C file */
+  int  includeln;          /* Line number for start of include code */
+  char *error;             /* Code to execute when an error is seen */
+  int  errorln;            /* Line number for start of error code */
+  char *overflow;          /* Code to execute on a stack overflow */
+  int  overflowln;         /* Line number for start of overflow code */
+  char *failure;           /* Code to execute on parser failure */
+  int  failureln;          /* Line number for start of failure code */
+  char *accept;            /* Code to execute when the parser excepts */
+  int  acceptln;           /* Line number for the start of accept code */
+  char *extracode;         /* Code appended to the generated file */
+  int  extracodeln;        /* Line number for the start of the extra code */
+  char *tokendest;         /* Code to execute to destroy token data */
+  int  tokendestln;        /* Line number for token destroyer code */
+  char *vardest;           /* Code for the default non-terminal destructor */
+  int  vardestln;          /* Line number for default non-term destructor code*/
+  char *filename;          /* Name of the input file */
+  char *outname;           /* Name of the current output file */
+  char *tokenprefix;       /* A prefix added to token names in the .h file */
+  int nconflict;           /* Number of parsing conflicts */
+  int tablesize;           /* Size of the parse tables */
+  int basisflag;           /* Print only basis configurations */
+  int has_fallback;        /* True if any %fallback is seen in the grammer */
+  char *argv0;             /* Name of the program */
+};
+
+#define MemoryCheck(X) if((X)==0){ \
+  extern void memory_error(); \
+  memory_error(); \
+}
+
+/**************** From the file "table.h" *********************************/
+/*
+** All code in this file has been automatically generated
+** from a specification in the file
+**              "table.q"
+** by the associative array code building program "aagen".
+** Do not edit this file!  Instead, edit the specification
+** file, then rerun aagen.
+*/
+/*
+** Code for processing tables in the LEMON parser generator.
+*/
+
+/* Routines for handling a strings */
+
+char *Strsafe();
+
+void Strsafe_init(/* void */);
+int Strsafe_insert(/* char * */);
+char *Strsafe_find(/* char * */);
+
+/* Routines for handling symbols of the grammar */
+
+struct symbol *Symbol_new();
+int Symbolcmpp(/* struct symbol **, struct symbol ** */);
+void Symbol_init(/* void */);
+int Symbol_insert(/* struct symbol *, char * */);
+struct symbol *Symbol_find(/* char * */);
+struct symbol *Symbol_Nth(/* int */);
+int Symbol_count(/*  */);
+struct symbol **Symbol_arrayof(/*  */);
+
+/* Routines to manage the state table */
+
+int Configcmp(/* struct config *, struct config * */);
+struct state *State_new();
+void State_init(/* void */);
+int State_insert(/* struct state *, struct config * */);
+struct state *State_find(/* struct config * */);
+struct state **State_arrayof(/*  */);
+
+/* Routines used for efficiency in Configlist_add */
+
+void Configtable_init(/* void */);
+int Configtable_insert(/* struct config * */);
+struct config *Configtable_find(/* struct config * */);
+void Configtable_clear(/* int(*)(struct config *) */);
+/****************** From the file "action.c" *******************************/
+/*
+** Routines processing parser actions in the LEMON parser generator.
+*/
+
+/* Allocate a new parser action */
+static struct action *Action_new(void){
+  static struct action *freelist = 0;
+  struct action *new;
+
+  if( freelist==0 ){
+    int i;
+    int amt = 100;
+    freelist = (struct action *)calloc(amt, sizeof(struct action));
+    if( freelist==0 ){
+      fprintf(stderr,"Unable to allocate memory for a new parser action.");
+      exit(1);
+    }
+    for(i=0; i<amt-1; i++) freelist[i].next = &freelist[i+1];
+    freelist[amt-1].next = 0;
+  }
+  new = freelist;
+  freelist = freelist->next;
+  return new;
+}
+
+/* Compare two actions for sorting purposes.  Return negative, zero, or
+** positive if the first action is less than, equal to, or greater than
+** the first
+*/
+static int actioncmp(
+  struct action *ap1,
+  struct action *ap2
+){
+  int rc;
+  rc = ap1->sp->index - ap2->sp->index;
+  if( rc==0 ){
+    rc = (int)ap1->type - (int)ap2->type;
+  }
+  if( rc==0 && ap1->type==REDUCE ){
+    rc = ap1->x.rp->index - ap2->x.rp->index;
+  }
+  return rc;
+}
+
+/* Sort parser actions */
+static struct action *Action_sort(
+  struct action *ap
+){
+  ap = (struct action *)msort((char *)ap,(char **)&ap->next,
+                              (int(*)(const char*,const char*))actioncmp);
+  return ap;
+}
+
+void Action_add(app,type,sp,arg)
+struct action **app;
+enum e_action type;
+struct symbol *sp;
+char *arg;
+{
+  struct action *new;
+  new = Action_new();
+  new->next = *app;
+  *app = new;
+  new->type = type;
+  new->sp = sp;
+  if( type==SHIFT ){
+    new->x.stp = (struct state *)arg;
+  }else{
+    new->x.rp = (struct rule *)arg;
+  }
+}
+/********************** New code to implement the "acttab" module ***********/
+/*
+** This module implements routines use to construct the yy_action[] table.
+*/
+
+/*
+** The state of the yy_action table under construction is an instance of
+** the following structure
+*/
+typedef struct acttab acttab;
+struct acttab {
+  int nAction;                 /* Number of used slots in aAction[] */
+  int nActionAlloc;            /* Slots allocated for aAction[] */
+  struct {
+    int lookahead;             /* Value of the lookahead token */
+    int action;                /* Action to take on the given lookahead */
+  } *aAction,                  /* The yy_action[] table under construction */
+    *aLookahead;               /* A single new transaction set */
+  int mnLookahead;             /* Minimum aLookahead[].lookahead */
+  int mnAction;                /* Action associated with mnLookahead */
+  int mxLookahead;             /* Maximum aLookahead[].lookahead */
+  int nLookahead;              /* Used slots in aLookahead[] */
+  int nLookaheadAlloc;         /* Slots allocated in aLookahead[] */
+};
+
+/* Return the number of entries in the yy_action table */
+#define acttab_size(X) ((X)->nAction)
+
+/* The value for the N-th entry in yy_action */
+#define acttab_yyaction(X,N)  ((X)->aAction[N].action)
+
+/* The value for the N-th entry in yy_lookahead */
+#define acttab_yylookahead(X,N)  ((X)->aAction[N].lookahead)
+
+/* Free all memory associated with the given acttab */
+void acttab_free(acttab *p){
+  free( p->aAction );
+  free( p->aLookahead );
+  free( p );
+}
+
+/* Allocate a new acttab structure */
+acttab *acttab_alloc(void){
+  acttab *p = calloc( 1, sizeof(*p) );
+  if( p==0 ){
+    fprintf(stderr,"Unable to allocate memory for a new acttab.");
+    exit(1);
+  }
+  memset(p, 0, sizeof(*p));
+  return p;
+}
+
+/* Add a new action to the current transaction set
+*/
+void acttab_action(acttab *p, int lookahead, int action){
+  if( p->nLookahead>=p->nLookaheadAlloc ){
+    p->nLookaheadAlloc += 25;
+    p->aLookahead = realloc( p->aLookahead,
+                             sizeof(p->aLookahead[0])*p->nLookaheadAlloc );
+    if( p->aLookahead==0 ){
+      fprintf(stderr,"malloc failed\n");
+      exit(1);
+    }
+  }
+  if( p->nLookahead==0 ){
+    p->mxLookahead = lookahead;
+    p->mnLookahead = lookahead;
+    p->mnAction = action;
+  }else{
+    if( p->mxLookahead<lookahead ) p->mxLookahead = lookahead;
+    if( p->mnLookahead>lookahead ){
+      p->mnLookahead = lookahead;
+      p->mnAction = action;
+    }
+  }
+  p->aLookahead[p->nLookahead].lookahead = lookahead;
+  p->aLookahead[p->nLookahead].action = action;
+  p->nLookahead++;
+}
+
+/*
+** Add the transaction set built up with prior calls to acttab_action()
+** into the current action table.  Then reset the transaction set back
+** to an empty set in preparation for a new round of acttab_action() calls.
+**
+** Return the offset into the action table of the new transaction.
+*/
+int acttab_insert(acttab *p){
+  int i, j, k, n;
+  assert( p->nLookahead>0 );
+
+  /* Make sure we have enough space to hold the expanded action table
+  ** in the worst case.  The worst case occurs if the transaction set
+  ** must be appended to the current action table
+  */
+  n = p->mxLookahead + 1;
+  if( p->nAction + n >= p->nActionAlloc ){
+    int oldAlloc = p->nActionAlloc;
+    p->nActionAlloc = p->nAction + n + p->nActionAlloc + 20;
+    p->aAction = realloc( p->aAction,
+                          sizeof(p->aAction[0])*p->nActionAlloc);
+    if( p->aAction==0 ){
+      fprintf(stderr,"malloc failed\n");
+      exit(1);
+    }
+    for(i=oldAlloc; i<p->nActionAlloc; i++){
+      p->aAction[i].lookahead = -1;
+      p->aAction[i].action = -1;
+    }
+  }
+
+  /* Scan the existing action table looking for an offset where we can
+  ** insert the current transaction set.  Fall out of the loop when that
+  ** offset is found.  In the worst case, we fall out of the loop when
+  ** i reaches p->nAction, which means we append the new transaction set.
+  **
+  ** i is the index in p->aAction[] where p->mnLookahead is inserted.
+  */
+  for(i=0; i<p->nAction+p->mnLookahead; i++){
+    if( p->aAction[i].lookahead<0 ){
+      for(j=0; j<p->nLookahead; j++){
+        k = p->aLookahead[j].lookahead - p->mnLookahead + i;
+        if( k<0 ) break;
+        if( p->aAction[k].lookahead>=0 ) break;
+      }
+      if( j<p->nLookahead ) continue;
+      for(j=0; j<p->nAction; j++){
+        if( p->aAction[j].lookahead==j+p->mnLookahead-i ) break;
+      }
+      if( j==p->nAction ){
+        break;  /* Fits in empty slots */
+      }
+    }else if( p->aAction[i].lookahead==p->mnLookahead ){
+      if( p->aAction[i].action!=p->mnAction ) continue;
+      for(j=0; j<p->nLookahead; j++){
+        k = p->aLookahead[j].lookahead - p->mnLookahead + i;
+        if( k<0 || k>=p->nAction ) break;
+        if( p->aLookahead[j].lookahead!=p->aAction[k].lookahead ) break;
+        if( p->aLookahead[j].action!=p->aAction[k].action ) break;
+      }
+      if( j<p->nLookahead ) continue;
+      n = 0;
+      for(j=0; j<p->nAction; j++){
+        if( p->aAction[j].lookahead<0 ) continue;
+        if( p->aAction[j].lookahead==j+p->mnLookahead-i ) n++;
+      }
+      if( n==p->nLookahead ){
+        break;  /* Same as a prior transaction set */
+      }
+    }
+  }
+  /* Insert transaction set at index i. */
+  for(j=0; j<p->nLookahead; j++){
+    k = p->aLookahead[j].lookahead - p->mnLookahead + i;
+    p->aAction[k] = p->aLookahead[j];
+    if( k>=p->nAction ) p->nAction = k+1;
+  }
+  p->nLookahead = 0;
+
+  /* Return the offset that is added to the lookahead in order to get the
+  ** index into yy_action of the action */
+  return i - p->mnLookahead;
+}
+
+/********************** From the file "build.c" *****************************/
+/*
+** Routines to construction the finite state machine for the LEMON
+** parser generator.
+*/
+
+/* Find a precedence symbol of every rule in the grammar.
+** 
+** Those rules which have a precedence symbol coded in the input
+** grammar using the "[symbol]" construct will already have the
+** rp->precsym field filled.  Other rules take as their precedence
+** symbol the first RHS symbol with a defined precedence.  If there
+** are not RHS symbols with a defined precedence, the precedence
+** symbol field is left blank.
+*/
+void FindRulePrecedences(xp)
+struct lemon *xp;
+{
+  struct rule *rp;
+  for(rp=xp->rule; rp; rp=rp->next){
+    if( rp->precsym==0 ){
+      int i, j;
+      for(i=0; i<rp->nrhs && rp->precsym==0; i++){
+        struct symbol *sp = rp->rhs[i];
+        if( sp->type==MULTITERMINAL ){
+          for(j=0; j<sp->nsubsym; j++){
+            if( sp->subsym[j]->prec>=0 ){
+              rp->precsym = sp->subsym[j];
+              break;
+            }
+          }
+        }else if( sp->prec>=0 ){
+          rp->precsym = rp->rhs[i];
+	}
+      }
+    }
+  }
+  return;
+}
+
+/* Find all nonterminals which will generate the empty string.
+** Then go back and compute the first sets of every nonterminal.
+** The first set is the set of all terminal symbols which can begin
+** a string generated by that nonterminal.
+*/
+void FindFirstSets(lemp)
+struct lemon *lemp;
+{
+  int i, j;
+  struct rule *rp;
+  int progress;
+
+  for(i=0; i<lemp->nsymbol; i++){
+    lemp->symbols[i]->lambda = LEMON_FALSE;
+  }
+  for(i=lemp->nterminal; i<lemp->nsymbol; i++){
+    lemp->symbols[i]->firstset = SetNew();
+  }
+
+  /* First compute all lambdas */
+  do{
+    progress = 0;
+    for(rp=lemp->rule; rp; rp=rp->next){
+      if( rp->lhs->lambda ) continue;
+      for(i=0; i<rp->nrhs; i++){
+         struct symbol *sp = rp->rhs[i];
+         if( sp->type!=TERMINAL || sp->lambda==LEMON_FALSE ) break;
+      }
+      if( i==rp->nrhs ){
+        rp->lhs->lambda = LEMON_TRUE;
+        progress = 1;
+      }
+    }
+  }while( progress );
+
+  /* Now compute all first sets */
+  do{
+    struct symbol *s1, *s2;
+    progress = 0;
+    for(rp=lemp->rule; rp; rp=rp->next){
+      s1 = rp->lhs;
+      for(i=0; i<rp->nrhs; i++){
+        s2 = rp->rhs[i];
+        if( s2->type==TERMINAL ){
+          progress += SetAdd(s1->firstset,s2->index);
+          break;
+        }else if( s2->type==MULTITERMINAL ){
+          for(j=0; j<s2->nsubsym; j++){
+            progress += SetAdd(s1->firstset,s2->subsym[j]->index);
+          }
+          break;
+	}else if( s1==s2 ){
+          if( s1->lambda==LEMON_FALSE ) break;
+	}else{
+          progress += SetUnion(s1->firstset,s2->firstset);
+          if( s2->lambda==LEMON_FALSE ) break;
+	}
+      }
+    }
+  }while( progress );
+  return;
+}
+
+/* Compute all LR(0) states for the grammar.  Links
+** are added to between some states so that the LR(1) follow sets
+** can be computed later.
+*/
+PRIVATE struct state *getstate(/* struct lemon * */);  /* forward reference */
+void FindStates(lemp)
+struct lemon *lemp;
+{
+  struct symbol *sp;
+  struct rule *rp;
+
+  Configlist_init();
+
+  /* Find the start symbol */
+  if( lemp->start ){
+    sp = Symbol_find(lemp->start);
+    if( sp==0 ){
+      ErrorMsg(lemp->filename,0,
+"The specified start symbol \"%s\" is not \
+in a nonterminal of the grammar.  \"%s\" will be used as the start \
+symbol instead.",lemp->start,lemp->rule->lhs->name);
+      lemp->errorcnt++;
+      sp = lemp->rule->lhs;
+    }
+  }else{
+    sp = lemp->rule->lhs;
+  }
+
+  /* Make sure the start symbol doesn't occur on the right-hand side of
+  ** any rule.  Report an error if it does.  (YACC would generate a new
+  ** start symbol in this case.) */
+  for(rp=lemp->rule; rp; rp=rp->next){
+    int i;
+    for(i=0; i<rp->nrhs; i++){
+      if( rp->rhs[i]==sp ){   /* FIX ME:  Deal with multiterminals */
+        ErrorMsg(lemp->filename,0,
+"The start symbol \"%s\" occurs on the \
+right-hand side of a rule. This will result in a parser which \
+does not work properly.",sp->name);
+        lemp->errorcnt++;
+      }
+    }
+  }
+
+  /* The basis configuration set for the first state
+  ** is all rules which have the start symbol as their
+  ** left-hand side */
+  for(rp=sp->rule; rp; rp=rp->nextlhs){
+    struct config *newcfp;
+    rp->lhsStart = 1;
+    newcfp = Configlist_addbasis(rp,0);
+    SetAdd(newcfp->fws,0);
+  }
+
+  /* Compute the first state.  All other states will be
+  ** computed automatically during the computation of the first one.
+  ** The returned pointer to the first state is not used. */
+  (void)getstate(lemp);
+  return;
+}
+
+/* Return a pointer to a state which is described by the configuration
+** list which has been built from calls to Configlist_add.
+*/
+PRIVATE void buildshifts(/* struct lemon *, struct state * */); /* Forwd ref */
+PRIVATE struct state *getstate(lemp)
+struct lemon *lemp;
+{
+  struct config *cfp, *bp;
+  struct state *stp;
+
+  /* Extract the sorted basis of the new state.  The basis was constructed
+  ** by prior calls to "Configlist_addbasis()". */
+  Configlist_sortbasis();
+  bp = Configlist_basis();
+
+  /* Get a state with the same basis */
+  stp = State_find(bp);
+  if( stp ){
+    /* A state with the same basis already exists!  Copy all the follow-set
+    ** propagation links from the state under construction into the
+    ** preexisting state, then return a pointer to the preexisting state */
+    struct config *x, *y;
+    for(x=bp, y=stp->bp; x && y; x=x->bp, y=y->bp){
+      Plink_copy(&y->bplp,x->bplp);
+      Plink_delete(x->fplp);
+      x->fplp = x->bplp = 0;
+    }
+    cfp = Configlist_return();
+    Configlist_eat(cfp);
+  }else{
+    /* This really is a new state.  Construct all the details */
+    Configlist_closure(lemp);    /* Compute the configuration closure */
+    Configlist_sort();           /* Sort the configuration closure */
+    cfp = Configlist_return();   /* Get a pointer to the config list */
+    stp = State_new();           /* A new state structure */
+    MemoryCheck(stp);
+    stp->bp = bp;                /* Remember the configuration basis */
+    stp->cfp = cfp;              /* Remember the configuration closure */
+    stp->statenum = lemp->nstate++; /* Every state gets a sequence number */
+    stp->ap = 0;                 /* No actions, yet. */
+    State_insert(stp,stp->bp);   /* Add to the state table */
+    buildshifts(lemp,stp);       /* Recursively compute successor states */
+  }
+  return stp;
+}
+
+/*
+** Return true if two symbols are the same.
+*/
+int same_symbol(a,b)
+struct symbol *a;
+struct symbol *b;
+{
+  int i;
+  if( a==b ) return 1;
+  if( a->type!=MULTITERMINAL ) return 0;
+  if( b->type!=MULTITERMINAL ) return 0;
+  if( a->nsubsym!=b->nsubsym ) return 0;
+  for(i=0; i<a->nsubsym; i++){
+    if( a->subsym[i]!=b->subsym[i] ) return 0;
+  }
+  return 1;
+}
+
+/* Construct all successor states to the given state.  A "successor"
+** state is any state which can be reached by a shift action.
+*/
+PRIVATE void buildshifts(lemp,stp)
+struct lemon *lemp;
+struct state *stp;     /* The state from which successors are computed */
+{
+  struct config *cfp;  /* For looping thru the config closure of "stp" */
+  struct config *bcfp; /* For the inner loop on config closure of "stp" */
+  struct config *new;  /* */
+  struct symbol *sp;   /* Symbol following the dot in configuration "cfp" */
+  struct symbol *bsp;  /* Symbol following the dot in configuration "bcfp" */
+  struct state *newstp; /* A pointer to a successor state */
+
+  /* Each configuration becomes complete after it contibutes to a successor
+  ** state.  Initially, all configurations are incomplete */
+  for(cfp=stp->cfp; cfp; cfp=cfp->next) cfp->status = INCOMPLETE;
+
+  /* Loop through all configurations of the state "stp" */
+  for(cfp=stp->cfp; cfp; cfp=cfp->next){
+    if( cfp->status==COMPLETE ) continue;    /* Already used by inner loop */
+    if( cfp->dot>=cfp->rp->nrhs ) continue;  /* Can't shift this config */
+    Configlist_reset();                      /* Reset the new config set */
+    sp = cfp->rp->rhs[cfp->dot];             /* Symbol after the dot */
+
+    /* For every configuration in the state "stp" which has the symbol "sp"
+    ** following its dot, add the same configuration to the basis set under
+    ** construction but with the dot shifted one symbol to the right. */
+    for(bcfp=cfp; bcfp; bcfp=bcfp->next){
+      if( bcfp->status==COMPLETE ) continue;    /* Already used */
+      if( bcfp->dot>=bcfp->rp->nrhs ) continue; /* Can't shift this one */
+      bsp = bcfp->rp->rhs[bcfp->dot];           /* Get symbol after dot */
+      if( !same_symbol(bsp,sp) ) continue;      /* Must be same as for "cfp" */
+      bcfp->status = COMPLETE;                  /* Mark this config as used */
+      new = Configlist_addbasis(bcfp->rp,bcfp->dot+1);
+      Plink_add(&new->bplp,bcfp);
+    }
+
+    /* Get a pointer to the state described by the basis configuration set
+    ** constructed in the preceding loop */
+    newstp = getstate(lemp);
+
+    /* The state "newstp" is reached from the state "stp" by a shift action
+    ** on the symbol "sp" */
+    if( sp->type==MULTITERMINAL ){
+      int i;
+      for(i=0; i<sp->nsubsym; i++){
+        Action_add(&stp->ap,SHIFT,sp->subsym[i],(char*)newstp);
+      }
+    }else{
+      Action_add(&stp->ap,SHIFT,sp,(char *)newstp);
+    }
+  }
+}
+
+/*
+** Construct the propagation links
+*/
+void FindLinks(lemp)
+struct lemon *lemp;
+{
+  int i;
+  struct config *cfp, *other;
+  struct state *stp;
+  struct plink *plp;
+
+  /* Housekeeping detail:
+  ** Add to every propagate link a pointer back to the state to
+  ** which the link is attached. */
+  for(i=0; i<lemp->nstate; i++){
+    stp = lemp->sorted[i];
+    for(cfp=stp->cfp; cfp; cfp=cfp->next){
+      cfp->stp = stp;
+    }
+  }
+
+  /* Convert all backlinks into forward links.  Only the forward
+  ** links are used in the follow-set computation. */
+  for(i=0; i<lemp->nstate; i++){
+    stp = lemp->sorted[i];
+    for(cfp=stp->cfp; cfp; cfp=cfp->next){
+      for(plp=cfp->bplp; plp; plp=plp->next){
+        other = plp->cfp;
+        Plink_add(&other->fplp,cfp);
+      }
+    }
+  }
+}
+
+/* Compute all followsets.
+**
+** A followset is the set of all symbols which can come immediately
+** after a configuration.
+*/
+void FindFollowSets(lemp)
+struct lemon *lemp;
+{
+  int i;
+  struct config *cfp;
+  struct plink *plp;
+  int progress;
+  int change;
+
+  for(i=0; i<lemp->nstate; i++){
+    for(cfp=lemp->sorted[i]->cfp; cfp; cfp=cfp->next){
+      cfp->status = INCOMPLETE;
+    }
+  }
+  
+  do{
+    progress = 0;
+    for(i=0; i<lemp->nstate; i++){
+      for(cfp=lemp->sorted[i]->cfp; cfp; cfp=cfp->next){
+        if( cfp->status==COMPLETE ) continue;
+        for(plp=cfp->fplp; plp; plp=plp->next){
+          change = SetUnion(plp->cfp->fws,cfp->fws);
+          if( change ){
+            plp->cfp->status = INCOMPLETE;
+            progress = 1;
+	  }
+	}
+        cfp->status = COMPLETE;
+      }
+    }
+  }while( progress );
+}
+
+static int resolve_conflict();
+
+/* Compute the reduce actions, and resolve conflicts.
+*/
+void FindActions(lemp)
+struct lemon *lemp;
+{
+  int i,j;
+  struct config *cfp;
+  struct state *stp;
+  struct symbol *sp;
+  struct rule *rp;
+
+  /* Add all of the reduce actions 
+  ** A reduce action is added for each element of the followset of
+  ** a configuration which has its dot at the extreme right.
+  */
+  for(i=0; i<lemp->nstate; i++){   /* Loop over all states */
+    stp = lemp->sorted[i];
+    for(cfp=stp->cfp; cfp; cfp=cfp->next){  /* Loop over all configurations */
+      if( cfp->rp->nrhs==cfp->dot ){        /* Is dot at extreme right? */
+        for(j=0; j<lemp->nterminal; j++){
+          if( SetFind(cfp->fws,j) ){
+            /* Add a reduce action to the state "stp" which will reduce by the
+            ** rule "cfp->rp" if the lookahead symbol is "lemp->symbols[j]" */
+            Action_add(&stp->ap,REDUCE,lemp->symbols[j],(char *)cfp->rp);
+          }
+	}
+      }
+    }
+  }
+
+  /* Add the accepting token */
+  if( lemp->start ){
+    sp = Symbol_find(lemp->start);
+    if( sp==0 ) sp = lemp->rule->lhs;
+  }else{
+    sp = lemp->rule->lhs;
+  }
+  /* Add to the first state (which is always the starting state of the
+  ** finite state machine) an action to ACCEPT if the lookahead is the
+  ** start nonterminal.  */
+  Action_add(&lemp->sorted[0]->ap,ACCEPT,sp,0);
+
+  /* Resolve conflicts */
+  for(i=0; i<lemp->nstate; i++){
+    struct action *ap, *nap;
+    struct state *stp;
+    stp = lemp->sorted[i];
+    /* assert( stp->ap ); */
+    stp->ap = Action_sort(stp->ap);
+    for(ap=stp->ap; ap && ap->next; ap=ap->next){
+      for(nap=ap->next; nap && nap->sp==ap->sp; nap=nap->next){
+         /* The two actions "ap" and "nap" have the same lookahead.
+         ** Figure out which one should be used */
+         lemp->nconflict += resolve_conflict(ap,nap,lemp->errsym);
+      }
+    }
+  }
+
+  /* Report an error for each rule that can never be reduced. */
+  for(rp=lemp->rule; rp; rp=rp->next) rp->canReduce = LEMON_FALSE;
+  for(i=0; i<lemp->nstate; i++){
+    struct action *ap;
+    for(ap=lemp->sorted[i]->ap; ap; ap=ap->next){
+      if( ap->type==REDUCE ) ap->x.rp->canReduce = LEMON_TRUE;
+    }
+  }
+  for(rp=lemp->rule; rp; rp=rp->next){
+    if( rp->canReduce ) continue;
+    ErrorMsg(lemp->filename,rp->ruleline,"This rule can not be reduced.\n");
+    lemp->errorcnt++;
+  }
+}
+
+/* Resolve a conflict between the two given actions.  If the
+** conflict can't be resolve, return non-zero.
+**
+** NO LONGER TRUE:
+**   To resolve a conflict, first look to see if either action
+**   is on an error rule.  In that case, take the action which
+**   is not associated with the error rule.  If neither or both
+**   actions are associated with an error rule, then try to
+**   use precedence to resolve the conflict.
+**
+** If either action is a SHIFT, then it must be apx.  This
+** function won't work if apx->type==REDUCE and apy->type==SHIFT.
+*/
+static int resolve_conflict(apx,apy,errsym)
+struct action *apx;
+struct action *apy;
+struct symbol *errsym;   /* The error symbol (if defined.  NULL otherwise) */
+{
+  struct symbol *spx, *spy;
+  int errcnt = 0;
+  assert( apx->sp==apy->sp );  /* Otherwise there would be no conflict */
+  if( apx->type==SHIFT && apy->type==SHIFT ){
+    apy->type = SSCONFLICT;
+    errcnt++;
+  }
+  if( apx->type==SHIFT && apy->type==REDUCE ){
+    spx = apx->sp;
+    spy = apy->x.rp->precsym;
+    if( spy==0 || spx->prec<0 || spy->prec<0 ){
+      /* Not enough precedence information. */
+      apy->type = SRCONFLICT;
+      errcnt++;
+    }else if( spx->prec>spy->prec ){    /* Lower precedence wins */
+      apy->type = RD_RESOLVED;
+    }else if( spx->prec<spy->prec ){
+      apx->type = SH_RESOLVED;
+    }else if( spx->prec==spy->prec && spx->assoc==RIGHT ){ /* Use operator */
+      apy->type = RD_RESOLVED;                             /* associativity */
+    }else if( spx->prec==spy->prec && spx->assoc==LEFT ){  /* to break tie */
+      apx->type = SH_RESOLVED;
+    }else{
+      assert( spx->prec==spy->prec && spx->assoc==NONE );
+      apy->type = SRCONFLICT;
+      errcnt++;
+    }
+  }else if( apx->type==REDUCE && apy->type==REDUCE ){
+    spx = apx->x.rp->precsym;
+    spy = apy->x.rp->precsym;
+    if( spx==0 || spy==0 || spx->prec<0 ||
+    spy->prec<0 || spx->prec==spy->prec ){
+      apy->type = RRCONFLICT;
+      errcnt++;
+    }else if( spx->prec>spy->prec ){
+      apy->type = RD_RESOLVED;
+    }else if( spx->prec<spy->prec ){
+      apx->type = RD_RESOLVED;
+    }
+  }else{
+    assert( 
+      apx->type==SH_RESOLVED ||
+      apx->type==RD_RESOLVED ||
+      apx->type==SSCONFLICT ||
+      apx->type==SRCONFLICT ||
+      apx->type==RRCONFLICT ||
+      apy->type==SH_RESOLVED ||
+      apy->type==RD_RESOLVED ||
+      apy->type==SSCONFLICT ||
+      apy->type==SRCONFLICT ||
+      apy->type==RRCONFLICT
+    );
+    /* The REDUCE/SHIFT case cannot happen because SHIFTs come before
+    ** REDUCEs on the list.  If we reach this point it must be because
+    ** the parser conflict had already been resolved. */
+  }
+  return errcnt;
+}
+/********************* From the file "configlist.c" *************************/
+/*
+** Routines to processing a configuration list and building a state
+** in the LEMON parser generator.
+*/
+
+static struct config *freelist = 0;      /* List of free configurations */
+static struct config *current = 0;       /* Top of list of configurations */
+static struct config **currentend = 0;   /* Last on list of configs */
+static struct config *basis = 0;         /* Top of list of basis configs */
+static struct config **basisend = 0;     /* End of list of basis configs */
+
+/* Return a pointer to a new configuration */
+PRIVATE struct config *newconfig(){
+  struct config *new;
+  if( freelist==0 ){
+    int i;
+    int amt = 3;
+    freelist = (struct config *)calloc( amt, sizeof(struct config) );
+    if( freelist==0 ){
+      fprintf(stderr,"Unable to allocate memory for a new configuration.");
+      exit(1);
+    }
+    for(i=0; i<amt-1; i++) freelist[i].next = &freelist[i+1];
+    freelist[amt-1].next = 0;
+  }
+  new = freelist;
+  freelist = freelist->next;
+  return new;
+}
+
+/* The configuration "old" is no longer used */
+PRIVATE void deleteconfig(old)
+struct config *old;
+{
+  old->next = freelist;
+  freelist = old;
+}
+
+/* Initialized the configuration list builder */
+void Configlist_init(){
+  current = 0;
+  currentend = ¤t;
+  basis = 0;
+  basisend = &basis;
+  Configtable_init();
+  return;
+}
+
+/* Initialized the configuration list builder */
+void Configlist_reset(){
+  current = 0;
+  currentend = ¤t;
+  basis = 0;
+  basisend = &basis;
+  Configtable_clear(0);
+  return;
+}
+
+/* Add another configuration to the configuration list */
+struct config *Configlist_add(rp,dot)
+struct rule *rp;    /* The rule */
+int dot;            /* Index into the RHS of the rule where the dot goes */
+{
+  struct config *cfp, model;
+
+  assert( currentend!=0 );
+  model.rp = rp;
+  model.dot = dot;
+  cfp = Configtable_find(&model);
+  if( cfp==0 ){
+    cfp = newconfig();
+    cfp->rp = rp;
+    cfp->dot = dot;
+    cfp->fws = SetNew();
+    cfp->stp = 0;
+    cfp->fplp = cfp->bplp = 0;
+    cfp->next = 0;
+    cfp->bp = 0;
+    *currentend = cfp;
+    currentend = &cfp->next;
+    Configtable_insert(cfp);
+  }
+  return cfp;
+}
+
+/* Add a basis configuration to the configuration list */
+struct config *Configlist_addbasis(rp,dot)
+struct rule *rp;
+int dot;
+{
+  struct config *cfp, model;
+
+  assert( basisend!=0 );
+  assert( currentend!=0 );
+  model.rp = rp;
+  model.dot = dot;
+  cfp = Configtable_find(&model);
+  if( cfp==0 ){
+    cfp = newconfig();
+    cfp->rp = rp;
+    cfp->dot = dot;
+    cfp->fws = SetNew();
+    cfp->stp = 0;
+    cfp->fplp = cfp->bplp = 0;
+    cfp->next = 0;
+    cfp->bp = 0;
+    *currentend = cfp;
+    currentend = &cfp->next;
+    *basisend = cfp;
+    basisend = &cfp->bp;
+    Configtable_insert(cfp);
+  }
+  return cfp;
+}
+
+/* Compute the closure of the configuration list */
+void Configlist_closure(lemp)
+struct lemon *lemp;
+{
+  struct config *cfp, *newcfp;
+  struct rule *rp, *newrp;
+  struct symbol *sp, *xsp;
+  int i, dot;
+
+  assert( currentend!=0 );
+  for(cfp=current; cfp; cfp=cfp->next){
+    rp = cfp->rp;
+    dot = cfp->dot;
+    if( dot>=rp->nrhs ) continue;
+    sp = rp->rhs[dot];
+    if( sp->type==NONTERMINAL ){
+      if( sp->rule==0 && sp!=lemp->errsym ){
+        ErrorMsg(lemp->filename,rp->line,"Nonterminal \"%s\" has no rules.",
+          sp->name);
+        lemp->errorcnt++;
+      }
+      for(newrp=sp->rule; newrp; newrp=newrp->nextlhs){
+        newcfp = Configlist_add(newrp,0);
+        for(i=dot+1; i<rp->nrhs; i++){
+          xsp = rp->rhs[i];
+          if( xsp->type==TERMINAL ){
+            SetAdd(newcfp->fws,xsp->index);
+            break;
+          }else if( xsp->type==MULTITERMINAL ){
+            int k;
+            for(k=0; k<xsp->nsubsym; k++){
+              SetAdd(newcfp->fws, xsp->subsym[k]->index);
+            }
+            break;
+	  }else{
+            SetUnion(newcfp->fws,xsp->firstset);
+            if( xsp->lambda==LEMON_FALSE ) break;
+	  }
+	}
+        if( i==rp->nrhs ) Plink_add(&cfp->fplp,newcfp);
+      }
+    }
+  }
+  return;
+}
+
+/* Sort the configuration list */
+void Configlist_sort(){
+  current = (struct config *)msort((char *)current,(char **)&(current->next),Configcmp);
+  currentend = 0;
+  return;
+}
+
+/* Sort the basis configuration list */
+void Configlist_sortbasis(){
+  basis = (struct config *)msort((char *)current,(char **)&(current->bp),Configcmp);
+  basisend = 0;
+  return;
+}
+
+/* Return a pointer to the head of the configuration list and
+** reset the list */
+struct config *Configlist_return(){
+  struct config *old;
+  old = current;
+  current = 0;
+  currentend = 0;
+  return old;
+}
+
+/* Return a pointer to the head of the configuration list and
+** reset the list */
+struct config *Configlist_basis(){
+  struct config *old;
+  old = basis;
+  basis = 0;
+  basisend = 0;
+  return old;
+}
+
+/* Free all elements of the given configuration list */
+void Configlist_eat(cfp)
+struct config *cfp;
+{
+  struct config *nextcfp;
+  for(; cfp; cfp=nextcfp){
+    nextcfp = cfp->next;
+    assert( cfp->fplp==0 );
+    assert( cfp->bplp==0 );
+    if( cfp->fws ) SetFree(cfp->fws);
+    deleteconfig(cfp);
+  }
+  return;
+}
+/***************** From the file "error.c" *********************************/
+/*
+** Code for printing error message.
+*/
+
+/* Find a good place to break "msg" so that its length is at least "min"
+** but no more than "max".  Make the point as close to max as possible.
+*/
+static int findbreak(msg,min,max)
+char *msg;
+int min;
+int max;
+{
+  int i,spot;
+  char c;
+  for(i=spot=min; i<=max; i++){
+    c = msg[i];
+    if( c=='\t' ) msg[i] = ' ';
+    if( c=='\n' ){ msg[i] = ' '; spot = i; break; }
+    if( c==0 ){ spot = i; break; }
+    if( c=='-' && i<max-1 ) spot = i+1;
+    if( c==' ' ) spot = i;
+  }
+  return spot;
+}
+
+/*
+** The error message is split across multiple lines if necessary.  The
+** splits occur at a space, if there is a space available near the end
+** of the line.
+*/
+#define ERRMSGSIZE  10000 /* Hope this is big enough.  No way to error check */
+#define LINEWIDTH      79 /* Max width of any output line */
+#define PREFIXLIMIT    30 /* Max width of the prefix on each line */
+void ErrorMsg(const char *filename, int lineno, const char *format, ...){
+  char errmsg[ERRMSGSIZE];
+  char prefix[PREFIXLIMIT+10];
+  int errmsgsize;
+  int prefixsize;
+  int availablewidth;
+  va_list ap;
+  int end, restart, base;
+
+  va_start(ap, format);
+  /* Prepare a prefix to be prepended to every output line */
+  if( lineno>0 ){
+    sprintf(prefix,"%.*s:%d: ",PREFIXLIMIT-10,filename,lineno);
+  }else{
+    sprintf(prefix,"%.*s: ",PREFIXLIMIT-10,filename);
+  }
+  prefixsize = strlen(prefix);
+  availablewidth = LINEWIDTH - prefixsize;
+
+  /* Generate the error message */
+  vsprintf(errmsg,format,ap);
+  va_end(ap);
+  errmsgsize = strlen(errmsg);
+  /* Remove trailing '\n's from the error message. */
+  while( errmsgsize>0 && errmsg[errmsgsize-1]=='\n' ){
+     errmsg[--errmsgsize] = 0;
+  }
+
+  /* Print the error message */
+  base = 0;
+  while( errmsg[base]!=0 ){
+    end = restart = findbreak(&errmsg[base],0,availablewidth);
+    restart += base;
+    while( errmsg[restart]==' ' ) restart++;
+    fprintf(stdout,"%s%.*s\n",prefix,end,&errmsg[base]);
+    base = restart;
+  }
+}
+/**************** From the file "main.c" ************************************/
+/*
+** Main program file for the LEMON parser generator.
+*/
+
+/* Report an out-of-memory condition and abort.  This function
+** is used mostly by the "MemoryCheck" macro in struct.h
+*/
+void memory_error(){
+  fprintf(stderr,"Out of memory.  Aborting...\n");
+  exit(1);
+}
+
+static int nDefine = 0;      /* Number of -D options on the command line */
+static char **azDefine = 0;  /* Name of the -D macros */
+
+/* This routine is called with the argument to each -D command-line option.
+** Add the macro defined to the azDefine array.
+*/
+static void handle_D_option(char *z){
+  char **paz;
+  nDefine++;
+  azDefine = realloc(azDefine, sizeof(azDefine[0])*nDefine);
+  if( azDefine==0 ){
+    fprintf(stderr,"out of memory\n");
+    exit(1);
+  }
+  paz = &azDefine[nDefine-1];
+  *paz = malloc( strlen(z)+1 );
+  if( *paz==0 ){
+    fprintf(stderr,"out of memory\n");
+    exit(1);
+  }
+  strcpy(*paz, z);
+  for(z=*paz; *z && *z!='='; z++){}
+  *z = 0;
+}
+
+
+/* The main program.  Parse the command line and do it... */
+int lemon_main(int argc,char **argv)
+{
+  static int version = 0;
+  static int rpflag = 0;
+  static int basisflag = 0;
+  static int compress = 0;
+  static int quiet = 0;
+  static int statistics = 0;
+  static int mhflag = 0;
+  static struct s_options options[] = {
+    {OPT_FLAG, "b", (char*)&basisflag, "Print only the basis in report."},
+    {OPT_FLAG, "c", (char*)&compress, "Don't compress the action table."},
+    {OPT_FSTR, "D", (char*)handle_D_option, "Define an %ifdef macro."},
+    {OPT_FLAG, "g", (char*)&rpflag, "Print grammar without actions."},
+    {OPT_FLAG, "m", (char*)&mhflag, "Output a makeheaders compatible file"},
+    {OPT_FLAG, "q", (char*)&quiet, "(Quiet) Don't print the report file."},
+    {OPT_FLAG, "s", (char*)&statistics,
+                                   "Print parser stats to standard output."},
+    {OPT_FLAG, "x", (char*)&version, "Print the version number."},
+    {OPT_FLAG,0,0,0}
+  };
+  int i;
+  struct lemon lem;
+
+  OptInit(argv,options,stderr);
+  if( version ){
+     printf("Lemon version 1.0\n");
+     exit(0); 
+  }
+  if( OptNArgs()!=1 ){
+    fprintf(stderr,"Exactly one filename argument is required.\n");
+    exit(1);
+  }
+  memset(&lem, 0, sizeof(lem));
+  lem.errorcnt = 0;
+
+  /* Initialize the machine */
+  Strsafe_init();
+  Symbol_init();
+  State_init();
+  lem.argv0 = argv[0];
+  lem.filename = OptArg(0);
+  lem.basisflag = basisflag;
+  Symbol_new("$");
+  lem.errsym = Symbol_new("error");
+  lem.errsym->useCnt = 0;
+
+  /* Parse the input file */
+  Parse(&lem);
+  if( lem.errorcnt ) exit(lem.errorcnt);
+  if( lem.nrule==0 ){
+    fprintf(stderr,"Empty grammar.\n");
+    exit(1);
+  }
+
+  /* Count and index the symbols of the grammar */
+  lem.nsymbol = Symbol_count();
+  Symbol_new("{default}");
+  lem.symbols = Symbol_arrayof();
+  for(i=0; i<=lem.nsymbol; i++) lem.symbols[i]->index = i;
+  qsort(lem.symbols,lem.nsymbol+1,sizeof(struct symbol*),
+        (int(*)())Symbolcmpp);
+  for(i=0; i<=lem.nsymbol; i++) lem.symbols[i]->index = i;
+  for(i=1; isupper(lem.symbols[i]->name[0]); i++);
+  lem.nterminal = i;
+
+  /* Generate a reprint of the grammar, if requested on the command line */
+  if( rpflag ){
+    Reprint(&lem);
+  }else{
+    /* Initialize the size for all follow and first sets */
+    SetSize(lem.nterminal+1);
+
+    /* Find the precedence for every production rule (that has one) */
+    FindRulePrecedences(&lem);
+
+    /* Compute the lambda-nonterminals and the first-sets for every
+    ** nonterminal */
+    FindFirstSets(&lem);
+
+    /* Compute all LR(0) states.  Also record follow-set propagation
+    ** links so that the follow-set can be computed later */
+    lem.nstate = 0;
+    FindStates(&lem);
+    lem.sorted = State_arrayof();
+
+    /* Tie up loose ends on the propagation links */
+    FindLinks(&lem);
+
+    /* Compute the follow set of every reducible configuration */
+    FindFollowSets(&lem);
+
+    /* Compute the action tables */
+    FindActions(&lem);
+
+    /* Compress the action tables */
+    if( compress==0 ) CompressTables(&lem);
+
+    /* Reorder and renumber the states so that states with fewer choices
+    ** occur at the end. */
+    ResortStates(&lem);
+
+    /* Generate a report of the parser generated.  (the "y.output" file) */
+    if( !quiet ) ReportOutput(&lem);
+
+    /* Generate the source code for the parser */
+    ReportTable(&lem, mhflag);
+
+    /* Produce a header file for use by the scanner.  (This step is
+    ** omitted if the "-m" option is used because makeheaders will
+    ** generate the file for us.) */
+    if( !mhflag ) ReportHeader(&lem);
+  }
+  if( statistics ){
+    printf("Parser statistics: %d terminals, %d nonterminals, %d rules\n",
+      lem.nterminal, lem.nsymbol - lem.nterminal, lem.nrule);
+    printf("                   %d states, %d parser table entries, %d conflicts\n",
+      lem.nstate, lem.tablesize, lem.nconflict);
+  }
+  if( lem.nconflict ){
+    fprintf(stderr,"%d parsing conflicts.\n",lem.nconflict);
+  }
+  exit(lem.errorcnt + lem.nconflict);
+  return (lem.errorcnt + lem.nconflict);
+}
+/******************** From the file "msort.c" *******************************/
+/*
+** A generic merge-sort program.
+**
+** USAGE:
+** Let "ptr" be a pointer to some structure which is at the head of
+** a null-terminated list.  Then to sort the list call:
+**
+**     ptr = msort(ptr,&(ptr->next),cmpfnc);
+**
+** In the above, "cmpfnc" is a pointer to a function which compares
+** two instances of the structure and returns an integer, as in
+** strcmp.  The second argument is a pointer to the pointer to the
+** second element of the linked list.  This address is used to compute
+** the offset to the "next" field within the structure.  The offset to
+** the "next" field must be constant for all structures in the list.
+**
+** The function returns a new pointer which is the head of the list
+** after sorting.
+**
+** ALGORITHM:
+** Merge-sort.
+*/
+
+/*
+** Return a pointer to the next structure in the linked list.
+*/
+#define NEXT(A) (*(char**)(((unsigned long)A)+offset))
+
+/*
+** Inputs:
+**   a:       A sorted, null-terminated linked list.  (May be null).
+**   b:       A sorted, null-terminated linked list.  (May be null).
+**   cmp:     A pointer to the comparison function.
+**   offset:  Offset in the structure to the "next" field.
+**
+** Return Value:
+**   A pointer to the head of a sorted list containing the elements
+**   of both a and b.
+**
+** Side effects:
+**   The "next" pointers for elements in the lists a and b are
+**   changed.
+*/
+static char *merge(
+  char *a,
+  char *b,
+  int (*cmp)(const char*,const char*),
+  int offset
+){
+  char *ptr, *head;
+
+  if( a==0 ){
+    head = b;
+  }else if( b==0 ){
+    head = a;
+  }else{
+    if( (*cmp)(a,b)<0 ){
+      ptr = a;
+      a = NEXT(a);
+    }else{
+      ptr = b;
+      b = NEXT(b);
+    }
+    head = ptr;
+    while( a && b ){
+      if( (*cmp)(a,b)<0 ){
+        NEXT(ptr) = a;
+        ptr = a;
+        a = NEXT(a);
+      }else{
+        NEXT(ptr) = b;
+        ptr = b;
+        b = NEXT(b);
+      }
+    }
+    if( a ) NEXT(ptr) = a;
+    else    NEXT(ptr) = b;
+  }
+  return head;
+}
+
+/*
+** Inputs:
+**   list:      Pointer to a singly-linked list of structures.
+**   next:      Pointer to pointer to the second element of the list.
+**   cmp:       A comparison function.
+**
+** Return Value:
+**   A pointer to the head of a sorted list containing the elements
+**   orginally in list.
+**
+** Side effects:
+**   The "next" pointers for elements in list are changed.
+*/
+#define LISTSIZE 30
+static char *msort(
+  char *list,
+  char **next,
+  int (*cmp)(const char*,const char*)
+){
+  unsigned long offset;
+  char *ep;
+  char *set[LISTSIZE];
+  int i;
+  offset = (unsigned long)next - (unsigned long)list;
+  for(i=0; i<LISTSIZE; i++) set[i] = 0;
+  while( list ){
+    ep = list;
+    list = NEXT(list);
+    NEXT(ep) = 0;
+    for(i=0; i<LISTSIZE-1 && set[i]!=0; i++){
+      ep = merge(ep,set[i],cmp,offset);
+      set[i] = 0;
+    }
+    set[i] = ep;
+  }
+  ep = 0;
+  for(i=0; i<LISTSIZE; i++) if( set[i] ) ep = merge(ep,set[i],cmp,offset);
+  return ep;
+}
+/************************ From the file "option.c" **************************/
+static char **argv;
+static struct s_options *op;
+static FILE *errstream;
+
+#define ISOPT(X) ((X)[0]=='-'||(X)[0]=='+'||strchr((X),'=')!=0)
+
+/*
+** Print the command line with a carrot pointing to the k-th character
+** of the n-th field.
+*/
+static void errline(n,k,err)
+int n;
+int k;
+FILE *err;
+{
+  int spcnt, i;
+  if( argv[0] ) fprintf(err,"%s",argv[0]);
+  spcnt = strlen(argv[0]) + 1;
+  for(i=1; i<n && argv[i]; i++){
+    fprintf(err," %s",argv[i]);
+    spcnt += strlen(argv[i])+1;
+  }
+  spcnt += k;
+  for(; argv[i]; i++) fprintf(err," %s",argv[i]);
+  if( spcnt<20 ){
+    fprintf(err,"\n%*s^-- here\n",spcnt,"");
+  }else{
+    fprintf(err,"\n%*shere --^\n",spcnt-7,"");
+  }
+}
+
+/*
+** Return the index of the N-th non-switch argument.  Return -1
+** if N is out of range.
+*/
+static int argindex(n)
+int n;
+{
+  int i;
+  int dashdash = 0;
+  if( argv!=0 && *argv!=0 ){
+    for(i=1; argv[i]; i++){
+      if( dashdash || !ISOPT(argv[i]) ){
+        if( n==0 ) return i;
+        n--;
+      }
+      if( strcmp(argv[i],"--")==0 ) dashdash = 1;
+    }
+  }
+  return -1;
+}
+
+static char emsg[] = "Command line syntax error: ";
+
+/*
+** Process a flag command line argument.
+*/
+static int handleflags(i,err)
+int i;
+FILE *err;
+{
+  int v;
+  int errcnt = 0;
+  int j;
+  for(j=0; op[j].label; j++){
+    if( strncmp(&argv[i][1],op[j].label,strlen(op[j].label))==0 ) break;
+  }
+  v = argv[i][0]=='-' ? 1 : 0;
+  if( op[j].label==0 ){
+    if( err ){
+      fprintf(err,"%sundefined option.\n",emsg);
+      errline(i,1,err);
+    }
+    errcnt++;
+  }else if( op[j].type==OPT_FLAG ){
+    *((int*)op[j].arg) = v;
+  }else if( op[j].type==OPT_FFLAG ){
+    (*(void(*)())(op[j].arg))(v);
+  }else if( op[j].type==OPT_FSTR ){
+    (*(void(*)())(op[j].arg))(&argv[i][2]);
+  }else{
+    if( err ){
+      fprintf(err,"%smissing argument on switch.\n",emsg);
+      errline(i,1,err);
+    }
+    errcnt++;
+  }
+  return errcnt;
+}
+
+/*
+** Process a command line switch which has an argument.
+*/
+static int handleswitch(i,err)
+int i;
+FILE *err;
+{
+  int lv = 0;
+  double dv = 0.0;
+  char *sv = 0, *end;
+  char *cp;
+  int j;
+  int errcnt = 0;
+  cp = strchr(argv[i],'=');
+  assert( cp!=0 );
+  *cp = 0;
+  for(j=0; op[j].label; j++){
+    if( strcmp(argv[i],op[j].label)==0 ) break;
+  }
+  *cp = '=';
+  if( op[j].label==0 ){
+    if( err ){
+      fprintf(err,"%sundefined option.\n",emsg);
+      errline(i,0,err);
+    }
+    errcnt++;
+  }else{
+    cp++;
+    switch( op[j].type ){
+      case OPT_FLAG:
+      case OPT_FFLAG:
+        if( err ){
+          fprintf(err,"%soption requires an argument.\n",emsg);
+          errline(i,0,err);
+        }
+        errcnt++;
+        break;
+      case OPT_DBL:
+      case OPT_FDBL:
+        dv = strtod(cp,&end);
+        if( *end ){
+          if( err ){
+            fprintf(err,"%sillegal character in floating-point argument.\n",emsg);
+            errline(i,((unsigned long)end)-(unsigned long)argv[i],err);
+          }
+          errcnt++;
+        }
+        break;
+      case OPT_INT:
+      case OPT_FINT:
+        lv = strtol(cp,&end,0);
+        if( *end ){
+          if( err ){
+            fprintf(err,"%sillegal character in integer argument.\n",emsg);
+            errline(i,((unsigned long)end)-(unsigned long)argv[i],err);
+          }
+          errcnt++;
+        }
+        break;
+      case OPT_STR:
+      case OPT_FSTR:
+        sv = cp;
+        break;
+    }
+    switch( op[j].type ){
+      case OPT_FLAG:
+      case OPT_FFLAG:
+        break;
+      case OPT_DBL:
+        *(double*)(op[j].arg) = dv;
+        break;
+      case OPT_FDBL:
+        (*(void(*)())(op[j].arg))(dv);
+        break;
+      case OPT_INT:
+        *(int*)(op[j].arg) = lv;
+        break;
+      case OPT_FINT:
+        (*(void(*)())(op[j].arg))((int)lv);
+        break;
+      case OPT_STR:
+        *(char**)(op[j].arg) = sv;
+        break;
+      case OPT_FSTR:
+        (*(void(*)())(op[j].arg))(sv);
+        break;
+    }
+  }
+  return errcnt;
+}
+
+int OptInit(a,o,err)
+char **a;
+struct s_options *o;
+FILE *err;
+{
+  int errcnt = 0;
+  argv = a;
+  op = o;
+  errstream = err;
+  if( argv && *argv && op ){
+    int i;
+    for(i=1; argv[i]; i++){
+      if( argv[i][0]=='+' || argv[i][0]=='-' ){
+        errcnt += handleflags(i,err);
+      }else if( strchr(argv[i],'=') ){
+        errcnt += handleswitch(i,err);
+      }
+    }
+  }
+  if( errcnt>0 ){
+    fprintf(err,"Valid command line options for \"%s\" are:\n",*a);
+    OptPrint();
+    exit(1);
+  }
+  return 0;
+}
+
+int OptNArgs(){
+  int cnt = 0;
+  int dashdash = 0;
+  int i;
+  if( argv!=0 && argv[0]!=0 ){
+    for(i=1; argv[i]; i++){
+      if( dashdash || !ISOPT(argv[i]) ) cnt++;
+      if( strcmp(argv[i],"--")==0 ) dashdash = 1;
+    }
+  }
+  return cnt;
+}
+
+char *OptArg(n)
+int n;
+{
+  int i;
+  i = argindex(n);
+  return i>=0 ? argv[i] : 0;
+}
+
+void OptErr(n)
+int n;
+{
+  int i;
+  i = argindex(n);
+  if( i>=0 ) errline(i,0,errstream);
+}
+
+void OptPrint(){
+  int i;
+  int max, len;
+  max = 0;
+  for(i=0; op[i].label; i++){
+    len = strlen(op[i].label) + 1;
+    switch( op[i].type ){
+      case OPT_FLAG:
+      case OPT_FFLAG:
+        break;
+      case OPT_INT:
+      case OPT_FINT:
+        len += 9;       /* length of "<integer>" */
+        break;
+      case OPT_DBL:
+      case OPT_FDBL:
+        len += 6;       /* length of "<real>" */
+        break;
+      case OPT_STR:
+      case OPT_FSTR:
+        len += 8;       /* length of "<string>" */
+        break;
+    }
+    if( len>max ) max = len;
+  }
+  for(i=0; op[i].label; i++){
+    switch( op[i].type ){
+      case OPT_FLAG:
+      case OPT_FFLAG:
+        fprintf(errstream,"  -%-*s  %s\n",max,op[i].label,op[i].message);
+        break;
+      case OPT_INT:
+      case OPT_FINT:
+        fprintf(errstream,"  %s=<integer>%*s  %s\n",op[i].label,
+          (int)(max-strlen(op[i].label)-9),"",op[i].message);
+        break;
+      case OPT_DBL:
+      case OPT_FDBL:
+        fprintf(errstream,"  %s=<real>%*s  %s\n",op[i].label,
+          (int)(max-strlen(op[i].label)-6),"",op[i].message);
+        break;
+      case OPT_STR:
+      case OPT_FSTR:
+        fprintf(errstream,"  %s=<string>%*s  %s\n",op[i].label,
+          (int)(max-strlen(op[i].label)-8),"",op[i].message);
+        break;
+    }
+  }
+}
+/*********************** From the file "parse.c" ****************************/
+/*
+** Input file parser for the LEMON parser generator.
+*/
+
+/* The state of the parser */
+struct pstate {
+  char *filename;       /* Name of the input file */
+  int tokenlineno;      /* Linenumber at which current token starts */
+  int errorcnt;         /* Number of errors so far */
+  char *tokenstart;     /* Text of current token */
+  struct lemon *gp;     /* Global state vector */
+  enum e_state {
+    INITIALIZE,
+    WAITING_FOR_DECL_OR_RULE,
+    WAITING_FOR_DECL_KEYWORD,
+    WAITING_FOR_DECL_ARG,
+    WAITING_FOR_PRECEDENCE_SYMBOL,
+    WAITING_FOR_ARROW,
+    IN_RHS,
+    LHS_ALIAS_1,
+    LHS_ALIAS_2,
+    LHS_ALIAS_3,
+    RHS_ALIAS_1,
+    RHS_ALIAS_2,
+    PRECEDENCE_MARK_1,
+    PRECEDENCE_MARK_2,
+    RESYNC_AFTER_RULE_ERROR,
+    RESYNC_AFTER_DECL_ERROR,
+    WAITING_FOR_DESTRUCTOR_SYMBOL,
+    WAITING_FOR_DATATYPE_SYMBOL,
+    WAITING_FOR_FALLBACK_ID,
+    WAITING_FOR_WILDCARD_ID
+  } state;                   /* The state of the parser */
+  struct symbol *fallback;   /* The fallback token */
+  struct symbol *lhs;        /* Left-hand side of current rule */
+  char *lhsalias;            /* Alias for the LHS */
+  int nrhs;                  /* Number of right-hand side symbols seen */
+  struct symbol *rhs[MAXRHS];  /* RHS symbols */
+  char *alias[MAXRHS];       /* Aliases for each RHS symbol (or NULL) */
+  struct rule *prevrule;     /* Previous rule parsed */
+  char *declkeyword;         /* Keyword of a declaration */
+  char **declargslot;        /* Where the declaration argument should be put */
+  int *decllnslot;           /* Where the declaration linenumber is put */
+  enum e_assoc declassoc;    /* Assign this association to decl arguments */
+  int preccounter;           /* Assign this precedence to decl arguments */
+  struct rule *firstrule;    /* Pointer to first rule in the grammar */
+  struct rule *lastrule;     /* Pointer to the most recently parsed rule */
+};
+
+/* Parse a single token */
+static void parseonetoken(psp)
+struct pstate *psp;
+{
+  char *x;
+  x = Strsafe(psp->tokenstart);     /* Save the token permanently */
+#if 0
+  printf("%s:%d: Token=[%s] state=%d\n",psp->filename,psp->tokenlineno,
+    x,psp->state);
+#endif
+  switch( psp->state ){
+    case INITIALIZE:
+      psp->prevrule = 0;
+      psp->preccounter = 0;
+      psp->firstrule = psp->lastrule = 0;
+      psp->gp->nrule = 0;
+      /* Fall thru to next case */
+    case WAITING_FOR_DECL_OR_RULE:
+      if( x[0]=='%' ){
+        psp->state = WAITING_FOR_DECL_KEYWORD;
+      }else if( islower(x[0]) ){
+        psp->lhs = Symbol_new(x);
+        psp->nrhs = 0;
+        psp->lhsalias = 0;
+        psp->state = WAITING_FOR_ARROW;
+      }else if( x[0]=='{' ){
+        if( psp->prevrule==0 ){
+          ErrorMsg(psp->filename,psp->tokenlineno,
+"There is not prior rule opon which to attach the code \
+fragment which begins on this line.");
+          psp->errorcnt++;
+	}else if( psp->prevrule->code!=0 ){
+          ErrorMsg(psp->filename,psp->tokenlineno,
+"Code fragment beginning on this line is not the first \
+to follow the previous rule.");
+          psp->errorcnt++;
+        }else{
+          psp->prevrule->line = psp->tokenlineno;
+          psp->prevrule->code = &x[1];
+	}
+      }else if( x[0]=='[' ){
+        psp->state = PRECEDENCE_MARK_1;
+      }else{
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "Token \"%s\" should be either \"%%\" or a nonterminal name.",
+          x);
+        psp->errorcnt++;
+      }
+      break;
+    case PRECEDENCE_MARK_1:
+      if( !isupper(x[0]) ){
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "The precedence symbol must be a terminal.");
+        psp->errorcnt++;
+      }else if( psp->prevrule==0 ){
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "There is no prior rule to assign precedence \"[%s]\".",x);
+        psp->errorcnt++;
+      }else if( psp->prevrule->precsym!=0 ){
+        ErrorMsg(psp->filename,psp->tokenlineno,
+"Precedence mark on this line is not the first \
+to follow the previous rule.");
+        psp->errorcnt++;
+      }else{
+        psp->prevrule->precsym = Symbol_new(x);
+      }
+      psp->state = PRECEDENCE_MARK_2;
+      break;
+    case PRECEDENCE_MARK_2:
+      if( x[0]!=']' ){
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "Missing \"]\" on precedence mark.");
+        psp->errorcnt++;
+      }
+      psp->state = WAITING_FOR_DECL_OR_RULE;
+      break;
+    case WAITING_FOR_ARROW:
+      if( x[0]==':' && x[1]==':' && x[2]=='=' ){
+        psp->state = IN_RHS;
+      }else if( x[0]=='(' ){
+        psp->state = LHS_ALIAS_1;
+      }else{
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "Expected to see a \":\" following the LHS symbol \"%s\".",
+          psp->lhs->name);
+        psp->errorcnt++;
+        psp->state = RESYNC_AFTER_RULE_ERROR;
+      }
+      break;
+    case LHS_ALIAS_1:
+      if( isalpha(x[0]) ){
+        psp->lhsalias = x;
+        psp->state = LHS_ALIAS_2;
+      }else{
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "\"%s\" is not a valid alias for the LHS \"%s\"\n",
+          x,psp->lhs->name);
+        psp->errorcnt++;
+        psp->state = RESYNC_AFTER_RULE_ERROR;
+      }
+      break;
+    case LHS_ALIAS_2:
+      if( x[0]==')' ){
+        psp->state = LHS_ALIAS_3;
+      }else{
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "Missing \")\" following LHS alias name \"%s\".",psp->lhsalias);
+        psp->errorcnt++;
+        psp->state = RESYNC_AFTER_RULE_ERROR;
+      }
+      break;
+    case LHS_ALIAS_3:
+      if( x[0]==':' && x[1]==':' && x[2]=='=' ){
+        psp->state = IN_RHS;
+      }else{
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "Missing \"->\" following: \"%s(%s)\".",
+           psp->lhs->name,psp->lhsalias);
+        psp->errorcnt++;
+        psp->state = RESYNC_AFTER_RULE_ERROR;
+      }
+      break;
+    case IN_RHS:
+      if( x[0]=='.' ){
+        struct rule *rp;
+        rp = (struct rule *)calloc( sizeof(struct rule) + 
+             sizeof(struct symbol*)*psp->nrhs + sizeof(char*)*psp->nrhs, 1);
+        if( rp==0 ){
+          ErrorMsg(psp->filename,psp->tokenlineno,
+            "Can't allocate enough memory for this rule.");
+          psp->errorcnt++;
+          psp->prevrule = 0;
+	}else{
+          int i;
+          rp->ruleline = psp->tokenlineno;
+          rp->rhs = (struct symbol**)&rp[1];
+          rp->rhsalias = (char**)&(rp->rhs[psp->nrhs]);
+          for(i=0; i<psp->nrhs; i++){
+            rp->rhs[i] = psp->rhs[i];
+            rp->rhsalias[i] = psp->alias[i];
+	  }
+          rp->lhs = psp->lhs;
+          rp->lhsalias = psp->lhsalias;
+          rp->nrhs = psp->nrhs;
+          rp->code = 0;
+          rp->precsym = 0;
+          rp->index = psp->gp->nrule++;
+          rp->nextlhs = rp->lhs->rule;
+          rp->lhs->rule = rp;
+          rp->next = 0;
+          if( psp->firstrule==0 ){
+            psp->firstrule = psp->lastrule = rp;
+	  }else{
+            psp->lastrule->next = rp;
+            psp->lastrule = rp;
+	  }
+          psp->prevrule = rp;
+	}
+        psp->state = WAITING_FOR_DECL_OR_RULE;
+      }else if( isalpha(x[0]) ){
+        if( psp->nrhs>=MAXRHS ){
+          ErrorMsg(psp->filename,psp->tokenlineno,
+            "Too many symbols on RHS of rule beginning at \"%s\".",
+            x);
+          psp->errorcnt++;
+          psp->state = RESYNC_AFTER_RULE_ERROR;
+	}else{
+          psp->rhs[psp->nrhs] = Symbol_new(x);
+          psp->alias[psp->nrhs] = 0;
+          psp->nrhs++;
+	}
+      }else if( (x[0]=='|' || x[0]=='/') && psp->nrhs>0 ){
+        struct symbol *msp = psp->rhs[psp->nrhs-1];
+        if( msp->type!=MULTITERMINAL ){
+          struct symbol *origsp = msp;
+          msp = calloc(1,sizeof(*msp));
+          memset(msp, 0, sizeof(*msp));
+          msp->type = MULTITERMINAL;
+          msp->nsubsym = 1;
+          msp->subsym = calloc(1,sizeof(struct symbol*));
+          msp->subsym[0] = origsp;
+          msp->name = origsp->name;
+          psp->rhs[psp->nrhs-1] = msp;
+        }
+        msp->nsubsym++;
+        msp->subsym = realloc(msp->subsym, sizeof(struct symbol*)*msp->nsubsym);
+        msp->subsym[msp->nsubsym-1] = Symbol_new(&x[1]);
+        if( islower(x[1]) || islower(msp->subsym[0]->name[0]) ){
+          ErrorMsg(psp->filename,psp->tokenlineno,
+            "Cannot form a compound containing a non-terminal");
+          psp->errorcnt++;
+        }
+      }else if( x[0]=='(' && psp->nrhs>0 ){
+        psp->state = RHS_ALIAS_1;
+      }else{
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "Illegal character on RHS of rule: \"%s\".",x);
+        psp->errorcnt++;
+        psp->state = RESYNC_AFTER_RULE_ERROR;
+      }
+      break;
+    case RHS_ALIAS_1:
+      if( isalpha(x[0]) ){
+        psp->alias[psp->nrhs-1] = x;
+        psp->state = RHS_ALIAS_2;
+      }else{
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "\"%s\" is not a valid alias for the RHS symbol \"%s\"\n",
+          x,psp->rhs[psp->nrhs-1]->name);
+        psp->errorcnt++;
+        psp->state = RESYNC_AFTER_RULE_ERROR;
+      }
+      break;
+    case RHS_ALIAS_2:
+      if( x[0]==')' ){
+        psp->state = IN_RHS;
+      }else{
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "Missing \")\" following LHS alias name \"%s\".",psp->lhsalias);
+        psp->errorcnt++;
+        psp->state = RESYNC_AFTER_RULE_ERROR;
+      }
+      break;
+    case WAITING_FOR_DECL_KEYWORD:
+      if( isalpha(x[0]) ){
+        psp->declkeyword = x;
+        psp->declargslot = 0;
+        psp->decllnslot = 0;
+        psp->state = WAITING_FOR_DECL_ARG;
+        if( strcmp(x,"name")==0 ){
+          psp->declargslot = &(psp->gp->name);
+	}else if( strcmp(x,"include")==0 ){
+          psp->declargslot = &(psp->gp->include);
+          psp->decllnslot = &psp->gp->includeln;
+	}else if( strcmp(x,"code")==0 ){
+          psp->declargslot = &(psp->gp->extracode);
+          psp->decllnslot = &psp->gp->extracodeln;
+	}else if( strcmp(x,"token_destructor")==0 ){
+          psp->declargslot = &psp->gp->tokendest;
+          psp->decllnslot = &psp->gp->tokendestln;
+	}else if( strcmp(x,"default_destructor")==0 ){
+          psp->declargslot = &psp->gp->vardest;
+          psp->decllnslot = &psp->gp->vardestln;
+	}else if( strcmp(x,"token_prefix")==0 ){
+          psp->declargslot = &psp->gp->tokenprefix;
+	}else if( strcmp(x,"syntax_error")==0 ){
+          psp->declargslot = &(psp->gp->error);
+          psp->decllnslot = &psp->gp->errorln;
+	}else if( strcmp(x,"parse_accept")==0 ){
+          psp->declargslot = &(psp->gp->accept);
+          psp->decllnslot = &psp->gp->acceptln;
+	}else if( strcmp(x,"parse_failure")==0 ){
+          psp->declargslot = &(psp->gp->failure);
+          psp->decllnslot = &psp->gp->failureln;
+	}else if( strcmp(x,"stack_overflow")==0 ){
+          psp->declargslot = &(psp->gp->overflow);
+          psp->decllnslot = &psp->gp->overflowln;
+        }else if( strcmp(x,"extra_argument")==0 ){
+          psp->declargslot = &(psp->gp->arg);
+        }else if( strcmp(x,"token_type")==0 ){
+          psp->declargslot = &(psp->gp->tokentype);
+        }else if( strcmp(x,"default_type")==0 ){
+          psp->declargslot = &(psp->gp->vartype);
+        }else if( strcmp(x,"stack_size")==0 ){
+          psp->declargslot = &(psp->gp->stacksize);
+        }else if( strcmp(x,"start_symbol")==0 ){
+          psp->declargslot = &(psp->gp->start);
+        }else if( strcmp(x,"left")==0 ){
+          psp->preccounter++;
+          psp->declassoc = LEFT;
+          psp->state = WAITING_FOR_PRECEDENCE_SYMBOL;
+        }else if( strcmp(x,"right")==0 ){
+          psp->preccounter++;
+          psp->declassoc = RIGHT;
+          psp->state = WAITING_FOR_PRECEDENCE_SYMBOL;
+        }else if( strcmp(x,"nonassoc")==0 ){
+          psp->preccounter++;
+          psp->declassoc = NONE;
+          psp->state = WAITING_FOR_PRECEDENCE_SYMBOL;
+	}else if( strcmp(x,"destructor")==0 ){
+          psp->state = WAITING_FOR_DESTRUCTOR_SYMBOL;
+	}else if( strcmp(x,"type")==0 ){
+          psp->state = WAITING_FOR_DATATYPE_SYMBOL;
+        }else if( strcmp(x,"fallback")==0 ){
+          psp->fallback = 0;
+          psp->state = WAITING_FOR_FALLBACK_ID;
+        }else if( strcmp(x,"wildcard")==0 ){
+          psp->state = WAITING_FOR_WILDCARD_ID;
+        }else{
+          ErrorMsg(psp->filename,psp->tokenlineno,
+            "Unknown declaration keyword: \"%%%s\".",x);
+          psp->errorcnt++;
+          psp->state = RESYNC_AFTER_DECL_ERROR;
+	}
+      }else{
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "Illegal declaration keyword: \"%s\".",x);
+        psp->errorcnt++;
+        psp->state = RESYNC_AFTER_DECL_ERROR;
+      }
+      break;
+    case WAITING_FOR_DESTRUCTOR_SYMBOL:
+      if( !isalpha(x[0]) ){
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "Symbol name missing after %destructor keyword");
+        psp->errorcnt++;
+        psp->state = RESYNC_AFTER_DECL_ERROR;
+      }else{
+        struct symbol *sp = Symbol_new(x);
+        psp->declargslot = &sp->destructor;
+        psp->decllnslot = &sp->destructorln;
+        psp->state = WAITING_FOR_DECL_ARG;
+      }
+      break;
+    case WAITING_FOR_DATATYPE_SYMBOL:
+      if( !isalpha(x[0]) ){
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "Symbol name missing after %destructor keyword");
+        psp->errorcnt++;
+        psp->state = RESYNC_AFTER_DECL_ERROR;
+      }else{
+        struct symbol *sp = Symbol_new(x);
+        psp->declargslot = &sp->datatype;
+        psp->decllnslot = 0;
+        psp->state = WAITING_FOR_DECL_ARG;
+      }
+      break;
+    case WAITING_FOR_PRECEDENCE_SYMBOL:
+      if( x[0]=='.' ){
+        psp->state = WAITING_FOR_DECL_OR_RULE;
+      }else if( isupper(x[0]) ){
+        struct symbol *sp;
+        sp = Symbol_new(x);
+        if( sp->prec>=0 ){
+          ErrorMsg(psp->filename,psp->tokenlineno,
+            "Symbol \"%s\" has already be given a precedence.",x);
+          psp->errorcnt++;
+	}else{
+          sp->prec = psp->preccounter;
+          sp->assoc = psp->declassoc;
+	}
+      }else{
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "Can't assign a precedence to \"%s\".",x);
+        psp->errorcnt++;
+      }
+      break;
+    case WAITING_FOR_DECL_ARG:
+      if( (x[0]=='{' || x[0]=='\"' || isalnum(x[0])) ){
+        if( *(psp->declargslot)!=0 ){
+          ErrorMsg(psp->filename,psp->tokenlineno,
+            "The argument \"%s\" to declaration \"%%%s\" is not the first.",
+            x[0]=='\"' ? &x[1] : x,psp->declkeyword);
+          psp->errorcnt++;
+          psp->state = RESYNC_AFTER_DECL_ERROR;
+	}else{
+          *(psp->declargslot) = (x[0]=='\"' || x[0]=='{') ? &x[1] : x;
+          if( psp->decllnslot ) *psp->decllnslot = psp->tokenlineno;
+          psp->state = WAITING_FOR_DECL_OR_RULE;
+	}
+      }else{
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "Illegal argument to %%%s: %s",psp->declkeyword,x);
+        psp->errorcnt++;
+        psp->state = RESYNC_AFTER_DECL_ERROR;
+      }
+      break;
+    case WAITING_FOR_FALLBACK_ID:
+      if( x[0]=='.' ){
+        psp->state = WAITING_FOR_DECL_OR_RULE;
+      }else if( !isupper(x[0]) ){
+        ErrorMsg(psp->filename, psp->tokenlineno,
+          "%%fallback argument \"%s\" should be a token", x);
+        psp->errorcnt++;
+      }else{
+        struct symbol *sp = Symbol_new(x);
+        if( psp->fallback==0 ){
+          psp->fallback = sp;
+        }else if( sp->fallback ){
+          ErrorMsg(psp->filename, psp->tokenlineno,
+            "More than one fallback assigned to token %s", x);
+          psp->errorcnt++;
+        }else{
+          sp->fallback = psp->fallback;
+          psp->gp->has_fallback = 1;
+        }
+      }
+      break;
+    case WAITING_FOR_WILDCARD_ID:
+      if( x[0]=='.' ){
+        psp->state = WAITING_FOR_DECL_OR_RULE;
+      }else if( !isupper(x[0]) ){
+        ErrorMsg(psp->filename, psp->tokenlineno,
+          "%%wildcard argument \"%s\" should be a token", x);
+        psp->errorcnt++;
+      }else{
+        struct symbol *sp = Symbol_new(x);
+        if( psp->gp->wildcard==0 ){
+          psp->gp->wildcard = sp;
+        }else{
+          ErrorMsg(psp->filename, psp->tokenlineno,
+            "Extra wildcard to token: %s", x);
+          psp->errorcnt++;
+        }
+      }
+      break;
+    case RESYNC_AFTER_RULE_ERROR:
+/*      if( x[0]=='.' ) psp->state = WAITING_FOR_DECL_OR_RULE;
+**      break; */
+    case RESYNC_AFTER_DECL_ERROR:
+      if( x[0]=='.' ) psp->state = WAITING_FOR_DECL_OR_RULE;
+      if( x[0]=='%' ) psp->state = WAITING_FOR_DECL_KEYWORD;
+      break;
+  }
+}
+
+/* Run the proprocessor over the input file text.  The global variables
+** azDefine[0] through azDefine[nDefine-1] contains the names of all defined
+** macros.  This routine looks for "%ifdef" and "%ifndef" and "%endif" and
+** comments them out.  Text in between is also commented out as appropriate.
+*/
+static void preprocess_input(char *z){
+  int i, j, k, n;
+  int exclude = 0;
+  int start = 0;
+  int lineno = 1;
+  int start_lineno = 1;
+  for(i=0; z[i]; i++){
+    if( z[i]=='\n' ) lineno++;
+    if( z[i]!='%' || (i>0 && z[i-1]!='\n') ) continue;
+    if( strncmp(&z[i],"%endif",6)==0 && isspace(z[i+6]) ){
+      if( exclude ){
+        exclude--;
+        if( exclude==0 ){
+          for(j=start; j<i; j++) if( z[j]!='\n' ) z[j] = ' ';
+        }
+      }
+      for(j=i; z[j] && z[j]!='\n'; j++) z[j] = ' ';
+    }else if( (strncmp(&z[i],"%ifdef",6)==0 && isspace(z[i+6]))
+          || (strncmp(&z[i],"%ifndef",7)==0 && isspace(z[i+7])) ){
+      if( exclude ){
+        exclude++;
+      }else{
+        for(j=i+7; isspace(z[j]); j++){}
+        for(n=0; z[j+n] && !isspace(z[j+n]); n++){}
+        exclude = 1;
+        for(k=0; k<nDefine; k++){
+          if( strncmp(azDefine[k],&z[j],n)==0 && strlen(azDefine[k])==n ){
+            exclude = 0;
+            break;
+          }
+        }
+        if( z[i+3]=='n' ) exclude = !exclude;
+        if( exclude ){
+          start = i;
+          start_lineno = lineno;
+        }
+      }
+      for(j=i; z[j] && z[j]!='\n'; j++) z[j] = ' ';
+    }
+  }
+  if( exclude ){
+    fprintf(stderr,"unterminated %%ifdef starting on line %d\n", start_lineno);
+    exit(1);
+  }
+}
+
+/* In spite of its name, this function is really a scanner.  It read
+** in the entire input file (all at once) then tokenizes it.  Each
+** token is passed to the function "parseonetoken" which builds all
+** the appropriate data structures in the global state vector "gp".
+*/
+void Parse(gp)
+struct lemon *gp;
+{
+  struct pstate ps;
+  FILE *fp;
+  char *filebuf;
+  int filesize;
+  int lineno;
+  int c;
+  char *cp, *nextcp;
+  int startline = 0;
+
+  memset(&ps, '\0', sizeof(ps));
+  ps.gp = gp;
+  ps.filename = gp->filename;
+  ps.errorcnt = 0;
+  ps.state = INITIALIZE;
+
+  /* Begin by reading the input file */
+  fp = fopen(ps.filename,"rb");
+  if( fp==0 ){
+    ErrorMsg(ps.filename,0,"Can't open this file for reading.");
+    gp->errorcnt++;
+    return;
+  }
+  fseek(fp,0,2);
+  filesize = ftell(fp);
+  rewind(fp);
+  filebuf = (char *)malloc( filesize+1 );
+  if( filebuf==0 ){
+    ErrorMsg(ps.filename,0,"Can't allocate %d of memory to hold this file.",
+      filesize+1);
+    gp->errorcnt++;
+    return;
+  }
+  if( fread(filebuf,1,filesize,fp)!=filesize ){
+    ErrorMsg(ps.filename,0,"Can't read in all %d bytes of this file.",
+      filesize);
+    free(filebuf);
+    gp->errorcnt++;
+    return;
+  }
+  fclose(fp);
+  filebuf[filesize] = 0;
+
+  /* Make an initial pass through the file to handle %ifdef and %ifndef */
+  preprocess_input(filebuf);
+
+  /* Now scan the text of the input file */
+  lineno = 1;
+  for(cp=filebuf; (c= *cp)!=0; ){
+    if( c=='\n' ) lineno++;              /* Keep track of the line number */
+    if( isspace(c) ){ cp++; continue; }  /* Skip all white space */
+    if( c=='/' && cp[1]=='/' ){          /* Skip C++ style comments */
+      cp+=2;
+      while( (c= *cp)!=0 && c!='\n' ) cp++;
+      continue;
+    }
+    if( c=='/' && cp[1]=='*' ){          /* Skip C style comments */
+      cp+=2;
+      while( (c= *cp)!=0 && (c!='/' || cp[-1]!='*') ){
+        if( c=='\n' ) lineno++;
+        cp++;
+      }
+      if( c ) cp++;
+      continue;
+    }
+    ps.tokenstart = cp;                /* Mark the beginning of the token */
+    ps.tokenlineno = lineno;           /* Linenumber on which token begins */
+    if( c=='\"' ){                     /* String literals */
+      cp++;
+      while( (c= *cp)!=0 && c!='\"' ){
+        if( c=='\n' ) lineno++;
+        cp++;
+      }
+      if( c==0 ){
+        ErrorMsg(ps.filename,startline,
+"String starting on this line is not terminated before the end of the file.");
+        ps.errorcnt++;
+        nextcp = cp;
+      }else{
+        nextcp = cp+1;
+      }
+    }else if( c=='{' ){               /* A block of C code */
+      int level;
+      cp++;
+      for(level=1; (c= *cp)!=0 && (level>1 || c!='}'); cp++){
+        if( c=='\n' ) lineno++;
+        else if( c=='{' ) level++;
+        else if( c=='}' ) level--;
+        else if( c=='/' && cp[1]=='*' ){  /* Skip comments */
+          int prevc;
+          cp = &cp[2];
+          prevc = 0;
+          while( (c= *cp)!=0 && (c!='/' || prevc!='*') ){
+            if( c=='\n' ) lineno++;
+            prevc = c;
+            cp++;
+	  }
+	}else if( c=='/' && cp[1]=='/' ){  /* Skip C++ style comments too */
+          cp = &cp[2];
+          while( (c= *cp)!=0 && c!='\n' ) cp++;
+          if( c ) lineno++;
+	}else if( c=='\'' || c=='\"' ){    /* String a character literals */
+          int startchar, prevc;
+          startchar = c;
+          prevc = 0;
+          for(cp++; (c= *cp)!=0 && (c!=startchar || prevc=='\\'); cp++){
+            if( c=='\n' ) lineno++;
+            if( prevc=='\\' ) prevc = 0;
+            else              prevc = c;
+	  }
+	}
+      }
+      if( c==0 ){
+        ErrorMsg(ps.filename,ps.tokenlineno,
+"C code starting on this line is not terminated before the end of the file.");
+        ps.errorcnt++;
+        nextcp = cp;
+      }else{
+        nextcp = cp+1;
+      }
+    }else if( isalnum(c) ){          /* Identifiers */
+      while( (c= *cp)!=0 && (isalnum(c) || c=='_') ) cp++;
+      nextcp = cp;
+    }else if( c==':' && cp[1]==':' && cp[2]=='=' ){ /* The operator "::=" */
+      cp += 3;
+      nextcp = cp;
+    }else if( (c=='/' || c=='|') && isalpha(cp[1]) ){
+      cp += 2;
+      while( (c = *cp)!=0 && (isalnum(c) || c=='_') ) cp++;
+      nextcp = cp;
+    }else{                          /* All other (one character) operators */
+      cp++;
+      nextcp = cp;
+    }
+    c = *cp;
+    *cp = 0;                        /* Null terminate the token */
+    parseonetoken(&ps);             /* Parse the token */
+    *cp = c;                        /* Restore the buffer */
+    cp = nextcp;
+  }
+  free(filebuf);                    /* Release the buffer after parsing */
+  gp->rule = ps.firstrule;
+  gp->errorcnt = ps.errorcnt;
+}
+/*************************** From the file "plink.c" *********************/
+/*
+** Routines processing configuration follow-set propagation links
+** in the LEMON parser generator.
+*/
+static struct plink *plink_freelist = 0;
+
+/* Allocate a new plink */
+struct plink *Plink_new(){
+  struct plink *new;
+
+  if( plink_freelist==0 ){
+    int i;
+    int amt = 100;
+    plink_freelist = (struct plink *)calloc( amt, sizeof(struct plink) );
+    if( plink_freelist==0 ){
+      fprintf(stderr,
+      "Unable to allocate memory for a new follow-set propagation link.\n");
+      exit(1);
+    }
+    for(i=0; i<amt-1; i++) plink_freelist[i].next = &plink_freelist[i+1];
+    plink_freelist[amt-1].next = 0;
+  }
+  new = plink_freelist;
+  plink_freelist = plink_freelist->next;
+  return new;
+}
+
+/* Add a plink to a plink list */
+void Plink_add(plpp,cfp)
+struct plink **plpp;
+struct config *cfp;
+{
+  struct plink *new;
+  new = Plink_new();
+  new->next = *plpp;
+  *plpp = new;
+  new->cfp = cfp;
+}
+
+/* Transfer every plink on the list "from" to the list "to" */
+void Plink_copy(to,from)
+struct plink **to;
+struct plink *from;
+{
+  struct plink *nextpl;
+  while( from ){
+    nextpl = from->next;
+    from->next = *to;
+    *to = from;
+    from = nextpl;
+  }
+}
+
+/* Delete every plink on the list */
+void Plink_delete(plp)
+struct plink *plp;
+{
+  struct plink *nextpl;
+
+  while( plp ){
+    nextpl = plp->next;
+    plp->next = plink_freelist;
+    plink_freelist = plp;
+    plp = nextpl;
+  }
+}
+/*********************** From the file "report.c" **************************/
+/*
+** Procedures for generating reports and tables in the LEMON parser generator.
+*/
+
+/* Generate a filename with the given suffix.  Space to hold the
+** name comes from malloc() and must be freed by the calling
+** function.
+*/
+PRIVATE char *file_makename(lemp,suffix)
+struct lemon *lemp;
+char *suffix;
+{
+  char *name;
+  char *cp;
+
+  name = malloc( strlen(lemp->filename) + strlen(suffix) + 5 );
+  if( name==0 ){
+    fprintf(stderr,"Can't allocate space for a filename.\n");
+    exit(1);
+  }
+  strcpy(name,lemp->filename);
+  cp = strrchr(name,'.');
+  if( cp ) *cp = 0;
+  strcat(name,suffix);
+  return name;
+}
+
+/* Open a file with a name based on the name of the input file,
+** but with a different (specified) suffix, and return a pointer
+** to the stream */
+PRIVATE FILE *file_open(lemp,suffix,mode)
+struct lemon *lemp;
+char *suffix;
+char *mode;
+{
+  FILE *fp;
+
+  if( lemp->outname ) free(lemp->outname);
+  lemp->outname = file_makename(lemp, suffix);
+  /* LLVM LOCAL begin */
+#if 0
+  fp = fopen(lemp->outname,mode);
+#else
+  if(*mode == 'r') return NULL;
+  fp = stdout;
+#endif
+  /* LLVM LOCAL end */
+  if( fp==0 && *mode=='w' ){
+    fprintf(stderr,"Can't open file \"%s\".\n",lemp->outname);
+    lemp->errorcnt++;
+    return 0;
+  }
+  return fp;
+}
+
+/* Duplicate the input file without comments and without actions 
+** on rules */
+void Reprint(lemp)
+struct lemon *lemp;
+{
+  struct rule *rp;
+  struct symbol *sp;
+  int i, j, maxlen, len, ncolumns, skip;
+  printf("// Reprint of input file \"%s\".\n// Symbols:\n",lemp->filename);
+  maxlen = 10;
+  for(i=0; i<lemp->nsymbol; i++){
+    sp = lemp->symbols[i];
+    len = strlen(sp->name);
+    if( len>maxlen ) maxlen = len;
+  }
+  ncolumns = 76/(maxlen+5);
+  if( ncolumns<1 ) ncolumns = 1;
+  skip = (lemp->nsymbol + ncolumns - 1)/ncolumns;
+  for(i=0; i<skip; i++){
+    printf("//");
+    for(j=i; j<lemp->nsymbol; j+=skip){
+      sp = lemp->symbols[j];
+      assert( sp->index==j );
+      printf(" %3d %-*.*s",j,maxlen,maxlen,sp->name);
+    }
+    printf("\n");
+  }
+  for(rp=lemp->rule; rp; rp=rp->next){
+    printf("%s",rp->lhs->name);
+    /*    if( rp->lhsalias ) printf("(%s)",rp->lhsalias); */
+    printf(" ::=");
+    for(i=0; i<rp->nrhs; i++){
+      sp = rp->rhs[i];
+      printf(" %s", sp->name);
+      if( sp->type==MULTITERMINAL ){
+        for(j=1; j<sp->nsubsym; j++){
+          printf("|%s", sp->subsym[j]->name);
+        }
+      }
+      /* if( rp->rhsalias[i] ) printf("(%s)",rp->rhsalias[i]); */
+    }
+    printf(".");
+    if( rp->precsym ) printf(" [%s]",rp->precsym->name);
+    /* if( rp->code ) printf("\n    %s",rp->code); */
+    printf("\n");
+  }
+}
+
+void ConfigPrint(fp,cfp)
+FILE *fp;
+struct config *cfp;
+{
+  struct rule *rp;
+  struct symbol *sp;
+  int i, j;
+  rp = cfp->rp;
+  fprintf(fp,"%s ::=",rp->lhs->name);
+  for(i=0; i<=rp->nrhs; i++){
+    if( i==cfp->dot ) fprintf(fp," *");
+    if( i==rp->nrhs ) break;
+    sp = rp->rhs[i];
+    fprintf(fp," %s", sp->name);
+    if( sp->type==MULTITERMINAL ){
+      for(j=1; j<sp->nsubsym; j++){
+        fprintf(fp,"|%s",sp->subsym[j]->name);
+      }
+    }
+  }
+}
+
+/* #define TEST */
+#if 0
+/* Print a set */
+PRIVATE void SetPrint(out,set,lemp)
+FILE *out;
+char *set;
+struct lemon *lemp;
+{
+  int i;
+  char *spacer;
+  spacer = "";
+  fprintf(out,"%12s[","");
+  for(i=0; i<lemp->nterminal; i++){
+    if( SetFind(set,i) ){
+      fprintf(out,"%s%s",spacer,lemp->symbols[i]->name);
+      spacer = " ";
+    }
+  }
+  fprintf(out,"]\n");
+}
+
+/* Print a plink chain */
+PRIVATE void PlinkPrint(out,plp,tag)
+FILE *out;
+struct plink *plp;
+char *tag;
+{
+  while( plp ){
+    fprintf(out,"%12s%s (state %2d) ","",tag,plp->cfp->stp->statenum);
+    ConfigPrint(out,plp->cfp);
+    fprintf(out,"\n");
+    plp = plp->next;
+  }
+}
+#endif
+
+/* Print an action to the given file descriptor.  Return FALSE if
+** nothing was actually printed.
+*/
+int PrintAction(struct action *ap, FILE *fp, int indent){
+  int result = 1;
+  switch( ap->type ){
+    case SHIFT:
+      fprintf(fp,"%*s shift  %d",indent,ap->sp->name,ap->x.stp->statenum);
+      break;
+    case REDUCE:
+      fprintf(fp,"%*s reduce %d",indent,ap->sp->name,ap->x.rp->index);
+      break;
+    case ACCEPT:
+      fprintf(fp,"%*s accept",indent,ap->sp->name);
+      break;
+    case ERROR:
+      fprintf(fp,"%*s error",indent,ap->sp->name);
+      break;
+    case SRCONFLICT:
+    case RRCONFLICT:
+      fprintf(fp,"%*s reduce %-3d ** Parsing conflict **",
+        indent,ap->sp->name,ap->x.rp->index);
+      break;
+    case SSCONFLICT:
+      fprintf(fp,"%*s shift  %d ** Parsing conflict **", 
+        indent,ap->sp->name,ap->x.stp->statenum);
+      break;
+    case SH_RESOLVED:
+    case RD_RESOLVED:
+    case NOT_USED:
+      result = 0;
+      break;
+  }
+  return result;
+}
+
+/* Generate the "y.output" log file */
+void ReportOutput(lemp)
+struct lemon *lemp;
+{
+  int i;
+  struct state *stp;
+  struct config *cfp;
+  struct action *ap;
+  FILE *fp;
+
+  fp = file_open(lemp,".out","wb");
+  if( fp==0 ) return;
+  for(i=0; i<lemp->nstate; i++){
+    stp = lemp->sorted[i];
+    fprintf(fp,"State %d:\n",stp->statenum);
+    if( lemp->basisflag ) cfp=stp->bp;
+    else                  cfp=stp->cfp;
+    while( cfp ){
+      char buf[20];
+      if( cfp->dot==cfp->rp->nrhs ){
+        sprintf(buf,"(%d)",cfp->rp->index);
+        fprintf(fp,"    %5s ",buf);
+      }else{
+        fprintf(fp,"          ");
+      }
+      ConfigPrint(fp,cfp);
+      fprintf(fp,"\n");
+#if 0
+      SetPrint(fp,cfp->fws,lemp);
+      PlinkPrint(fp,cfp->fplp,"To  ");
+      PlinkPrint(fp,cfp->bplp,"From");
+#endif
+      if( lemp->basisflag ) cfp=cfp->bp;
+      else                  cfp=cfp->next;
+    }
+    fprintf(fp,"\n");
+    for(ap=stp->ap; ap; ap=ap->next){
+      if( PrintAction(ap,fp,30) ) fprintf(fp,"\n");
+    }
+    fprintf(fp,"\n");
+  }
+  fprintf(fp, "----------------------------------------------------\n");
+  fprintf(fp, "Symbols:\n");
+  for(i=0; i<lemp->nsymbol; i++){
+    int j;
+    struct symbol *sp;
+
+    sp = lemp->symbols[i];
+    fprintf(fp, "  %3d: %s", i, sp->name);
+    if( sp->type==NONTERMINAL ){
+      fprintf(fp, ":");
+      if( sp->lambda ){
+        fprintf(fp, " <lambda>");
+      }
+      for(j=0; j<lemp->nterminal; j++){
+        if( sp->firstset && SetFind(sp->firstset, j) ){
+          fprintf(fp, " %s", lemp->symbols[j]->name);
+        }
+      }
+    }
+    fprintf(fp, "\n");
+  }
+#if 0
+  fclose(fp);
+#endif
+  return;
+}
+
+/* Search for the file "name" which is in the same directory as
+** the exacutable */
+PRIVATE char *pathsearch(argv0,name,modemask)
+char *argv0;
+char *name;
+int modemask;
+{
+  char *pathlist;
+  char *path,*cp;
+  char c;
+
+#ifdef __WIN32__
+  cp = strrchr(argv0,'\\');
+#else
+  cp = strrchr(argv0,'/');
+#endif
+  if( cp ){
+    c = *cp;
+    *cp = 0;
+    path = (char *)malloc( strlen(argv0) + strlen(name) + 2 );
+    if( path ) sprintf(path,"%s/%s",argv0,name);
+    *cp = c;
+  }else{
+    extern char *getenv();
+    pathlist = getenv("PATH");
+    if( pathlist==0 ) pathlist = ".:/bin:/usr/bin";
+    path = (char *)malloc( strlen(pathlist)+strlen(name)+2 );
+    if( path!=0 ){
+      while( *pathlist ){
+        cp = strchr(pathlist,':');
+        if( cp==0 ) cp = &pathlist[strlen(pathlist)];
+        c = *cp;
+        *cp = 0;
+        sprintf(path,"%s/%s",pathlist,name);
+        *cp = c;
+        if( c==0 ) pathlist = "";
+        else pathlist = &cp[1];
+        if( access(path,modemask)==0 ) break;
+      }
+    }
+  }
+  return path;
+}
+
+/* Given an action, compute the integer value for that action
+** which is to be put in the action table of the generated machine.
+** Return negative if no action should be generated.
+*/
+PRIVATE int compute_action(lemp,ap)
+struct lemon *lemp;
+struct action *ap;
+{
+  int act;
+  switch( ap->type ){
+    case SHIFT:  act = ap->x.stp->statenum;            break;
+    case REDUCE: act = ap->x.rp->index + lemp->nstate; break;
+    case ERROR:  act = lemp->nstate + lemp->nrule;     break;
+    case ACCEPT: act = lemp->nstate + lemp->nrule + 1; break;
+    default:     act = -1; break;
+  }
+  return act;
+}
+
+#define LINESIZE 1000
+/* The next cluster of routines are for reading the template file
+** and writing the results to the generated parser */
+/* The first function transfers data from "in" to "out" until
+** a line is seen which begins with "%%".  The line number is
+** tracked.
+**
+** if name!=0, then any word that begin with "Parse" is changed to
+** begin with *name instead.
+*/
+PRIVATE void tplt_xfer(name,in,out,lineno)
+char *name;
+FILE *in;
+FILE *out;
+int *lineno;
+{
+  int i, iStart;
+  char line[LINESIZE];
+  while( fgets(line,LINESIZE,in) && (line[0]!='%' || line[1]!='%') ){
+    (*lineno)++;
+    iStart = 0;
+    if( name ){
+      for(i=0; line[i]; i++){
+        if( line[i]=='P' && strncmp(&line[i],"Parse",5)==0
+          && (i==0 || !isalpha(line[i-1]))
+        ){
+          if( i>iStart ) fprintf(out,"%.*s",i-iStart,&line[iStart]);
+          fprintf(out,"%s",name);
+          i += 4;
+          iStart = i+1;
+        }
+      }
+    }
+    fprintf(out,"%s",&line[iStart]);
+  }
+}
+
+/* The next function finds the template file and opens it, returning
+** a pointer to the opened file. */
+PRIVATE FILE *tplt_open(lemp)
+struct lemon *lemp;
+{
+  static char templatename[] = "lempar.c";
+  char buf[1000];
+  FILE *in;
+  char *tpltname;
+  char *cp;
+
+  cp = strrchr(lemp->filename,'.');
+  if( cp ){
+    sprintf(buf,"%.*s.lt",(int)(cp-lemp->filename),lemp->filename);
+  }else{
+    sprintf(buf,"%s.lt",lemp->filename);
+  }
+  if( access(buf,004)==0 ){
+    tpltname = buf;
+  }else if( access(templatename,004)==0 ){
+    tpltname = templatename;
+  }else{
+    tpltname = pathsearch(lemp->argv0,templatename,0);
+  }
+  if( tpltname==0 ){
+    fprintf(stderr,"Can't find the parser driver template file \"%s\".\n",
+    templatename);
+    lemp->errorcnt++;
+    return 0;
+  }
+  in = fopen(tpltname,"rb");
+  if( in==0 ){
+    fprintf(stderr,"Can't open the template file \"%s\".\n",templatename);
+    lemp->errorcnt++;
+    return 0;
+  }
+  return in;
+}
+
+/* Print a #line directive line to the output file. */
+PRIVATE void tplt_linedir(out,lineno,filename)
+FILE *out;
+int lineno;
+char *filename;
+{
+  fprintf(out,"#line %d \"",lineno);
+  while( *filename ){
+    if( *filename == '\\' ) putc('\\',out);
+    putc(*filename,out);
+    filename++;
+  }
+  fprintf(out,"\"\n");
+}
+
+/* Print a string to the file and keep the linenumber up to date */
+PRIVATE void tplt_print(out,lemp,str,strln,lineno)
+FILE *out;
+struct lemon *lemp;
+char *str;
+int strln;
+int *lineno;
+{
+  if( str==0 ) return;
+  tplt_linedir(out,strln,lemp->filename);
+  (*lineno)++;
+  while( *str ){
+    if( *str=='\n' ) (*lineno)++;
+    putc(*str,out);
+    str++;
+  }
+  if( str[-1]!='\n' ){
+    putc('\n',out);
+    (*lineno)++;
+  }
+  tplt_linedir(out,*lineno+2,lemp->outname); 
+  (*lineno)+=2;
+  return;
+}
+
+/*
+** The following routine emits code for the destructor for the
+** symbol sp
+*/
+void emit_destructor_code(out,sp,lemp,lineno)
+FILE *out;
+struct symbol *sp;
+struct lemon *lemp;
+int *lineno;
+{
+ char *cp = 0;
+
+ int linecnt = 0;
+ if( sp->type==TERMINAL ){
+   cp = lemp->tokendest;
+   if( cp==0 ) return;
+   tplt_linedir(out,lemp->tokendestln,lemp->filename);
+   fprintf(out,"{");
+ }else if( sp->destructor ){
+   cp = sp->destructor;
+   tplt_linedir(out,sp->destructorln,lemp->filename);
+   fprintf(out,"{");
+ }else if( lemp->vardest ){
+   cp = lemp->vardest;
+   if( cp==0 ) return;
+   tplt_linedir(out,lemp->vardestln,lemp->filename);
+   fprintf(out,"{");
+ }else{
+   assert( 0 );  /* Cannot happen */
+ }
+ for(; *cp; cp++){
+   if( *cp=='$' && cp[1]=='$' ){
+     fprintf(out,"(yypminor->yy%d)",sp->dtnum);
+     cp++;
+     continue;
+   }
+   if( *cp=='\n' ) linecnt++;
+   fputc(*cp,out);
+ }
+ (*lineno) += 3 + linecnt;
+ fprintf(out,"}\n");
+ tplt_linedir(out,*lineno,lemp->outname);
+ return;
+}
+
+/*
+** Return TRUE (non-zero) if the given symbol has a destructor.
+*/
+int has_destructor(sp, lemp)
+struct symbol *sp;
+struct lemon *lemp;
+{
+  int ret;
+  if( sp->type==TERMINAL ){
+    ret = lemp->tokendest!=0;
+  }else{
+    ret = lemp->vardest!=0 || sp->destructor!=0;
+  }
+  return ret;
+}
+
+/*
+** Append text to a dynamically allocated string.  If zText is 0 then
+** reset the string to be empty again.  Always return the complete text
+** of the string (which is overwritten with each call).
+**
+** n bytes of zText are stored.  If n==0 then all of zText up to the first
+** \000 terminator is stored.  zText can contain up to two instances of
+** %d.  The values of p1 and p2 are written into the first and second
+** %d.
+**
+** If n==-1, then the previous character is overwritten.
+*/
+PRIVATE char *append_str(char *zText, int n, int p1, int p2){
+  static char *z = 0;
+  static int alloced = 0;
+  static int used = 0;
+  int c;
+  char zInt[40];
+
+  if( zText==0 ){
+    used = 0;
+    return z;
+  }
+  if( n<=0 ){
+    if( n<0 ){
+      used += n;
+      assert( used>=0 );
+    }
+    n = strlen(zText);
+  }
+  if( n+sizeof(zInt)*2+used >= alloced ){
+    alloced = n + sizeof(zInt)*2 + used + 200;
+    z = realloc(z,  alloced);
+  }
+  if( z==0 ) return "";
+  while( n-- > 0 ){
+    c = *(zText++);
+    if( c=='%' && n>0 && zText[0]=='d' ){
+      sprintf(zInt, "%d", p1);
+      p1 = p2;
+      strcpy(&z[used], zInt);
+      used += strlen(&z[used]);
+      zText++;
+      n--;
+    }else{
+      z[used++] = c;
+    }
+  }
+  z[used] = 0;
+  return z;
+}
+
+/*
+** zCode is a string that is the action associated with a rule.  Expand
+** the symbols in this string so that the refer to elements of the parser
+** stack.
+*/
+PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){
+  char *cp, *xp;
+  int i;
+  char lhsused = 0;    /* True if the LHS element has been used */
+  char used[MAXRHS];   /* True for each RHS element which is used */
+
+  for(i=0; i<rp->nrhs; i++) used[i] = 0;
+  lhsused = 0;
+
+  if( rp->code==0 ){
+    rp->code = "\n";
+    rp->line = rp->ruleline;
+  }
+
+  append_str(0,0,0,0);
+  for(cp=rp->code; *cp; cp++){
+    if( isalpha(*cp) && (cp==rp->code || (!isalnum(cp[-1]) && cp[-1]!='_')) ){
+      char saved;
+      for(xp= &cp[1]; isalnum(*xp) || *xp=='_'; xp++);
+      saved = *xp;
+      *xp = 0;
+      if( rp->lhsalias && strcmp(cp,rp->lhsalias)==0 ){
+        append_str("yygotominor.yy%d",0,rp->lhs->dtnum,0);
+        cp = xp;
+        lhsused = 1;
+      }else{
+        for(i=0; i<rp->nrhs; i++){
+          if( rp->rhsalias[i] && strcmp(cp,rp->rhsalias[i])==0 ){
+            if( cp!=rp->code && cp[-1]=='@' ){
+              /* If the argument is of the form @X then substituted
+              ** the token number of X, not the value of X */
+              append_str("yymsp[%d].major",-1,i-rp->nrhs+1,0);
+            }else{
+              struct symbol *sp = rp->rhs[i];
+              int dtnum;
+              if( sp->type==MULTITERMINAL ){
+                dtnum = sp->subsym[0]->dtnum;
+              }else{
+                dtnum = sp->dtnum;
+              }
+              append_str("yymsp[%d].minor.yy%d",0,i-rp->nrhs+1, dtnum);
+            }
+            cp = xp;
+            used[i] = 1;
+            break;
+          }
+        }
+      }
+      *xp = saved;
+    }
+    append_str(cp, 1, 0, 0);
+  } /* End loop */
+
+  /* Check to make sure the LHS has been used */
+  if( rp->lhsalias && !lhsused ){
+    ErrorMsg(lemp->filename,rp->ruleline,
+      "Label \"%s\" for \"%s(%s)\" is never used.",
+        rp->lhsalias,rp->lhs->name,rp->lhsalias);
+    lemp->errorcnt++;
+  }
+
+  /* Generate destructor code for RHS symbols which are not used in the
+  ** reduce code */
+  for(i=0; i<rp->nrhs; i++){
+    if( rp->rhsalias[i] && !used[i] ){
+      ErrorMsg(lemp->filename,rp->ruleline,
+        "Label %s for \"%s(%s)\" is never used.",
+        rp->rhsalias[i],rp->rhs[i]->name,rp->rhsalias[i]);
+      lemp->errorcnt++;
+    }else if( rp->rhsalias[i]==0 ){
+      if( has_destructor(rp->rhs[i],lemp) ){
+        append_str("  yy_destructor(%d,&yymsp[%d].minor);\n", 0,
+           rp->rhs[i]->index,i-rp->nrhs+1);
+      }else{
+        /* No destructor defined for this term */
+      }
+    }
+  }
+  if( rp->code ){
+    cp = append_str(0,0,0,0);
+    rp->code = Strsafe(cp?cp:"");
+  }
+}
+
+/* 
+** Generate code which executes when the rule "rp" is reduced.  Write
+** the code to "out".  Make sure lineno stays up-to-date.
+*/
+PRIVATE void emit_code(out,rp,lemp,lineno)
+FILE *out;
+struct rule *rp;
+struct lemon *lemp;
+int *lineno;
+{
+ char *cp;
+ int linecnt = 0;
+
+ /* Generate code to do the reduce action */
+ if( rp->code ){
+   tplt_linedir(out,rp->line,lemp->filename);
+   fprintf(out,"{%s",rp->code);
+   for(cp=rp->code; *cp; cp++){
+     if( *cp=='\n' ) linecnt++;
+   } /* End loop */
+   (*lineno) += 3 + linecnt;
+   fprintf(out,"}\n");
+   tplt_linedir(out,*lineno,lemp->outname);
+ } /* End if( rp->code ) */
+
+ return;
+}
+
+/*
+** Print the definition of the union used for the parser's data stack.
+** This union contains fields for every possible data type for tokens
+** and nonterminals.  In the process of computing and printing this
+** union, also set the ".dtnum" field of every terminal and nonterminal
+** symbol.
+*/
+void print_stack_union(out,lemp,plineno,mhflag)
+FILE *out;                  /* The output stream */
+struct lemon *lemp;         /* The main info structure for this parser */
+int *plineno;               /* Pointer to the line number */
+int mhflag;                 /* True if generating makeheaders output */
+{
+  int lineno = *plineno;    /* The line number of the output */
+  char **types;             /* A hash table of datatypes */
+  int arraysize;            /* Size of the "types" array */
+  int maxdtlength;          /* Maximum length of any ".datatype" field. */
+  char *stddt;              /* Standardized name for a datatype */
+  int i,j;                  /* Loop counters */
+  int hash;                 /* For hashing the name of a type */
+  char *name;               /* Name of the parser */
+
+  /* Allocate and initialize types[] and allocate stddt[] */
+  arraysize = lemp->nsymbol * 2;
+  types = (char**)calloc( arraysize, sizeof(char*) );
+  for(i=0; i<arraysize; i++) types[i] = 0;
+  maxdtlength = 0;
+  if( lemp->vartype ){
+    maxdtlength = strlen(lemp->vartype);
+  }
+  for(i=0; i<lemp->nsymbol; i++){
+    int len;
+    struct symbol *sp = lemp->symbols[i];
+    if( sp->datatype==0 ) continue;
+    len = strlen(sp->datatype);
+    if( len>maxdtlength ) maxdtlength = len;
+  }
+  stddt = (char*)malloc( maxdtlength*2 + 1 );
+  if( types==0 || stddt==0 ){
+    fprintf(stderr,"Out of memory.\n");
+    exit(1);
+  }
+
+  /* Build a hash table of datatypes. The ".dtnum" field of each symbol
+  ** is filled in with the hash index plus 1.  A ".dtnum" value of 0 is
+  ** used for terminal symbols.  If there is no %default_type defined then
+  ** 0 is also used as the .dtnum value for nonterminals which do not specify
+  ** a datatype using the %type directive.
+  */
+  for(i=0; i<lemp->nsymbol; i++){
+    struct symbol *sp = lemp->symbols[i];
+    char *cp;
+    if( sp==lemp->errsym ){
+      sp->dtnum = arraysize+1;
+      continue;
+    }
+    if( sp->type!=NONTERMINAL || (sp->datatype==0 && lemp->vartype==0) ){
+      sp->dtnum = 0;
+      continue;
+    }
+    cp = sp->datatype;
+    if( cp==0 ) cp = lemp->vartype;
+    j = 0;
+    while( isspace(*cp) ) cp++;
+    while( *cp ) stddt[j++] = *cp++;
+    while( j>0 && isspace(stddt[j-1]) ) j--;
+    stddt[j] = 0;
+    hash = 0;
+    for(j=0; stddt[j]; j++){
+      hash = hash*53 + stddt[j];
+    }
+    hash = (hash & 0x7fffffff)%arraysize;
+    while( types[hash] ){
+      if( strcmp(types[hash],stddt)==0 ){
+        sp->dtnum = hash + 1;
+        break;
+      }
+      hash++;
+      if( hash>=arraysize ) hash = 0;
+    }
+    if( types[hash]==0 ){
+      sp->dtnum = hash + 1;
+      types[hash] = (char*)malloc( strlen(stddt)+1 );
+      if( types[hash]==0 ){
+        fprintf(stderr,"Out of memory.\n");
+        exit(1);
+      }
+      strcpy(types[hash],stddt);
+    }
+  }
+
+  /* Print out the definition of YYTOKENTYPE and YYMINORTYPE */
+  name = lemp->name ? lemp->name : "Parse";
+  lineno = *plineno;
+  if( mhflag ){ fprintf(out,"#if INTERFACE\n"); lineno++; }
+  fprintf(out,"#define %sTOKENTYPE %s\n",name,
+    lemp->tokentype?lemp->tokentype:"void*");  lineno++;
+  if( mhflag ){ fprintf(out,"#endif\n"); lineno++; }
+  fprintf(out,"typedef union {\n"); lineno++;
+  fprintf(out,"  %sTOKENTYPE yy0;\n",name); lineno++;
+  for(i=0; i<arraysize; i++){
+    if( types[i]==0 ) continue;
+    fprintf(out,"  %s yy%d;\n",types[i],i+1); lineno++;
+    free(types[i]);
+  }
+  if( lemp->errsym->useCnt ){
+    fprintf(out,"  int yy%d;\n",lemp->errsym->dtnum); lineno++;
+  }
+  free(stddt);
+  free(types);
+  fprintf(out,"} YYMINORTYPE;\n"); lineno++;
+  *plineno = lineno;
+}
+
+/*
+** Return the name of a C datatype able to represent values between
+** lwr and upr, inclusive.
+*/
+static const char *minimum_size_type(int lwr, int upr){
+  if( lwr>=0 ){
+    if( upr<=255 ){
+      return "unsigned char";
+    }else if( upr<65535 ){
+      return "unsigned short int";
+    }else{
+      return "unsigned int";
+    }
+  }else if( lwr>=-127 && upr<=127 ){
+    return "signed char";
+  }else if( lwr>=-32767 && upr<32767 ){
+    return "short";
+  }else{
+    return "int";
+  }
+}
+
+/*
+** Each state contains a set of token transaction and a set of
+** nonterminal transactions.  Each of these sets makes an instance
+** of the following structure.  An array of these structures is used
+** to order the creation of entries in the yy_action[] table.
+*/
+struct axset {
+  struct state *stp;   /* A pointer to a state */
+  int isTkn;           /* True to use tokens.  False for non-terminals */
+  int nAction;         /* Number of actions */
+};
+
+/*
+** Compare to axset structures for sorting purposes
+*/
+static int axset_compare(const void *a, const void *b){
+  struct axset *p1 = (struct axset*)a;
+  struct axset *p2 = (struct axset*)b;
+  return p2->nAction - p1->nAction;
+}
+
+/*
+** Write text on "out" that describes the rule "rp".
+*/
+static void writeRuleText(FILE *out, struct rule *rp){
+  int j;
+  fprintf(out,"%s ::=", rp->lhs->name);
+  for(j=0; j<rp->nrhs; j++){
+    struct symbol *sp = rp->rhs[j];
+    fprintf(out," %s", sp->name);
+    if( sp->type==MULTITERMINAL ){
+      int k;
+      for(k=1; k<sp->nsubsym; k++){
+        fprintf(out,"|%s",sp->subsym[k]->name);
+      }
+    }
+  }
+}
+
+
+/* Generate C source code for the parser */
+void ReportTable(lemp, mhflag)
+struct lemon *lemp;
+int mhflag;     /* Output in makeheaders format if true */
+{
+  FILE *out, *in;
+  char line[LINESIZE];
+  int  lineno;
+  struct state *stp;
+  struct action *ap;
+  struct rule *rp;
+  struct acttab *pActtab;
+  int i, j, n;
+  char *name;
+  int mnTknOfst, mxTknOfst;
+  int mnNtOfst, mxNtOfst;
+  struct axset *ax;
+
+  in = tplt_open(lemp);
+  if( in==0 ) return;
+  out = file_open(lemp,".c","wb");
+  if( out==0 ){
+    fclose(in);
+    return;
+  }
+  lineno = 1;
+  tplt_xfer(lemp->name,in,out,&lineno);
+
+  /* Generate the include code, if any */
+  tplt_print(out,lemp,lemp->include,lemp->includeln,&lineno);
+  if( mhflag ){
+    char *name = file_makename(lemp, ".h");
+    fprintf(out,"#include \"%s\"\n", name); lineno++;
+    free(name);
+  }
+  tplt_xfer(lemp->name,in,out,&lineno);
+
+  /* Generate #defines for all tokens */
+  if( mhflag ){
+    char *prefix;
+    fprintf(out,"#if INTERFACE\n"); lineno++;
+    if( lemp->tokenprefix ) prefix = lemp->tokenprefix;
+    else                    prefix = "";
+    for(i=1; i<lemp->nterminal; i++){
+      fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i);
+      lineno++;
+    }
+    fprintf(out,"#endif\n"); lineno++;
+  }
+  tplt_xfer(lemp->name,in,out,&lineno);
+
+  /* Generate the defines */
+  fprintf(out,"#define YYCODETYPE %s\n",
+    minimum_size_type(0, lemp->nsymbol+5)); lineno++;
+  fprintf(out,"#define YYNOCODE %d\n",lemp->nsymbol+1);  lineno++;
+  fprintf(out,"#define YYACTIONTYPE %s\n",
+    minimum_size_type(0, lemp->nstate+lemp->nrule+5));  lineno++;
+  if( lemp->wildcard ){
+    fprintf(out,"#define YYWILDCARD %d\n",
+       lemp->wildcard->index); lineno++;
+  }
+  print_stack_union(out,lemp,&lineno,mhflag);
+  fprintf(out, "#ifndef YYSTACKDEPTH\n"); lineno++;
+  if( lemp->stacksize ){
+    fprintf(out,"#define YYSTACKDEPTH %s\n",lemp->stacksize);  lineno++;
+  }else{
+    fprintf(out,"#define YYSTACKDEPTH 100\n");  lineno++;
+  }
+  fprintf(out, "#endif\n"); lineno++;
+  if( mhflag ){
+    fprintf(out,"#if INTERFACE\n"); lineno++;
+  }
+  name = lemp->name ? lemp->name : "Parse";
+  if( lemp->arg && lemp->arg[0] ){
+    int i;
+    i = strlen(lemp->arg);
+    while( i>=1 && isspace(lemp->arg[i-1]) ) i--;
+    while( i>=1 && (isalnum(lemp->arg[i-1]) || lemp->arg[i-1]=='_') ) i--;
+    fprintf(out,"#define %sARG_SDECL %s;\n",name,lemp->arg);  lineno++;
+    fprintf(out,"#define %sARG_PDECL ,%s\n",name,lemp->arg);  lineno++;
+    fprintf(out,"#define %sARG_FETCH %s = yypParser->%s\n",
+                 name,lemp->arg,&lemp->arg[i]);  lineno++;
+    fprintf(out,"#define %sARG_STORE yypParser->%s = %s\n",
+                 name,&lemp->arg[i],&lemp->arg[i]);  lineno++;
+  }else{
+    fprintf(out,"#define %sARG_SDECL\n",name);  lineno++;
+    fprintf(out,"#define %sARG_PDECL\n",name);  lineno++;
+    fprintf(out,"#define %sARG_FETCH\n",name); lineno++;
+    fprintf(out,"#define %sARG_STORE\n",name); lineno++;
+  }
+  if( mhflag ){
+    fprintf(out,"#endif\n"); lineno++;
+  }
+  fprintf(out,"#define YYNSTATE %d\n",lemp->nstate);  lineno++;
+  fprintf(out,"#define YYNRULE %d\n",lemp->nrule);  lineno++;
+  if( lemp->errsym->useCnt ){
+    fprintf(out,"#define YYERRORSYMBOL %d\n",lemp->errsym->index);  lineno++;
+    fprintf(out,"#define YYERRSYMDT yy%d\n",lemp->errsym->dtnum);  lineno++;
+  }
+  if( lemp->has_fallback ){
+    fprintf(out,"#define YYFALLBACK 1\n");  lineno++;
+  }
+  tplt_xfer(lemp->name,in,out,&lineno);
+
+  /* Generate the action table and its associates:
+  **
+  **  yy_action[]        A single table containing all actions.
+  **  yy_lookahead[]     A table containing the lookahead for each entry in
+  **                     yy_action.  Used to detect hash collisions.
+  **  yy_shift_ofst[]    For each state, the offset into yy_action for
+  **                     shifting terminals.
+  **  yy_reduce_ofst[]   For each state, the offset into yy_action for
+  **                     shifting non-terminals after a reduce.
+  **  yy_default[]       Default action for each state.
+  */
+
+  /* Compute the actions on all states and count them up */
+  ax = calloc(lemp->nstate*2, sizeof(ax[0]));
+  if( ax==0 ){
+    fprintf(stderr,"malloc failed\n");
+    exit(1);
+  }
+  for(i=0; i<lemp->nstate; i++){
+    stp = lemp->sorted[i];
+    ax[i*2].stp = stp;
+    ax[i*2].isTkn = 1;
+    ax[i*2].nAction = stp->nTknAct;
+    ax[i*2+1].stp = stp;
+    ax[i*2+1].isTkn = 0;
+    ax[i*2+1].nAction = stp->nNtAct;
+  }
+  mxTknOfst = mnTknOfst = 0;
+  mxNtOfst = mnNtOfst = 0;
+
+  /* Compute the action table.  In order to try to keep the size of the
+  ** action table to a minimum, the heuristic of placing the largest action
+  ** sets first is used.
+  */
+  qsort(ax, lemp->nstate*2, sizeof(ax[0]), axset_compare);
+  pActtab = acttab_alloc();
+  for(i=0; i<lemp->nstate*2 && ax[i].nAction>0; i++){
+    stp = ax[i].stp;
+    if( ax[i].isTkn ){
+      for(ap=stp->ap; ap; ap=ap->next){
+        int action;
+        if( ap->sp->index>=lemp->nterminal ) continue;
+        action = compute_action(lemp, ap);
+        if( action<0 ) continue;
+        acttab_action(pActtab, ap->sp->index, action);
+      }
+      stp->iTknOfst = acttab_insert(pActtab);
+      if( stp->iTknOfst<mnTknOfst ) mnTknOfst = stp->iTknOfst;
+      if( stp->iTknOfst>mxTknOfst ) mxTknOfst = stp->iTknOfst;
+    }else{
+      for(ap=stp->ap; ap; ap=ap->next){
+        int action;
+        if( ap->sp->index<lemp->nterminal ) continue;
+        if( ap->sp->index==lemp->nsymbol ) continue;
+        action = compute_action(lemp, ap);
+        if( action<0 ) continue;
+        acttab_action(pActtab, ap->sp->index, action);
+      }
+      stp->iNtOfst = acttab_insert(pActtab);
+      if( stp->iNtOfst<mnNtOfst ) mnNtOfst = stp->iNtOfst;
+      if( stp->iNtOfst>mxNtOfst ) mxNtOfst = stp->iNtOfst;
+    }
+  }
+  free(ax);
+
+  /* Output the yy_action table */
+  fprintf(out,"static const YYACTIONTYPE yy_action[] = {\n"); lineno++;
+  n = acttab_size(pActtab);
+  for(i=j=0; i<n; i++){
+    int action = acttab_yyaction(pActtab, i);
+    if( action<0 ) action = lemp->nstate + lemp->nrule + 2;
+    if( j==0 ) fprintf(out," /* %5d */ ", i);
+    fprintf(out, " %4d,", action);
+    if( j==9 || i==n-1 ){
+      fprintf(out, "\n"); lineno++;
+      j = 0;
+    }else{
+      j++;
+    }
+  }
+  fprintf(out, "};\n"); lineno++;
+
+  /* Output the yy_lookahead table */
+  fprintf(out,"static const YYCODETYPE yy_lookahead[] = {\n"); lineno++;
+  for(i=j=0; i<n; i++){
+    int la = acttab_yylookahead(pActtab, i);
+    if( la<0 ) la = lemp->nsymbol;
+    if( j==0 ) fprintf(out," /* %5d */ ", i);
+    fprintf(out, " %4d,", la);
+    if( j==9 || i==n-1 ){
+      fprintf(out, "\n"); lineno++;
+      j = 0;
+    }else{
+      j++;
+    }
+  }
+  fprintf(out, "};\n"); lineno++;
+
+  /* Output the yy_shift_ofst[] table */
+  fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", mnTknOfst-1); lineno++;
+  n = lemp->nstate;
+  while( n>0 && lemp->sorted[n-1]->iTknOfst==NO_OFFSET ) n--;
+  fprintf(out, "#define YY_SHIFT_MAX %d\n", n-1); lineno++;
+  fprintf(out, "static const %s yy_shift_ofst[] = {\n", 
+          minimum_size_type(mnTknOfst-1, mxTknOfst)); lineno++;
+  for(i=j=0; i<n; i++){
+    int ofst;
+    stp = lemp->sorted[i];
+    ofst = stp->iTknOfst;
+    if( ofst==NO_OFFSET ) ofst = mnTknOfst - 1;
+    if( j==0 ) fprintf(out," /* %5d */ ", i);
+    fprintf(out, " %4d,", ofst);
+    if( j==9 || i==n-1 ){
+      fprintf(out, "\n"); lineno++;
+      j = 0;
+    }else{
+      j++;
+    }
+  }
+  fprintf(out, "};\n"); lineno++;
+
+  /* Output the yy_reduce_ofst[] table */
+  fprintf(out, "#define YY_REDUCE_USE_DFLT (%d)\n", mnNtOfst-1); lineno++;
+  n = lemp->nstate;
+  while( n>0 && lemp->sorted[n-1]->iNtOfst==NO_OFFSET ) n--;
+  fprintf(out, "#define YY_REDUCE_MAX %d\n", n-1); lineno++;
+  fprintf(out, "static const %s yy_reduce_ofst[] = {\n", 
+          minimum_size_type(mnNtOfst-1, mxNtOfst)); lineno++;
+  for(i=j=0; i<n; i++){
+    int ofst;
+    stp = lemp->sorted[i];
+    ofst = stp->iNtOfst;
+    if( ofst==NO_OFFSET ) ofst = mnNtOfst - 1;
+    if( j==0 ) fprintf(out," /* %5d */ ", i);
+    fprintf(out, " %4d,", ofst);
+    if( j==9 || i==n-1 ){
+      fprintf(out, "\n"); lineno++;
+      j = 0;
+    }else{
+      j++;
+    }
+  }
+  fprintf(out, "};\n"); lineno++;
+
+  /* Output the default action table */
+  fprintf(out, "static const YYACTIONTYPE yy_default[] = {\n"); lineno++;
+  n = lemp->nstate;
+  for(i=j=0; i<n; i++){
+    stp = lemp->sorted[i];
+    if( j==0 ) fprintf(out," /* %5d */ ", i);
+    fprintf(out, " %4d,", stp->iDflt);
+    if( j==9 || i==n-1 ){
+      fprintf(out, "\n"); lineno++;
+      j = 0;
+    }else{
+      j++;
+    }
+  }
+  fprintf(out, "};\n"); lineno++;
+  tplt_xfer(lemp->name,in,out,&lineno);
+
+  /* Generate the table of fallback tokens.
+  */
+  if( lemp->has_fallback ){
+    for(i=0; i<lemp->nterminal; i++){
+      struct symbol *p = lemp->symbols[i];
+      if( p->fallback==0 ){
+        fprintf(out, "    0,  /* %10s => nothing */\n", p->name);
+      }else{
+        fprintf(out, "  %3d,  /* %10s => %s */\n", p->fallback->index,
+          p->name, p->fallback->name);
+      }
+      lineno++;
+    }
+  }
+  tplt_xfer(lemp->name, in, out, &lineno);
+
+  /* Generate a table containing the symbolic name of every symbol
+  */
+  for(i=0; i<lemp->nsymbol; i++){
+    sprintf(line,"\"%s\",",lemp->symbols[i]->name);
+    fprintf(out,"  %-15s",line);
+    if( (i&3)==3 ){ fprintf(out,"\n"); lineno++; }
+  }
+  if( (i&3)!=0 ){ fprintf(out,"\n"); lineno++; }
+  tplt_xfer(lemp->name,in,out,&lineno);
+
+  /* Generate a table containing a text string that describes every
+  ** rule in the rule set of the grammer.  This information is used
+  ** when tracing REDUCE actions.
+  */
+  for(i=0, rp=lemp->rule; rp; rp=rp->next, i++){
+    assert( rp->index==i );
+    fprintf(out," /* %3d */ \"", i);
+    writeRuleText(out, rp);
+    fprintf(out,"\",\n"); lineno++;
+  }
+  tplt_xfer(lemp->name,in,out,&lineno);
+
+  /* Generate code which executes every time a symbol is popped from
+  ** the stack while processing errors or while destroying the parser. 
+  ** (In other words, generate the %destructor actions)
+  */
+  if( lemp->tokendest ){
+    for(i=0; i<lemp->nsymbol; i++){
+      struct symbol *sp = lemp->symbols[i];
+      if( sp==0 || sp->type!=TERMINAL ) continue;
+      fprintf(out,"    case %d: /* %s */\n",
+              sp->index, sp->name); lineno++;
+    }
+    for(i=0; i<lemp->nsymbol && lemp->symbols[i]->type!=TERMINAL; i++);
+    if( i<lemp->nsymbol ){
+      emit_destructor_code(out,lemp->symbols[i],lemp,&lineno);
+      fprintf(out,"      break;\n"); lineno++;
+    }
+  }
+  if( lemp->vardest ){
+    struct symbol *dflt_sp = 0;
+    for(i=0; i<lemp->nsymbol; i++){
+      struct symbol *sp = lemp->symbols[i];
+      if( sp==0 || sp->type==TERMINAL ||
+          sp->index<=0 || sp->destructor!=0 ) continue;
+      fprintf(out,"    case %d: /* %s */\n",
+              sp->index, sp->name); lineno++;
+      dflt_sp = sp;
+    }
+    if( dflt_sp!=0 ){
+      emit_destructor_code(out,dflt_sp,lemp,&lineno);
+      fprintf(out,"      break;\n"); lineno++;
+    }
+  }
+  for(i=0; i<lemp->nsymbol; i++){
+    struct symbol *sp = lemp->symbols[i];
+    if( sp==0 || sp->type==TERMINAL || sp->destructor==0 ) continue;
+    fprintf(out,"    case %d: /* %s */\n",
+            sp->index, sp->name); lineno++;
+
+    /* Combine duplicate destructors into a single case */
+    for(j=i+1; j<lemp->nsymbol; j++){
+      struct symbol *sp2 = lemp->symbols[j];
+      if( sp2 && sp2->type!=TERMINAL && sp2->destructor
+          && sp2->dtnum==sp->dtnum
+          && strcmp(sp->destructor,sp2->destructor)==0 ){
+         fprintf(out,"    case %d: /* %s */\n",
+                 sp2->index, sp2->name); lineno++;
+         sp2->destructor = 0;
+      }
+    }
+
+    emit_destructor_code(out,lemp->symbols[i],lemp,&lineno);
+    fprintf(out,"      break;\n"); lineno++;
+  }
+  tplt_xfer(lemp->name,in,out,&lineno);
+
+  /* Generate code which executes whenever the parser stack overflows */
+  tplt_print(out,lemp,lemp->overflow,lemp->overflowln,&lineno);
+  tplt_xfer(lemp->name,in,out,&lineno);
+
+  /* Generate the table of rule information 
+  **
+  ** Note: This code depends on the fact that rules are number
+  ** sequentually beginning with 0.
+  */
+  for(rp=lemp->rule; rp; rp=rp->next){
+    fprintf(out,"  { %d, %d },\n",rp->lhs->index,rp->nrhs); lineno++;
+  }
+  tplt_xfer(lemp->name,in,out,&lineno);
+
+  /* Generate code which execution during each REDUCE action */
+  for(rp=lemp->rule; rp; rp=rp->next){
+    translate_code(lemp, rp);
+  }
+  for(rp=lemp->rule; rp; rp=rp->next){
+    struct rule *rp2;
+    if( rp->code==0 ) continue;
+    fprintf(out,"      case %d: /* ", rp->index);
+    writeRuleText(out, rp);
+    fprintf(out, " */\n"); lineno++;
+    for(rp2=rp->next; rp2; rp2=rp2->next){
+      if( rp2->code==rp->code ){
+        fprintf(out,"      case %d: /* ", rp2->index);
+        writeRuleText(out, rp2);
+        fprintf(out," */\n"); lineno++;
+        rp2->code = 0;
+      }
+    }
+    emit_code(out,rp,lemp,&lineno);
+    fprintf(out,"        break;\n"); lineno++;
+  }
+  tplt_xfer(lemp->name,in,out,&lineno);
+
+  /* Generate code which executes if a parse fails */
+  tplt_print(out,lemp,lemp->failure,lemp->failureln,&lineno);
+  tplt_xfer(lemp->name,in,out,&lineno);
+
+  /* Generate code which executes when a syntax error occurs */
+  tplt_print(out,lemp,lemp->error,lemp->errorln,&lineno);
+  tplt_xfer(lemp->name,in,out,&lineno);
+
+  /* Generate code which executes when the parser accepts its input */
+  tplt_print(out,lemp,lemp->accept,lemp->acceptln,&lineno);
+  tplt_xfer(lemp->name,in,out,&lineno);
+
+  /* Append any addition code the user desires */
+  tplt_print(out,lemp,lemp->extracode,lemp->extracodeln,&lineno);
+
+  fclose(in);
+#if 0  
+  fclose(out);
+#endif
+  return;
+}
+
+/* Generate a header file for the parser */
+void ReportHeader(lemp)
+struct lemon *lemp;
+{
+  FILE *out, *in;
+  char *prefix;
+  char line[LINESIZE];
+  char pattern[LINESIZE];
+  int i;
+
+  if( lemp->tokenprefix ) prefix = lemp->tokenprefix;
+  else                    prefix = "";
+  in = file_open(lemp,".h","rb");
+  if( in ){
+    for(i=1; i<lemp->nterminal && fgets(line,LINESIZE,in); i++){
+      sprintf(pattern,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i);
+      if( strcmp(line,pattern) ) break;
+    }
+    fclose(in);
+    if( i==lemp->nterminal ){
+      /* No change in the file.  Don't rewrite it. */
+      return;
+    }
+  }
+  out = file_open(lemp,".h","wb");
+  if( out ){
+    for(i=1; i<lemp->nterminal; i++){
+      fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i);
+    }
+#if 0
+    fclose(out);  
+#endif    
+  }
+  return;
+}
+
+/* Reduce the size of the action tables, if possible, by making use
+** of defaults.
+**
+** In this version, we take the most frequent REDUCE action and make
+** it the default.  Except, there is no default if the wildcard token
+** is a possible look-ahead.
+*/
+void CompressTables(lemp)
+struct lemon *lemp;
+{
+  struct state *stp;
+  struct action *ap, *ap2;
+  struct rule *rp, *rp2, *rbest;
+  int nbest, n;
+  int i;
+  int usesWildcard;
+
+  for(i=0; i<lemp->nstate; i++){
+    stp = lemp->sorted[i];
+    nbest = 0;
+    rbest = 0;
+    usesWildcard = 0;
+
+    for(ap=stp->ap; ap; ap=ap->next){
+      if( ap->type==SHIFT && ap->sp==lemp->wildcard ){
+        usesWildcard = 1;
+      }
+      if( ap->type!=REDUCE ) continue;
+      rp = ap->x.rp;
+      if( rp->lhsStart ) continue;
+      if( rp==rbest ) continue;
+      n = 1;
+      for(ap2=ap->next; ap2; ap2=ap2->next){
+        if( ap2->type!=REDUCE ) continue;
+        rp2 = ap2->x.rp;
+        if( rp2==rbest ) continue;
+        if( rp2==rp ) n++;
+      }
+      if( n>nbest ){
+        nbest = n;
+        rbest = rp;
+      }
+    }
+ 
+    /* Do not make a default if the number of rules to default
+    ** is not at least 1 or if the wildcard token is a possible
+    ** lookahead.
+    */
+    if( nbest<1 || usesWildcard ) continue;
+
+
+    /* Combine matching REDUCE actions into a single default */
+    for(ap=stp->ap; ap; ap=ap->next){
+      if( ap->type==REDUCE && ap->x.rp==rbest ) break;
+    }
+    assert( ap );
+    ap->sp = Symbol_new("{default}");
+    for(ap=ap->next; ap; ap=ap->next){
+      if( ap->type==REDUCE && ap->x.rp==rbest ) ap->type = NOT_USED;
+    }
+    stp->ap = Action_sort(stp->ap);
+  }
+}
+
+
+/*
+** Compare two states for sorting purposes.  The smaller state is the
+** one with the most non-terminal actions.  If they have the same number
+** of non-terminal actions, then the smaller is the one with the most
+** token actions.
+*/
+static int stateResortCompare(const void *a, const void *b){
+  const struct state *pA = *(const struct state**)a;
+  const struct state *pB = *(const struct state**)b;
+  int n;
+
+  n = pB->nNtAct - pA->nNtAct;
+  if( n==0 ){
+    n = pB->nTknAct - pA->nTknAct;
+  }
+  return n;
+}
+
+
+/*
+** Renumber and resort states so that states with fewer choices
+** occur at the end.  Except, keep state 0 as the first state.
+*/
+void ResortStates(lemp)
+struct lemon *lemp;
+{
+  int i;
+  struct state *stp;
+  struct action *ap;
+
+  for(i=0; i<lemp->nstate; i++){
+    stp = lemp->sorted[i];
+    stp->nTknAct = stp->nNtAct = 0;
+    stp->iDflt = lemp->nstate + lemp->nrule;
+    stp->iTknOfst = NO_OFFSET;
+    stp->iNtOfst = NO_OFFSET;
+    for(ap=stp->ap; ap; ap=ap->next){
+      if( compute_action(lemp,ap)>=0 ){
+        if( ap->sp->index<lemp->nterminal ){
+          stp->nTknAct++;
+        }else if( ap->sp->index<lemp->nsymbol ){
+          stp->nNtAct++;
+        }else{
+          stp->iDflt = compute_action(lemp, ap);
+        }
+      }
+    }
+  }
+  qsort(&lemp->sorted[1], lemp->nstate-1, sizeof(lemp->sorted[0]),
+        stateResortCompare);
+  for(i=0; i<lemp->nstate; i++){
+    lemp->sorted[i]->statenum = i;
+  }
+}
+
+
+/***************** From the file "set.c" ************************************/
+/*
+** Set manipulation routines for the LEMON parser generator.
+*/
+
+static int size = 0;
+
+/* Set the set size */
+void SetSize(n)
+int n;
+{
+  size = n+1;
+}
+
+/* Allocate a new set */
+char *SetNew(){
+  char *s;
+  s = (char*)calloc( size, 1);
+  if( s==0 ){
+    extern void memory_error();
+    memory_error();
+  }
+  return s;
+}
+
+/* Deallocate a set */
+void SetFree(s)
+char *s;
+{
+  free(s);
+}
+
+/* Add a new element to the set.  Return TRUE if the element was added
+** and FALSE if it was already there. */
+int SetAdd(s,e)
+char *s;
+int e;
+{
+  int rv;
+  assert( e>=0 && e<size );
+  rv = s[e];
+  s[e] = 1;
+  return !rv;
+}
+
+/* Add every element of s2 to s1.  Return TRUE if s1 changes. */
+int SetUnion(s1,s2)
+char *s1;
+char *s2;
+{
+  int i, progress;
+  progress = 0;
+  for(i=0; i<size; i++){
+    if( s2[i]==0 ) continue;
+    if( s1[i]==0 ){
+      progress = 1;
+      s1[i] = 1;
+    }
+  }
+  return progress;
+}
+/********************** From the file "table.c" ****************************/
+/*
+** All code in this file has been automatically generated
+** from a specification in the file
+**              "table.q"
+** by the associative array code building program "aagen".
+** Do not edit this file!  Instead, edit the specification
+** file, then rerun aagen.
+*/
+/*
+** Code for processing tables in the LEMON parser generator.
+*/
+
+PRIVATE int strhash(x)
+char *x;
+{
+  int h = 0;
+  while( *x) h = h*13 + *(x++);
+  return h;
+}
+
+/* Works like strdup, sort of.  Save a string in malloced memory, but
+** keep strings in a table so that the same string is not in more
+** than one place.
+*/
+char *Strsafe(y)
+char *y;
+{
+  char *z;
+
+  if( y==0 ) return 0;
+  z = Strsafe_find(y);
+  if( z==0 && (z=malloc( strlen(y)+1 ))!=0 ){
+    strcpy(z,y);
+    Strsafe_insert(z);
+  }
+  MemoryCheck(z);
+  return z;
+}
+
+/* There is one instance of the following structure for each
+** associative array of type "x1".
+*/
+struct s_x1 {
+  int size;               /* The number of available slots. */
+                          /*   Must be a power of 2 greater than or */
+                          /*   equal to 1 */
+  int count;              /* Number of currently slots filled */
+  struct s_x1node *tbl;  /* The data stored here */
+  struct s_x1node **ht;  /* Hash table for lookups */
+};
+
+/* There is one instance of this structure for every data element
+** in an associative array of type "x1".
+*/
+typedef struct s_x1node {
+  char *data;                  /* The data */
+  struct s_x1node *next;   /* Next entry with the same hash */
+  struct s_x1node **from;  /* Previous link */
+} x1node;
+
+/* There is only one instance of the array, which is the following */
+static struct s_x1 *x1a;
+
+/* Allocate a new associative array */
+void Strsafe_init(){
+  if( x1a ) return;
+  x1a = (struct s_x1*)malloc( sizeof(struct s_x1) );
+  if( x1a ){
+    x1a->size = 1024;
+    x1a->count = 0;
+    x1a->tbl = (x1node*)malloc( 
+      (sizeof(x1node) + sizeof(x1node*))*1024 );
+    if( x1a->tbl==0 ){
+      free(x1a);
+      x1a = 0;
+    }else{
+      int i;
+      x1a->ht = (x1node**)&(x1a->tbl[1024]);
+      for(i=0; i<1024; i++) x1a->ht[i] = 0;
+    }
+  }
+}
+/* Insert a new record into the array.  Return TRUE if successful.
+** Prior data with the same key is NOT overwritten */
+int Strsafe_insert(data)
+char *data;
+{
+  x1node *np;
+  int h;
+  int ph;
+
+  if( x1a==0 ) return 0;
+  ph = strhash(data);
+  h = ph & (x1a->size-1);
+  np = x1a->ht[h];
+  while( np ){
+    if( strcmp(np->data,data)==0 ){
+      /* An existing entry with the same key is found. */
+      /* Fail because overwrite is not allows. */
+      return 0;
+    }
+    np = np->next;
+  }
+  if( x1a->count>=x1a->size ){
+    /* Need to make the hash table bigger */
+    int i,size;
+    struct s_x1 array;
+    array.size = size = x1a->size*2;
+    array.count = x1a->count;
+    array.tbl = (x1node*)malloc(
+      (sizeof(x1node) + sizeof(x1node*))*size );
+    if( array.tbl==0 ) return 0;  /* Fail due to malloc failure */
+    array.ht = (x1node**)&(array.tbl[size]);
+    for(i=0; i<size; i++) array.ht[i] = 0;
+    for(i=0; i<x1a->count; i++){
+      x1node *oldnp, *newnp;
+      oldnp = &(x1a->tbl[i]);
+      h = strhash(oldnp->data) & (size-1);
+      newnp = &(array.tbl[i]);
+      if( array.ht[h] ) array.ht[h]->from = &(newnp->next);
+      newnp->next = array.ht[h];
+      newnp->data = oldnp->data;
+      newnp->from = &(array.ht[h]);
+      array.ht[h] = newnp;
+    }
+    free(x1a->tbl);
+    *x1a = array;
+  }
+  /* Insert the new data */
+  h = ph & (x1a->size-1);
+  np = &(x1a->tbl[x1a->count++]);
+  np->data = data;
+  if( x1a->ht[h] ) x1a->ht[h]->from = &(np->next);
+  np->next = x1a->ht[h];
+  x1a->ht[h] = np;
+  np->from = &(x1a->ht[h]);
+  return 1;
+}
+
+/* Return a pointer to data assigned to the given key.  Return NULL
+** if no such key. */
+char *Strsafe_find(key)
+char *key;
+{
+  int h;
+  x1node *np;
+
+  if( x1a==0 ) return 0;
+  h = strhash(key) & (x1a->size-1);
+  np = x1a->ht[h];
+  while( np ){
+    if( strcmp(np->data,key)==0 ) break;
+    np = np->next;
+  }
+  return np ? np->data : 0;
+}
+
+/* Return a pointer to the (terminal or nonterminal) symbol "x".
+** Create a new symbol if this is the first time "x" has been seen.
+*/
+struct symbol *Symbol_new(x)
+char *x;
+{
+  struct symbol *sp;
+
+  sp = Symbol_find(x);
+  if( sp==0 ){
+    sp = (struct symbol *)calloc(1, sizeof(struct symbol) );
+    MemoryCheck(sp);
+    sp->name = Strsafe(x);
+    sp->type = isupper(*x) ? TERMINAL : NONTERMINAL;
+    sp->rule = 0;
+    sp->fallback = 0;
+    sp->prec = -1;
+    sp->assoc = UNK;
+    sp->firstset = 0;
+    sp->lambda = LEMON_FALSE;
+    sp->destructor = 0;
+    sp->datatype = 0;
+    sp->useCnt = 0;
+    Symbol_insert(sp,sp->name);
+  }
+  sp->useCnt++;
+  return sp;
+}
+
+/* Compare two symbols for working purposes
+**
+** Symbols that begin with upper case letters (terminals or tokens)
+** must sort before symbols that begin with lower case letters
+** (non-terminals).  Other than that, the order does not matter.
+**
+** We find experimentally that leaving the symbols in their original
+** order (the order they appeared in the grammar file) gives the
+** smallest parser tables in SQLite.
+*/
+int Symbolcmpp(struct symbol **a, struct symbol **b){
+  int i1 = (**a).index + 10000000*((**a).name[0]>'Z');
+  int i2 = (**b).index + 10000000*((**b).name[0]>'Z');
+  return i1-i2;
+}
+
+/* There is one instance of the following structure for each
+** associative array of type "x2".
+*/
+struct s_x2 {
+  int size;               /* The number of available slots. */
+                          /*   Must be a power of 2 greater than or */
+                          /*   equal to 1 */
+  int count;              /* Number of currently slots filled */
+  struct s_x2node *tbl;  /* The data stored here */
+  struct s_x2node **ht;  /* Hash table for lookups */
+};
+
+/* There is one instance of this structure for every data element
+** in an associative array of type "x2".
+*/
+typedef struct s_x2node {
+  struct symbol *data;                  /* The data */
+  char *key;                   /* The key */
+  struct s_x2node *next;   /* Next entry with the same hash */
+  struct s_x2node **from;  /* Previous link */
+} x2node;
+
+/* There is only one instance of the array, which is the following */
+static struct s_x2 *x2a;
+
+/* Allocate a new associative array */
+void Symbol_init(){
+  if( x2a ) return;
+  x2a = (struct s_x2*)malloc( sizeof(struct s_x2) );
+  if( x2a ){
+    x2a->size = 128;
+    x2a->count = 0;
+    x2a->tbl = (x2node*)malloc( 
+      (sizeof(x2node) + sizeof(x2node*))*128 );
+    if( x2a->tbl==0 ){
+      free(x2a);
+      x2a = 0;
+    }else{
+      int i;
+      x2a->ht = (x2node**)&(x2a->tbl[128]);
+      for(i=0; i<128; i++) x2a->ht[i] = 0;
+    }
+  }
+}
+/* Insert a new record into the array.  Return TRUE if successful.
+** Prior data with the same key is NOT overwritten */
+int Symbol_insert(data,key)
+struct symbol *data;
+char *key;
+{
+  x2node *np;
+  int h;
+  int ph;
+
+  if( x2a==0 ) return 0;
+  ph = strhash(key);
+  h = ph & (x2a->size-1);
+  np = x2a->ht[h];
+  while( np ){
+    if( strcmp(np->key,key)==0 ){
+      /* An existing entry with the same key is found. */
+      /* Fail because overwrite is not allows. */
+      return 0;
+    }
+    np = np->next;
+  }
+  if( x2a->count>=x2a->size ){
+    /* Need to make the hash table bigger */
+    int i,size;
+    struct s_x2 array;
+    array.size = size = x2a->size*2;
+    array.count = x2a->count;
+    array.tbl = (x2node*)malloc(
+      (sizeof(x2node) + sizeof(x2node*))*size );
+    if( array.tbl==0 ) return 0;  /* Fail due to malloc failure */
+    array.ht = (x2node**)&(array.tbl[size]);
+    for(i=0; i<size; i++) array.ht[i] = 0;
+    for(i=0; i<x2a->count; i++){
+      x2node *oldnp, *newnp;
+      oldnp = &(x2a->tbl[i]);
+      h = strhash(oldnp->key) & (size-1);
+      newnp = &(array.tbl[i]);
+      if( array.ht[h] ) array.ht[h]->from = &(newnp->next);
+      newnp->next = array.ht[h];
+      newnp->key = oldnp->key;
+      newnp->data = oldnp->data;
+      newnp->from = &(array.ht[h]);
+      array.ht[h] = newnp;
+    }
+    free(x2a->tbl);
+    *x2a = array;
+  }
+  /* Insert the new data */
+  h = ph & (x2a->size-1);
+  np = &(x2a->tbl[x2a->count++]);
+  np->key = key;
+  np->data = data;
+  if( x2a->ht[h] ) x2a->ht[h]->from = &(np->next);
+  np->next = x2a->ht[h];
+  x2a->ht[h] = np;
+  np->from = &(x2a->ht[h]);
+  return 1;
+}
+
+/* Return a pointer to data assigned to the given key.  Return NULL
+** if no such key. */
+struct symbol *Symbol_find(key)
+char *key;
+{
+  int h;
+  x2node *np;
+
+  if( x2a==0 ) return 0;
+  h = strhash(key) & (x2a->size-1);
+  np = x2a->ht[h];
+  while( np ){
+    if( strcmp(np->key,key)==0 ) break;
+    np = np->next;
+  }
+  return np ? np->data : 0;
+}
+
+/* Return the n-th data.  Return NULL if n is out of range. */
+struct symbol *Symbol_Nth(n)
+int n;
+{
+  struct symbol *data;
+  if( x2a && n>0 && n<=x2a->count ){
+    data = x2a->tbl[n-1].data;
+  }else{
+    data = 0;
+  }
+  return data;
+}
+
+/* Return the size of the array */
+int Symbol_count()
+{
+  return x2a ? x2a->count : 0;
+}
+
+/* Return an array of pointers to all data in the table.
+** The array is obtained from malloc.  Return NULL if memory allocation
+** problems, or if the array is empty. */
+struct symbol **Symbol_arrayof()
+{
+  struct symbol **array;
+  int i,size;
+  if( x2a==0 ) return 0;
+  size = x2a->count;
+  array = (struct symbol **)calloc(size, sizeof(struct symbol *));
+  if( array ){
+    for(i=0; i<size; i++) array[i] = x2a->tbl[i].data;
+  }
+  return array;
+}
+
+/* Compare two configurations */
+int Configcmp(a,b)
+struct config *a;
+struct config *b;
+{
+  int x;
+  x = a->rp->index - b->rp->index;
+  if( x==0 ) x = a->dot - b->dot;
+  return x;
+}
+
+/* Compare two states */
+PRIVATE int statecmp(a,b)
+struct config *a;
+struct config *b;
+{
+  int rc;
+  for(rc=0; rc==0 && a && b;  a=a->bp, b=b->bp){
+    rc = a->rp->index - b->rp->index;
+    if( rc==0 ) rc = a->dot - b->dot;
+  }
+  if( rc==0 ){
+    if( a ) rc = 1;
+    if( b ) rc = -1;
+  }
+  return rc;
+}
+
+/* Hash a state */
+PRIVATE int statehash(a)
+struct config *a;
+{
+  int h=0;
+  while( a ){
+    h = h*571 + a->rp->index*37 + a->dot;
+    a = a->bp;
+  }
+  return h;
+}
+
+/* Allocate a new state structure */
+struct state *State_new()
+{
+  struct state *new;
+  new = (struct state *)calloc(1, sizeof(struct state) );
+  MemoryCheck(new);
+  return new;
+}
+
+/* There is one instance of the following structure for each
+** associative array of type "x3".
+*/
+struct s_x3 {
+  int size;               /* The number of available slots. */
+                          /*   Must be a power of 2 greater than or */
+                          /*   equal to 1 */
+  int count;              /* Number of currently slots filled */
+  struct s_x3node *tbl;  /* The data stored here */
+  struct s_x3node **ht;  /* Hash table for lookups */
+};
+
+/* There is one instance of this structure for every data element
+** in an associative array of type "x3".
+*/
+typedef struct s_x3node {
+  struct state *data;                  /* The data */
+  struct config *key;                   /* The key */
+  struct s_x3node *next;   /* Next entry with the same hash */
+  struct s_x3node **from;  /* Previous link */
+} x3node;
+
+/* There is only one instance of the array, which is the following */
+static struct s_x3 *x3a;
+
+/* Allocate a new associative array */
+void State_init(){
+  if( x3a ) return;
+  x3a = (struct s_x3*)malloc( sizeof(struct s_x3) );
+  if( x3a ){
+    x3a->size = 128;
+    x3a->count = 0;
+    x3a->tbl = (x3node*)malloc( 
+      (sizeof(x3node) + sizeof(x3node*))*128 );
+    if( x3a->tbl==0 ){
+      free(x3a);
+      x3a = 0;
+    }else{
+      int i;
+      x3a->ht = (x3node**)&(x3a->tbl[128]);
+      for(i=0; i<128; i++) x3a->ht[i] = 0;
+    }
+  }
+}
+/* Insert a new record into the array.  Return TRUE if successful.
+** Prior data with the same key is NOT overwritten */
+int State_insert(data,key)
+struct state *data;
+struct config *key;
+{
+  x3node *np;
+  int h;
+  int ph;
+
+  if( x3a==0 ) return 0;
+  ph = statehash(key);
+  h = ph & (x3a->size-1);
+  np = x3a->ht[h];
+  while( np ){
+    if( statecmp(np->key,key)==0 ){
+      /* An existing entry with the same key is found. */
+      /* Fail because overwrite is not allows. */
+      return 0;
+    }
+    np = np->next;
+  }
+  if( x3a->count>=x3a->size ){
+    /* Need to make the hash table bigger */
+    int i,size;
+    struct s_x3 array;
+    array.size = size = x3a->size*2;
+    array.count = x3a->count;
+    array.tbl = (x3node*)malloc(
+      (sizeof(x3node) + sizeof(x3node*))*size );
+    if( array.tbl==0 ) return 0;  /* Fail due to malloc failure */
+    array.ht = (x3node**)&(array.tbl[size]);
+    for(i=0; i<size; i++) array.ht[i] = 0;
+    for(i=0; i<x3a->count; i++){
+      x3node *oldnp, *newnp;
+      oldnp = &(x3a->tbl[i]);
+      h = statehash(oldnp->key) & (size-1);
+      newnp = &(array.tbl[i]);
+      if( array.ht[h] ) array.ht[h]->from = &(newnp->next);
+      newnp->next = array.ht[h];
+      newnp->key = oldnp->key;
+      newnp->data = oldnp->data;
+      newnp->from = &(array.ht[h]);
+      array.ht[h] = newnp;
+    }
+    free(x3a->tbl);
+    *x3a = array;
+  }
+  /* Insert the new data */
+  h = ph & (x3a->size-1);
+  np = &(x3a->tbl[x3a->count++]);
+  np->key = key;
+  np->data = data;
+  if( x3a->ht[h] ) x3a->ht[h]->from = &(np->next);
+  np->next = x3a->ht[h];
+  x3a->ht[h] = np;
+  np->from = &(x3a->ht[h]);
+  return 1;
+}
+
+/* Return a pointer to data assigned to the given key.  Return NULL
+** if no such key. */
+struct state *State_find(key)
+struct config *key;
+{
+  int h;
+  x3node *np;
+
+  if( x3a==0 ) return 0;
+  h = statehash(key) & (x3a->size-1);
+  np = x3a->ht[h];
+  while( np ){
+    if( statecmp(np->key,key)==0 ) break;
+    np = np->next;
+  }
+  return np ? np->data : 0;
+}
+
+/* Return an array of pointers to all data in the table.
+** The array is obtained from malloc.  Return NULL if memory allocation
+** problems, or if the array is empty. */
+struct state **State_arrayof()
+{
+  struct state **array;
+  int i,size;
+  if( x3a==0 ) return 0;
+  size = x3a->count;
+  array = (struct state **)malloc( sizeof(struct state *)*size );
+  if( array ){
+    for(i=0; i<size; i++) array[i] = x3a->tbl[i].data;
+  }
+  return array;
+}
+
+/* Hash a configuration */
+PRIVATE int confighash(a)
+struct config *a;
+{
+  int h=0;
+  h = h*571 + a->rp->index*37 + a->dot;
+  return h;
+}
+
+/* There is one instance of the following structure for each
+** associative array of type "x4".
+*/
+struct s_x4 {
+  int size;               /* The number of available slots. */
+                          /*   Must be a power of 2 greater than or */
+                          /*   equal to 1 */
+  int count;              /* Number of currently slots filled */
+  struct s_x4node *tbl;  /* The data stored here */
+  struct s_x4node **ht;  /* Hash table for lookups */
+};
+
+/* There is one instance of this structure for every data element
+** in an associative array of type "x4".
+*/
+typedef struct s_x4node {
+  struct config *data;                  /* The data */
+  struct s_x4node *next;   /* Next entry with the same hash */
+  struct s_x4node **from;  /* Previous link */
+} x4node;
+
+/* There is only one instance of the array, which is the following */
+static struct s_x4 *x4a;
+
+/* Allocate a new associative array */
+void Configtable_init(){
+  if( x4a ) return;
+  x4a = (struct s_x4*)malloc( sizeof(struct s_x4) );
+  if( x4a ){
+    x4a->size = 64;
+    x4a->count = 0;
+    x4a->tbl = (x4node*)malloc( 
+      (sizeof(x4node) + sizeof(x4node*))*64 );
+    if( x4a->tbl==0 ){
+      free(x4a);
+      x4a = 0;
+    }else{
+      int i;
+      x4a->ht = (x4node**)&(x4a->tbl[64]);
+      for(i=0; i<64; i++) x4a->ht[i] = 0;
+    }
+  }
+}
+/* Insert a new record into the array.  Return TRUE if successful.
+** Prior data with the same key is NOT overwritten */
+int Configtable_insert(data)
+struct config *data;
+{
+  x4node *np;
+  int h;
+  int ph;
+
+  if( x4a==0 ) return 0;
+  ph = confighash(data);
+  h = ph & (x4a->size-1);
+  np = x4a->ht[h];
+  while( np ){
+    if( Configcmp(np->data,data)==0 ){
+      /* An existing entry with the same key is found. */
+      /* Fail because overwrite is not allows. */
+      return 0;
+    }
+    np = np->next;
+  }
+  if( x4a->count>=x4a->size ){
+    /* Need to make the hash table bigger */
+    int i,size;
+    struct s_x4 array;
+    array.size = size = x4a->size*2;
+    array.count = x4a->count;
+    array.tbl = (x4node*)malloc(
+      (sizeof(x4node) + sizeof(x4node*))*size );
+    if( array.tbl==0 ) return 0;  /* Fail due to malloc failure */
+    array.ht = (x4node**)&(array.tbl[size]);
+    for(i=0; i<size; i++) array.ht[i] = 0;
+    for(i=0; i<x4a->count; i++){
+      x4node *oldnp, *newnp;
+      oldnp = &(x4a->tbl[i]);
+      h = confighash(oldnp->data) & (size-1);
+      newnp = &(array.tbl[i]);
+      if( array.ht[h] ) array.ht[h]->from = &(newnp->next);
+      newnp->next = array.ht[h];
+      newnp->data = oldnp->data;
+      newnp->from = &(array.ht[h]);
+      array.ht[h] = newnp;
+    }
+    free(x4a->tbl);
+    *x4a = array;
+  }
+  /* Insert the new data */
+  h = ph & (x4a->size-1);
+  np = &(x4a->tbl[x4a->count++]);
+  np->data = data;
+  if( x4a->ht[h] ) x4a->ht[h]->from = &(np->next);
+  np->next = x4a->ht[h];
+  x4a->ht[h] = np;
+  np->from = &(x4a->ht[h]);
+  return 1;
+}
+
+/* Return a pointer to data assigned to the given key.  Return NULL
+** if no such key. */
+struct config *Configtable_find(key)
+struct config *key;
+{
+  int h;
+  x4node *np;
+
+  if( x4a==0 ) return 0;
+  h = confighash(key) & (x4a->size-1);
+  np = x4a->ht[h];
+  while( np ){
+    if( Configcmp(np->data,key)==0 ) break;
+    np = np->next;
+  }
+  return np ? np->data : 0;
+}
+
+/* Remove all data from the table.  Pass each data to the function "f"
+** as it is removed.  ("f" may be null to avoid this step.) */
+void Configtable_clear(f)
+int(*f)(/* struct config * */);
+{
+  int i;
+  if( x4a==0 || x4a->count==0 ) return;
+  if( f ) for(i=0; i<x4a->count; i++) (*f)(x4a->tbl[i].data);
+  for(i=0; i<x4a->size; i++) x4a->ht[i] = 0;
+  x4a->count = 0;
+  return;
+}
+
+/* LLVM LOCAL begin */
+
+#include <unistd.h>
+#include <sys/wait.h>
+#include <errno.h>
+/* llvm-test supports only running program once,
+ * we need to run it multiple times, because it only accepts
+ * one input a time, and has a global state */
+int main(int argc, char **argv)
+{
+	int j,i = 0;
+	for(j=0;j<20;j++) {
+		/* test finishes too fast, run more times to get
+		 * meaningful timings */
+		for(i=1;i<argc;i++) {
+			int status;
+			pid_t p = fork();
+			if(p == 0) {
+				char *argv_child[] = {"lemon-child","-s",argv[i],NULL};
+				/* child */
+				fprintf(stdout,"Processing %s\n",argv[i]);
+				exit( lemon_main(3, argv_child) );
+			}
+			while(wait(&status) == -1 && errno == EINTR) {}
+			if(status) {
+				fprintf(stderr,"Error while running on: %s\n",argv[i]);
+			}
+		}
+	}
+	return 0;
+}
+
+/* LLVM LOCAL end */

Added: test-suite/trunk/MultiSource/Applications/lemon/lempar.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/lemon/lempar.c?rev=48828&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/lemon/lempar.c (added)
+++ test-suite/trunk/MultiSource/Applications/lemon/lempar.c Wed Mar 26 12:03:57 2008
@@ -0,0 +1,769 @@
+/* Driver template for the LEMON parser generator.
+** The author disclaims copyright to this source code.
+*/
+/* First off, code is include which follows the "include" declaration
+** in the input file. */
+#include <stdio.h>
+%%
+/* Next is all token values, in a form suitable for use by makeheaders.
+** This section will be null unless lemon is run with the -m switch.
+*/
+/* 
+** These constants (all generated automatically by the parser generator)
+** specify the various kinds of tokens (terminals) that the parser
+** understands. 
+**
+** Each symbol here is a terminal symbol in the grammar.
+*/
+%%
+/* Make sure the INTERFACE macro is defined.
+*/
+#ifndef INTERFACE
+# define INTERFACE 1
+#endif
+/* The next thing included is series of defines which control
+** various aspects of the generated parser.
+**    YYCODETYPE         is the data type used for storing terminal
+**                       and nonterminal numbers.  "unsigned char" is
+**                       used if there are fewer than 250 terminals
+**                       and nonterminals.  "int" is used otherwise.
+**    YYNOCODE           is a number of type YYCODETYPE which corresponds
+**                       to no legal terminal or nonterminal number.  This
+**                       number is used to fill in empty slots of the hash 
+**                       table.
+**    YYFALLBACK         If defined, this indicates that one or more tokens
+**                       have fall-back values which should be used if the
+**                       original value of the token will not parse.
+**    YYACTIONTYPE       is the data type used for storing terminal
+**                       and nonterminal numbers.  "unsigned char" is
+**                       used if there are fewer than 250 rules and
+**                       states combined.  "int" is used otherwise.
+**    ParseTOKENTYPE     is the data type used for minor tokens given 
+**                       directly to the parser from the tokenizer.
+**    YYMINORTYPE        is the data type used for all minor tokens.
+**                       This is typically a union of many types, one of
+**                       which is ParseTOKENTYPE.  The entry in the union
+**                       for base tokens is called "yy0".
+**    YYSTACKDEPTH       is the maximum depth of the parser's stack.  If
+**                       zero the stack is dynamically sized using realloc()
+**    ParseARG_SDECL     A static variable declaration for the %extra_argument
+**    ParseARG_PDECL     A parameter declaration for the %extra_argument
+**    ParseARG_STORE     Code to store %extra_argument into yypParser
+**    ParseARG_FETCH     Code to extract %extra_argument from yypParser
+**    YYNSTATE           the combined number of states.
+**    YYNRULE            the number of rules in the grammar
+**    YYERRORSYMBOL      is the code number of the error symbol.  If not
+**                       defined, then do no error processing.
+*/
+%%
+#define YY_NO_ACTION      (YYNSTATE+YYNRULE+2)
+#define YY_ACCEPT_ACTION  (YYNSTATE+YYNRULE+1)
+#define YY_ERROR_ACTION   (YYNSTATE+YYNRULE)
+
+/* Next are that tables used to determine what action to take based on the
+** current state and lookahead token.  These tables are used to implement
+** functions that take a state number and lookahead value and return an
+** action integer.  
+**
+** Suppose the action integer is N.  Then the action is determined as
+** follows
+**
+**   0 <= N < YYNSTATE                  Shift N.  That is, push the lookahead
+**                                      token onto the stack and goto state N.
+**
+**   YYNSTATE <= N < YYNSTATE+YYNRULE   Reduce by rule N-YYNSTATE.
+**
+**   N == YYNSTATE+YYNRULE              A syntax error has occurred.
+**
+**   N == YYNSTATE+YYNRULE+1            The parser accepts its input.
+**
+**   N == YYNSTATE+YYNRULE+2            No such action.  Denotes unused
+**                                      slots in the yy_action[] table.
+**
+** The action table is constructed as a single large table named yy_action[].
+** Given state S and lookahead X, the action is computed as
+**
+**      yy_action[ yy_shift_ofst[S] + X ]
+**
+** If the index value yy_shift_ofst[S]+X is out of range or if the value
+** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
+** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
+** and that yy_default[S] should be used instead.  
+**
+** The formula above is for computing the action when the lookahead is
+** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
+** a reduce action) then the yy_reduce_ofst[] array is used in place of
+** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
+** YY_SHIFT_USE_DFLT.
+**
+** The following are the tables generated in this section:
+**
+**  yy_action[]        A single table containing all actions.
+**  yy_lookahead[]     A table containing the lookahead for each entry in
+**                     yy_action.  Used to detect hash collisions.
+**  yy_shift_ofst[]    For each state, the offset into yy_action for
+**                     shifting terminals.
+**  yy_reduce_ofst[]   For each state, the offset into yy_action for
+**                     shifting non-terminals after a reduce.
+**  yy_default[]       Default action for each state.
+*/
+%%
+#define YY_SZ_ACTTAB (int)(sizeof(yy_action)/sizeof(yy_action[0]))
+
+/* The next table maps tokens into fallback tokens.  If a construct
+** like the following:
+** 
+**      %fallback ID X Y Z.
+**
+** appears in the grammer, then ID becomes a fallback token for X, Y,
+** and Z.  Whenever one of the tokens X, Y, or Z is input to the parser
+** but it does not parse, the type of the token is changed to ID and
+** the parse is retried before an error is thrown.
+*/
+#ifdef YYFALLBACK
+static const YYCODETYPE yyFallback[] = {
+%%
+};
+#endif /* YYFALLBACK */
+
+/* The following structure represents a single element of the
+** parser's stack.  Information stored includes:
+**
+**   +  The state number for the parser at this level of the stack.
+**
+**   +  The value of the token stored at this level of the stack.
+**      (In other words, the "major" token.)
+**
+**   +  The semantic value stored at this level of the stack.  This is
+**      the information used by the action routines in the grammar.
+**      It is sometimes called the "minor" token.
+*/
+struct yyStackEntry {
+  int stateno;       /* The state-number */
+  int major;         /* The major token value.  This is the code
+                     ** number for the token at this stack level */
+  YYMINORTYPE minor; /* The user-supplied minor token value.  This
+                     ** is the value of the token  */
+};
+typedef struct yyStackEntry yyStackEntry;
+
+/* The state of the parser is completely contained in an instance of
+** the following structure */
+struct yyParser {
+  int yyidx;                    /* Index of top element in stack */
+  int yyerrcnt;                 /* Shifts left before out of the error */
+  ParseARG_SDECL                /* A place to hold %extra_argument */
+#if YYSTACKDEPTH<=0
+  int yystksz;                  /* Current side of the stack */
+  yyStackEntry *yystack;        /* The parser's stack */
+#else
+  yyStackEntry yystack[YYSTACKDEPTH];  /* The parser's stack */
+#endif
+};
+typedef struct yyParser yyParser;
+
+#ifndef NDEBUG
+#include <stdio.h>
+static FILE *yyTraceFILE = 0;
+static char *yyTracePrompt = 0;
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/* 
+** Turn parser tracing on by giving a stream to which to write the trace
+** and a prompt to preface each trace message.  Tracing is turned off
+** by making either argument NULL 
+**
+** Inputs:
+** <ul>
+** <li> A FILE* to which trace output should be written.
+**      If NULL, then tracing is turned off.
+** <li> A prefix string written at the beginning of every
+**      line of trace output.  If NULL, then tracing is
+**      turned off.
+** </ul>
+**
+** Outputs:
+** None.
+*/
+void ParseTrace(FILE *TraceFILE, char *zTracePrompt){
+  yyTraceFILE = TraceFILE;
+  yyTracePrompt = zTracePrompt;
+  if( yyTraceFILE==0 ) yyTracePrompt = 0;
+  else if( yyTracePrompt==0 ) yyTraceFILE = 0;
+}
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/* For tracing shifts, the names of all terminals and nonterminals
+** are required.  The following table supplies these names */
+static const char *const yyTokenName[] = { 
+%%
+};
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/* For tracing reduce actions, the names of all rules are required.
+*/
+static const char *const yyRuleName[] = {
+%%
+};
+#endif /* NDEBUG */
+
+
+#if YYSTACKDEPTH<=0
+/*
+** Try to increase the size of the parser stack.
+*/
+static void yyGrowStack(yyParser *p){
+  int newSize;
+  yyStackEntry *pNew;
+
+  newSize = p->yystksz*2 + 100;
+  pNew = realloc(p->yystack, newSize*sizeof(pNew[0]));
+  if( pNew ){
+    p->yystack = pNew;
+    p->yystksz = newSize;
+#ifndef NDEBUG
+    if( yyTraceFILE ){
+      fprintf(yyTraceFILE,"%sStack grows to %d entries!\n",
+              yyTracePrompt, p->yystksz);
+    }
+#endif
+  }
+}
+#endif
+
+/* 
+** This function allocates a new parser.
+** The only argument is a pointer to a function which works like
+** malloc.
+**
+** Inputs:
+** A pointer to the function used to allocate memory.
+**
+** Outputs:
+** A pointer to a parser.  This pointer is used in subsequent calls
+** to Parse and ParseFree.
+*/
+void *ParseAlloc(void *(*mallocProc)(size_t)){
+  yyParser *pParser;
+  pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
+  if( pParser ){
+    pParser->yyidx = -1;
+#if YYSTACKDEPTH<=0
+    yyGrowStack(pParser);
+#endif
+  }
+  return pParser;
+}
+
+/* The following function deletes the value associated with a
+** symbol.  The symbol can be either a terminal or nonterminal.
+** "yymajor" is the symbol code, and "yypminor" is a pointer to
+** the value.
+*/
+static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
+  switch( yymajor ){
+    /* Here is inserted the actions which take place when a
+    ** terminal or non-terminal is destroyed.  This can happen
+    ** when the symbol is popped from the stack during a
+    ** reduce or during error processing or when a parser is 
+    ** being destroyed before it is finished parsing.
+    **
+    ** Note: during a reduce, the only symbols destroyed are those
+    ** which appear on the RHS of the rule, but which are not used
+    ** inside the C code.
+    */
+%%
+    default:  break;   /* If no destructor action specified: do nothing */
+  }
+}
+
+/*
+** Pop the parser's stack once.
+**
+** If there is a destructor routine associated with the token which
+** is popped from the stack, then call it.
+**
+** Return the major token number for the symbol popped.
+*/
+static int yy_pop_parser_stack(yyParser *pParser){
+  YYCODETYPE yymajor;
+  yyStackEntry *yytos = &pParser->yystack[pParser->yyidx];
+
+  if( pParser->yyidx<0 ) return 0;
+#ifndef NDEBUG
+  if( yyTraceFILE && pParser->yyidx>=0 ){
+    fprintf(yyTraceFILE,"%sPopping %s\n",
+      yyTracePrompt,
+      yyTokenName[yytos->major]);
+  }
+#endif
+  yymajor = yytos->major;
+  yy_destructor( yymajor, &yytos->minor);
+  pParser->yyidx--;
+  return yymajor;
+}
+
+/* 
+** Deallocate and destroy a parser.  Destructors are all called for
+** all stack elements before shutting the parser down.
+**
+** Inputs:
+** <ul>
+** <li>  A pointer to the parser.  This should be a pointer
+**       obtained from ParseAlloc.
+** <li>  A pointer to a function used to reclaim memory obtained
+**       from malloc.
+** </ul>
+*/
+void ParseFree(
+  void *p,                    /* The parser to be deleted */
+  void (*freeProc)(void*)     /* Function used to reclaim memory */
+){
+  yyParser *pParser = (yyParser*)p;
+  if( pParser==0 ) return;
+  while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
+#if YYSTACKDEPTH<=0
+  free(pParser->yystack);
+#endif
+  (*freeProc)((void*)pParser);
+}
+
+/*
+** Find the appropriate action for a parser given the terminal
+** look-ahead token iLookAhead.
+**
+** If the look-ahead token is YYNOCODE, then check to see if the action is
+** independent of the look-ahead.  If it is, return the action, otherwise
+** return YY_NO_ACTION.
+*/
+static int yy_find_shift_action(
+  yyParser *pParser,        /* The parser */
+  YYCODETYPE iLookAhead     /* The look-ahead token */
+){
+  int i;
+  int stateno = pParser->yystack[pParser->yyidx].stateno;
+ 
+  if( stateno>YY_SHIFT_MAX || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){
+    return yy_default[stateno];
+  }
+  assert( iLookAhead!=YYNOCODE );
+  i += iLookAhead;
+  if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
+    if( iLookAhead>0 ){
+#ifdef YYFALLBACK
+      int iFallback;            /* Fallback token */
+      if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
+             && (iFallback = yyFallback[iLookAhead])!=0 ){
+#ifndef NDEBUG
+        if( yyTraceFILE ){
+          fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
+             yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
+        }
+#endif
+        return yy_find_shift_action(pParser, iFallback);
+      }
+#endif
+#ifdef YYWILDCARD
+      {
+        int j = i - iLookAhead + YYWILDCARD;
+        if( j>=0 && j<YY_SZ_ACTTAB && yy_lookahead[j]==YYWILDCARD ){
+#ifndef NDEBUG
+          if( yyTraceFILE ){
+            fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n",
+               yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[YYWILDCARD]);
+          }
+#endif /* NDEBUG */
+          return yy_action[j];
+        }
+      }
+#endif /* YYWILDCARD */
+    }
+    return yy_default[stateno];
+  }else{
+    return yy_action[i];
+  }
+}
+
+/*
+** Find the appropriate action for a parser given the non-terminal
+** look-ahead token iLookAhead.
+**
+** If the look-ahead token is YYNOCODE, then check to see if the action is
+** independent of the look-ahead.  If it is, return the action, otherwise
+** return YY_NO_ACTION.
+*/
+static int yy_find_reduce_action(
+  int stateno,              /* Current state number */
+  YYCODETYPE iLookAhead     /* The look-ahead token */
+){
+  int i;
+  assert( stateno<=YY_REDUCE_MAX );
+  i = yy_reduce_ofst[stateno];
+  assert( i!=YY_REDUCE_USE_DFLT );
+  assert( iLookAhead!=YYNOCODE );
+  i += iLookAhead;
+  assert( i>=0 && i<YY_SZ_ACTTAB );
+  assert( yy_lookahead[i]==iLookAhead );
+  return yy_action[i];
+}
+
+/*
+** The following routine is called if the stack overflows.
+*/
+static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){
+   ParseARG_FETCH;
+   yypParser->yyidx--;
+#ifndef NDEBUG
+   if( yyTraceFILE ){
+     fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
+   }
+#endif
+   while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
+   /* Here code is inserted which will execute if the parser
+   ** stack every overflows */
+%%
+   ParseARG_STORE; /* Suppress warning about unused %extra_argument var */
+}
+
+/*
+** Perform a shift action.
+*/
+static void yy_shift(
+  yyParser *yypParser,          /* The parser to be shifted */
+  int yyNewState,               /* The new state to shift in */
+  int yyMajor,                  /* The major token to shift in */
+  YYMINORTYPE *yypMinor         /* Pointer ot the minor token to shift in */
+){
+  yyStackEntry *yytos;
+  yypParser->yyidx++;
+#if YYSTACKDEPTH>0 
+  if( yypParser->yyidx>=YYSTACKDEPTH ){
+    yyStackOverflow(yypParser, yypMinor);
+    return;
+  }
+#else
+  if( yypParser->yyidx>=yypParser->yystksz ){
+    yyGrowStack(yypParser);
+    if( yypParser->yyidx>=yypParser->yystksz ){
+      yyStackOverflow(yypParser, yypMinor);
+      return;
+    }
+  }
+#endif
+  yytos = &yypParser->yystack[yypParser->yyidx];
+  yytos->stateno = yyNewState;
+  yytos->major = yyMajor;
+  yytos->minor = *yypMinor;
+#ifndef NDEBUG
+  if( yyTraceFILE && yypParser->yyidx>0 ){
+    int i;
+    fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
+    fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
+    for(i=1; i<=yypParser->yyidx; i++)
+      fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
+    fprintf(yyTraceFILE,"\n");
+  }
+#endif
+}
+
+/* The following table contains information about every rule that
+** is used during the reduce.
+*/
+static const struct {
+  YYCODETYPE lhs;         /* Symbol on the left-hand side of the rule */
+  unsigned char nrhs;     /* Number of right-hand side symbols in the rule */
+} yyRuleInfo[] = {
+%%
+};
+
+static void yy_accept(yyParser*);  /* Forward Declaration */
+
+/*
+** Perform a reduce action and the shift that must immediately
+** follow the reduce.
+*/
+static void yy_reduce(
+  yyParser *yypParser,         /* The parser */
+  int yyruleno                 /* Number of the rule by which to reduce */
+){
+  int yygoto;                     /* The next state */
+  int yyact;                      /* The next action */
+  YYMINORTYPE yygotominor;        /* The LHS of the rule reduced */
+  yyStackEntry *yymsp;            /* The top of the parser's stack */
+  int yysize;                     /* Amount to pop the stack */
+  ParseARG_FETCH;
+  yymsp = &yypParser->yystack[yypParser->yyidx];
+#ifndef NDEBUG
+  if( yyTraceFILE && yyruleno>=0 
+        && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
+    fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
+      yyRuleName[yyruleno]);
+  }
+#endif /* NDEBUG */
+
+  /* Silence complaints from purify about yygotominor being uninitialized
+  ** in some cases when it is copied into the stack after the following
+  ** switch.  yygotominor is uninitialized when a rule reduces that does
+  ** not set the value of its left-hand side nonterminal.  Leaving the
+  ** value of the nonterminal uninitialized is utterly harmless as long
+  ** as the value is never used.  So really the only thing this code
+  ** accomplishes is to quieten purify.  
+  **
+  ** 2007-01-16:  The wireshark project (www.wireshark.org) reports that
+  ** without this code, their parser segfaults.  I'm not sure what there
+  ** parser is doing to make this happen.  This is the second bug report
+  ** from wireshark this week.  Clearly they are stressing Lemon in ways
+  ** that it has not been previously stressed...  (SQLite ticket #2172)
+  */
+  memset(&yygotominor, 0, sizeof(yygotominor));
+
+
+  switch( yyruleno ){
+  /* Beginning here are the reduction cases.  A typical example
+  ** follows:
+  **   case 0:
+  **  #line <lineno> <grammarfile>
+  **     { ... }           // User supplied code
+  **  #line <lineno> <thisfile>
+  **     break;
+  */
+%%
+  };
+  yygoto = yyRuleInfo[yyruleno].lhs;
+  yysize = yyRuleInfo[yyruleno].nrhs;
+  yypParser->yyidx -= yysize;
+  yyact = yy_find_reduce_action(yymsp[-yysize].stateno,yygoto);
+  if( yyact < YYNSTATE ){
+#ifdef NDEBUG
+    /* If we are not debugging and the reduce action popped at least
+    ** one element off the stack, then we can push the new element back
+    ** onto the stack here, and skip the stack overflow test in yy_shift().
+    ** That gives a significant speed improvement. */
+    if( yysize ){
+      yypParser->yyidx++;
+      yymsp -= yysize-1;
+      yymsp->stateno = yyact;
+      yymsp->major = yygoto;
+      yymsp->minor = yygotominor;
+    }else
+#endif
+    {
+      yy_shift(yypParser,yyact,yygoto,&yygotominor);
+    }
+  }else{
+    assert( yyact == YYNSTATE + YYNRULE + 1 );
+    yy_accept(yypParser);
+  }
+}
+
+/*
+** The following code executes when the parse fails
+*/
+static void yy_parse_failed(
+  yyParser *yypParser           /* The parser */
+){
+  ParseARG_FETCH;
+#ifndef NDEBUG
+  if( yyTraceFILE ){
+    fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
+  }
+#endif
+  while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
+  /* Here code is inserted which will be executed whenever the
+  ** parser fails */
+%%
+  ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+
+/*
+** The following code executes when a syntax error first occurs.
+*/
+static void yy_syntax_error(
+  yyParser *yypParser,           /* The parser */
+  int yymajor,                   /* The major type of the error token */
+  YYMINORTYPE yyminor            /* The minor type of the error token */
+){
+  ParseARG_FETCH;
+#define TOKEN (yyminor.yy0)
+%%
+  ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+
+/*
+** The following is executed when the parser accepts
+*/
+static void yy_accept(
+  yyParser *yypParser           /* The parser */
+){
+  ParseARG_FETCH;
+#ifndef NDEBUG
+  if( yyTraceFILE ){
+    fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
+  }
+#endif
+  while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
+  /* Here code is inserted which will be executed whenever the
+  ** parser accepts */
+%%
+  ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+
+/* The main parser program.
+** The first argument is a pointer to a structure obtained from
+** "ParseAlloc" which describes the current state of the parser.
+** The second argument is the major token number.  The third is
+** the minor token.  The fourth optional argument is whatever the
+** user wants (and specified in the grammar) and is available for
+** use by the action routines.
+**
+** Inputs:
+** <ul>
+** <li> A pointer to the parser (an opaque structure.)
+** <li> The major token number.
+** <li> The minor token number.
+** <li> An option argument of a grammar-specified type.
+** </ul>
+**
+** Outputs:
+** None.
+*/
+void Parse(
+  void *yyp,                   /* The parser */
+  int yymajor,                 /* The major token code number */
+  ParseTOKENTYPE yyminor       /* The value for the token */
+  ParseARG_PDECL               /* Optional %extra_argument parameter */
+){
+  YYMINORTYPE yyminorunion;
+  int yyact;            /* The parser action. */
+  int yyendofinput;     /* True if we are at the end of input */
+#ifdef YYERRORSYMBOL
+  int yyerrorhit = 0;   /* True if yymajor has invoked an error */
+#endif
+  yyParser *yypParser;  /* The parser */
+
+  /* (re)initialize the parser, if necessary */
+  yypParser = (yyParser*)yyp;
+  if( yypParser->yyidx<0 ){
+#if YYSTACKDEPTH<=0
+    if( yypParser->yystksz <=0 ){
+      memset(&yyminorunion, 0, sizeof(yyminorunion));
+      yyStackOverflow(yypParser, &yyminorunion);
+      return;
+    }
+#endif
+    yypParser->yyidx = 0;
+    yypParser->yyerrcnt = -1;
+    yypParser->yystack[0].stateno = 0;
+    yypParser->yystack[0].major = 0;
+  }
+  yyminorunion.yy0 = yyminor;
+  yyendofinput = (yymajor==0);
+  ParseARG_STORE;
+
+#ifndef NDEBUG
+  if( yyTraceFILE ){
+    fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]);
+  }
+#endif
+
+  do{
+    yyact = yy_find_shift_action(yypParser,yymajor);
+    if( yyact<YYNSTATE ){
+      assert( !yyendofinput );  /* Impossible to shift the $ token */
+      yy_shift(yypParser,yyact,yymajor,&yyminorunion);
+      yypParser->yyerrcnt--;
+      yymajor = YYNOCODE;
+    }else if( yyact < YYNSTATE + YYNRULE ){
+      yy_reduce(yypParser,yyact-YYNSTATE);
+    }else{
+      assert( yyact == YY_ERROR_ACTION );
+#ifdef YYERRORSYMBOL
+      int yymx;
+#endif
+#ifndef NDEBUG
+      if( yyTraceFILE ){
+        fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
+      }
+#endif
+#ifdef YYERRORSYMBOL
+      /* A syntax error has occurred.
+      ** The response to an error depends upon whether or not the
+      ** grammar defines an error token "ERROR".  
+      **
+      ** This is what we do if the grammar does define ERROR:
+      **
+      **  * Call the %syntax_error function.
+      **
+      **  * Begin popping the stack until we enter a state where
+      **    it is legal to shift the error symbol, then shift
+      **    the error symbol.
+      **
+      **  * Set the error count to three.
+      **
+      **  * Begin accepting and shifting new tokens.  No new error
+      **    processing will occur until three tokens have been
+      **    shifted successfully.
+      **
+      */
+      if( yypParser->yyerrcnt<0 ){
+        yy_syntax_error(yypParser,yymajor,yyminorunion);
+      }
+      yymx = yypParser->yystack[yypParser->yyidx].major;
+      if( yymx==YYERRORSYMBOL || yyerrorhit ){
+#ifndef NDEBUG
+        if( yyTraceFILE ){
+          fprintf(yyTraceFILE,"%sDiscard input token %s\n",
+             yyTracePrompt,yyTokenName[yymajor]);
+        }
+#endif
+        yy_destructor(yymajor,&yyminorunion);
+        yymajor = YYNOCODE;
+      }else{
+         while(
+          yypParser->yyidx >= 0 &&
+          yymx != YYERRORSYMBOL &&
+          (yyact = yy_find_reduce_action(
+                        yypParser->yystack[yypParser->yyidx].stateno,
+                        YYERRORSYMBOL)) >= YYNSTATE
+        ){
+          yy_pop_parser_stack(yypParser);
+        }
+        if( yypParser->yyidx < 0 || yymajor==0 ){
+          yy_destructor(yymajor,&yyminorunion);
+          yy_parse_failed(yypParser);
+          yymajor = YYNOCODE;
+        }else if( yymx!=YYERRORSYMBOL ){
+          YYMINORTYPE u2;
+          u2.YYERRSYMDT = 0;
+          yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
+        }
+      }
+      yypParser->yyerrcnt = 3;
+      yyerrorhit = 1;
+#else  /* YYERRORSYMBOL is not defined */
+      /* This is what we do if the grammar does not define ERROR:
+      **
+      **  * Report an error message, and throw away the input token.
+      **
+      **  * If the input token is $, then fail the parse.
+      **
+      ** As before, subsequent error messages are suppressed until
+      ** three input tokens have been successfully shifted.
+      */
+      if( yypParser->yyerrcnt<=0 ){
+        yy_syntax_error(yypParser,yymajor,yyminorunion);
+      }
+      yypParser->yyerrcnt = 3;
+      yy_destructor(yymajor,&yyminorunion);
+      if( yyendofinput ){
+        yy_parse_failed(yypParser);
+      }
+      yymajor = YYNOCODE;
+#endif
+    }
+  }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
+  return;
+}

Added: test-suite/trunk/MultiSource/Applications/lemon/lighttpd_COPYING
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/lemon/lighttpd_COPYING?rev=48828&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/lemon/lighttpd_COPYING (added)
+++ test-suite/trunk/MultiSource/Applications/lemon/lighttpd_COPYING Wed Mar 26 12:03:57 2008
@@ -0,0 +1,31 @@
+
+
+Copyright (c) 2004, Jan Kneschke, incremental
+ All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+- Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+- Neither the name of the 'incremental' nor the names of its contributors may
+  be used to endorse or promote products derived from this software without
+  specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGE.
+

Added: test-suite/trunk/MultiSource/Applications/lemon/lighttpd_configparser.y
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/lemon/lighttpd_configparser.y?rev=48828&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/lemon/lighttpd_configparser.y (added)
+++ test-suite/trunk/MultiSource/Applications/lemon/lighttpd_configparser.y Wed Mar 26 12:03:57 2008
@@ -0,0 +1,564 @@
+%token_prefix TK_
+%extra_argument {config_t *ctx}
+%name configparser
+
+%include {
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "configfile.h"
+#include "buffer.h"
+#include "array.h"
+
+static void configparser_push(config_t *ctx, data_config *dc, int isnew) {
+  if (isnew) {
+    dc->context_ndx = ctx->all_configs->used;
+    assert(dc->context_ndx > ctx->current->context_ndx);
+    array_insert_unique(ctx->all_configs, (data_unset *)dc);
+    dc->parent = ctx->current;
+    array_insert_unique(dc->parent->childs, (data_unset *)dc);
+  }
+  array_insert_unique(ctx->configs_stack, (data_unset *)ctx->current);
+  ctx->current = dc;
+}
+
+static data_config *configparser_pop(config_t *ctx) {
+  data_config *old = ctx->current;
+  ctx->current = (data_config *) array_pop(ctx->configs_stack);
+  return old;
+}
+
+/* return a copied variable */
+static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
+  data_unset *du;
+  data_config *dc;
+
+#if 0
+  fprintf(stderr, "get var %s\n", key->ptr);
+#endif
+  for (dc = ctx->current; dc; dc = dc->parent) {
+#if 0
+    fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
+    array_print(dc->value, 0);
+#endif
+    if (NULL != (du = array_get_element(dc->value, key->ptr))) {
+      return du->copy(du);
+    }
+  }
+  return NULL;
+}
+
+/* op1 is to be eat/return by this function if success, op1->key is not cared
+   op2 is left untouch, unreferenced
+ */
+data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) {
+  /* type mismatch */
+  if (op1->type != op2->type) {
+    if (op1->type == TYPE_STRING && op2->type == TYPE_INTEGER) {
+      data_string *ds = (data_string *)op1;
+      buffer_append_long(ds->value, ((data_integer*)op2)->value);
+      return op1;
+    } else if (op1->type == TYPE_INTEGER && op2->type == TYPE_STRING) {
+      data_string *ds = data_string_init();
+      buffer_append_long(ds->value, ((data_integer*)op1)->value);
+      buffer_append_string_buffer(ds->value, ((data_string*)op2)->value);
+      op1->free(op1);
+      return (data_unset *)ds;
+    } else {
+      fprintf(stderr, "data type mismatch, cannot be merge\n");
+      return NULL;
+    }
+  }
+
+  switch (op1->type) {
+    case TYPE_STRING:
+      buffer_append_string_buffer(((data_string *)op1)->value, ((data_string *)op2)->value);
+      break;
+    case TYPE_INTEGER:
+      ((data_integer *)op1)->value += ((data_integer *)op2)->value;
+      break;
+    case TYPE_ARRAY: {
+      array *dst = ((data_array *)op1)->value;
+      array *src = ((data_array *)op2)->value;
+      data_unset *du;
+      size_t i;
+
+      for (i = 0; i < src->used; i ++) {
+        du = (data_unset *)src->data[i];
+        if (du) {
+          array_insert_unique(dst, du->copy(du));
+        }
+      }
+      break;
+    default:
+      assert(0);
+      break;
+    }
+  }
+  return op1;
+}
+
+}
+
+%parse_failure {
+  ctx->ok = 0;
+}
+
+input ::= metalines.
+metalines ::= metalines metaline.
+metalines ::= .
+metaline ::= varline.
+metaline ::= global.
+metaline ::= condlines(A) EOL. { A = NULL; }
+metaline ::= include.
+metaline ::= include_shell.
+metaline ::= EOL.
+
+%type       value                  {data_unset *}
+%type       expression             {data_unset *}
+%type       aelement               {data_unset *}
+%type       condline               {data_config *}
+%type       condlines              {data_config *}
+%type       global                 {data_config *}
+%type       aelements              {array *}
+%type       array                  {array *}
+%type       key                    {buffer *}
+%type       stringop               {buffer *}
+
+%type       cond                   {config_cond_t }
+
+%destructor value                  { $$->free($$); }
+%destructor expression             { $$->free($$); }
+%destructor aelement               { $$->free($$); }
+%destructor aelements              { array_free($$); }
+%destructor array                  { array_free($$); }
+%destructor key                    { buffer_free($$); }
+%destructor stringop               { buffer_free($$); }
+
+%token_type                        {buffer *}
+%token_destructor                  { buffer_free($$); }
+
+varline ::= key(A) ASSIGN expression(B). {
+  if (ctx->ok) {
+    buffer_copy_string_buffer(B->key, A);
+    if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
+      fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
+          ctx->current->context_ndx,
+          ctx->current->key->ptr, A->ptr);
+      ctx->ok = 0;
+    } else if (NULL == array_get_element(ctx->current->value, B->key->ptr)) {
+      array_insert_unique(ctx->current->value, B);
+      B = NULL;
+    } else {
+      fprintf(stderr, "Duplicate config variable in conditional %d %s: %s\n",
+              ctx->current->context_ndx,
+              ctx->current->key->ptr, B->key->ptr);
+      ctx->ok = 0;
+      B->free(B);
+      B = NULL;
+    }
+  }
+  buffer_free(A);
+  A = NULL;
+}
+
+varline ::= key(A) APPEND expression(B). {
+  array *vars = ctx->current->value;
+  data_unset *du;
+
+  if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
+    fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n",
+        ctx->current->context_ndx,
+        ctx->current->key->ptr, A->ptr);
+    ctx->ok = 0;
+  } else if (NULL != (du = array_get_element(vars, A->ptr))) {
+    /* exists in current block */
+    du = configparser_merge_data(du, B);
+    if (NULL == du) {
+      ctx->ok = 0;
+    }
+    else {
+      buffer_copy_string_buffer(du->key, A);
+      array_replace(vars, du);
+    }
+    B->free(B);
+  } else if (NULL != (du = configparser_get_variable(ctx, A))) {
+    du = configparser_merge_data(du, B);
+    if (NULL == du) {
+      ctx->ok = 0;
+      du->free(du);
+    }
+    else {
+      buffer_copy_string_buffer(du->key, A);
+      array_insert_unique(ctx->current->value, du);
+    }
+    B->free(B);
+  } else {
+    buffer_copy_string_buffer(B->key, A);
+    array_insert_unique(ctx->current->value, B);
+  }
+  buffer_free(A);
+  A = NULL;
+  B = NULL;
+}
+
+key(A) ::= LKEY(B). {
+  if (strchr(B->ptr, '.') == NULL) {
+    A = buffer_init_string("var.");
+    buffer_append_string_buffer(A, B);
+    buffer_free(B);
+    B = NULL;
+  } else {
+    A = B;
+    B = NULL;
+  }
+}
+
+expression(A) ::= expression(B) PLUS value(C). {
+  A = configparser_merge_data(B, C);
+  if (NULL == A) {
+    ctx->ok = 0;
+  }
+  B = NULL;
+  C->free(C);
+  C = NULL;
+}
+
+expression(A) ::= value(B). {
+  A = B;
+  B = NULL;
+}
+
+value(A) ::= key(B). {
+  A = NULL;
+  if (strncmp(B->ptr, "env.", sizeof("env.") - 1) == 0) {
+    char *env;
+
+    if (NULL != (env = getenv(B->ptr + 4))) {
+      data_string *ds;
+      ds = data_string_init();
+      buffer_append_string(ds->value, env);
+      A = (data_unset *)ds;
+    }
+    else {
+      fprintf(stderr, "Undefined env variable: %s\n", B->ptr + 4);
+      ctx->ok = 0;
+    }
+  } else if (NULL == (A = configparser_get_variable(ctx, B))) {
+    fprintf(stderr, "Undefined config variable: %s\n", B->ptr);
+    ctx->ok = 0;
+  }
+  if (!A) {
+    /* make a dummy so it won't crash */
+    A = (data_unset *)data_string_init();
+  }
+  buffer_free(B);
+  B = NULL;
+}
+
+value(A) ::= STRING(B). {
+  A = (data_unset *)data_string_init();
+  buffer_copy_string_buffer(((data_string *)(A))->value, B);
+  buffer_free(B);
+  B = NULL;
+}
+
+value(A) ::= INTEGER(B). {
+  A = (data_unset *)data_integer_init();
+  ((data_integer *)(A))->value = strtol(B->ptr, NULL, 10);
+  buffer_free(B);
+  B = NULL;
+}
+value(A) ::= array(B). {
+  A = (data_unset *)data_array_init();
+  array_free(((data_array *)(A))->value);
+  ((data_array *)(A))->value = B;
+  B = NULL;
+}
+array(A) ::= LPARAN RPARAN. {
+  A = array_init();
+}
+array(A) ::= LPARAN aelements(B) RPARAN. {
+  A = B;
+  B = NULL;
+}
+
+aelements(A) ::= aelements(C) COMMA aelement(B). {
+  if (buffer_is_empty(B->key) ||
+      NULL == array_get_element(C, B->key->ptr)) {
+    array_insert_unique(C, B);
+    B = NULL;
+  } else {
+    fprintf(stderr, "Duplicate array-key: %s\n",
+            B->key->ptr);
+    ctx->ok = 0;
+    B->free(B);
+    B = NULL;
+  }
+
+  A = C;
+  C = NULL;
+}
+
+aelements(A) ::= aelements(C) COMMA. {
+  A = C;
+  C = NULL;
+}
+
+aelements(A) ::= aelement(B). {
+  A = array_init();
+  array_insert_unique(A, B);
+  B = NULL;
+}
+
+aelement(A) ::= expression(B). {
+  A = B;
+  B = NULL;
+}
+aelement(A) ::= stringop(B) ARRAY_ASSIGN expression(C). {
+  buffer_copy_string_buffer(C->key, B);
+  buffer_free(B);
+  B = NULL;
+
+  A = C;
+  C = NULL;
+}
+
+eols ::= EOL.
+eols ::= .
+
+globalstart ::= GLOBAL. {
+  data_config *dc;
+  dc = (data_config *)array_get_element(ctx->srv->config_context, "global");
+  assert(dc);
+  configparser_push(ctx, dc, 0);
+}
+
+global(A) ::= globalstart LCURLY metalines RCURLY. {
+  data_config *cur;
+
+  cur = ctx->current;
+  configparser_pop(ctx);
+
+  assert(cur && ctx->current);
+
+  A = cur;
+}
+
+condlines(A) ::= condlines(B) eols ELSE condline(C). {
+  assert(B->context_ndx < C->context_ndx);
+  C->prev = B;
+  B->next = C;
+  A = C;
+  B = NULL;
+  C = NULL;
+}
+
+condlines(A) ::= condline(B). {
+  A = B;
+  B = NULL;
+}
+
+condline(A) ::= context LCURLY metalines RCURLY. {
+  data_config *cur;
+
+  cur = ctx->current;
+  configparser_pop(ctx);
+
+  assert(cur && ctx->current);
+
+  A = cur;
+}
+
+context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expression(D). {
+  data_config *dc;
+  buffer *b, *rvalue, *op;
+
+  if (ctx->ok && D->type != TYPE_STRING) {
+    fprintf(stderr, "rvalue must be string");
+    ctx->ok = 0;
+  }
+
+  switch(E) {
+  case CONFIG_COND_NE:
+    op = buffer_init_string("!=");
+    break;
+  case CONFIG_COND_EQ:
+    op = buffer_init_string("==");
+    break;
+  case CONFIG_COND_NOMATCH:
+    op = buffer_init_string("!~");
+    break;
+  case CONFIG_COND_MATCH:
+    op = buffer_init_string("=~");
+    break;
+  default:
+    assert(0);
+    return;
+  }
+
+  b = buffer_init();
+  buffer_copy_string_buffer(b, ctx->current->key);
+  buffer_append_string(b, "/");
+  buffer_append_string_buffer(b, B);
+  buffer_append_string_buffer(b, C);
+  buffer_append_string_buffer(b, op);
+  rvalue = ((data_string*)D)->value;
+  buffer_append_string_buffer(b, rvalue);
+
+  if (NULL != (dc = (data_config *)array_get_element(ctx->all_configs, b->ptr))) {
+    configparser_push(ctx, dc, 0);
+  } else {
+    struct {
+      comp_key_t comp;
+      char *comp_key;
+      size_t len;
+    } comps[] = {
+      { COMP_SERVER_SOCKET,      CONST_STR_LEN("SERVER[\"socket\"]"   ) },
+      { COMP_HTTP_URL,           CONST_STR_LEN("HTTP[\"url\"]"        ) },
+      { COMP_HTTP_HOST,          CONST_STR_LEN("HTTP[\"host\"]"       ) },
+      { COMP_HTTP_REFERER,       CONST_STR_LEN("HTTP[\"referer\"]"    ) },
+      { COMP_HTTP_USER_AGENT,    CONST_STR_LEN("HTTP[\"useragent\"]"  ) },
+      { COMP_HTTP_USER_AGENT,    CONST_STR_LEN("HTTP[\"user-agent\"]"  ) },
+      { COMP_HTTP_COOKIE,        CONST_STR_LEN("HTTP[\"cookie\"]"     ) },
+      { COMP_HTTP_REMOTE_IP,     CONST_STR_LEN("HTTP[\"remoteip\"]"   ) },
+      { COMP_HTTP_REMOTE_IP,     CONST_STR_LEN("HTTP[\"remote-ip\"]"   ) },
+      { COMP_HTTP_QUERY_STRING,  CONST_STR_LEN("HTTP[\"querystring\"]") },
+      { COMP_HTTP_QUERY_STRING,  CONST_STR_LEN("HTTP[\"query-string\"]") },
+      { COMP_HTTP_REQUEST_METHOD, CONST_STR_LEN("HTTP[\"request-method\"]") },
+      { COMP_HTTP_SCHEME,        CONST_STR_LEN("HTTP[\"scheme\"]"     ) },
+      { COMP_UNSET, NULL, 0 },
+    };
+    size_t i;
+
+    dc = data_config_init();
+
+    buffer_copy_string_buffer(dc->key, b);
+    buffer_copy_string_buffer(dc->op, op);
+    buffer_copy_string_buffer(dc->comp_key, B);
+    buffer_append_string_len(dc->comp_key, CONST_STR_LEN("[\""));
+    buffer_append_string_buffer(dc->comp_key, C);
+    buffer_append_string_len(dc->comp_key, CONST_STR_LEN("\"]"));
+    dc->cond = E;
+
+    for (i = 0; comps[i].comp_key; i ++) {
+      if (buffer_is_equal_string(
+            dc->comp_key, comps[i].comp_key, comps[i].len)) {
+        dc->comp = comps[i].comp;
+        break;
+      }
+    }
+    if (COMP_UNSET == dc->comp) {
+      fprintf(stderr, "error comp_key %s", dc->comp_key->ptr);
+      ctx->ok = 0;
+    }
+
+    switch(E) {
+    case CONFIG_COND_NE:
+    case CONFIG_COND_EQ:
+      dc->string = buffer_init_buffer(rvalue);
+      break;
+    case CONFIG_COND_NOMATCH:
+    case CONFIG_COND_MATCH: {
+#ifdef HAVE_PCRE_H
+      const char *errptr;
+      int erroff;
+
+      if (NULL == (dc->regex =
+          pcre_compile(rvalue->ptr, 0, &errptr, &erroff, NULL))) {
+        dc->string = buffer_init_string(errptr);
+        dc->cond = CONFIG_COND_UNSET;
+
+        fprintf(stderr, "parsing regex failed: %s -> %s at offset %d\n",
+            rvalue->ptr, errptr, erroff);
+
+        ctx->ok = 0;
+      } else if (NULL == (dc->regex_study =
+          pcre_study(dc->regex, 0, &errptr)) &&
+                 errptr != NULL) {
+        fprintf(stderr, "studying regex failed: %s -> %s\n",
+            rvalue->ptr, errptr);
+        ctx->ok = 0;
+      } else {
+        dc->string = buffer_init_buffer(rvalue);
+      }
+#else
+      fprintf(stderr, "can't handle '$%s[%s] =~ ...' as you compiled without pcre support. \n"
+		      "(perhaps just a missing pcre-devel package ?) \n",
+                      B->ptr, C->ptr);
+      ctx->ok = 0;
+#endif
+      break;
+    }
+
+    default:
+      fprintf(stderr, "unknown condition for $%s[%s]\n",
+                      B->ptr, C->ptr);
+      ctx->ok = 0;
+      break;
+    }
+
+    configparser_push(ctx, dc, 1);
+  }
+
+  buffer_free(b);
+  buffer_free(op);
+  buffer_free(B);
+  B = NULL;
+  buffer_free(C);
+  C = NULL;
+  D->free(D);
+  D = NULL;
+}
+cond(A) ::= EQ. {
+  A = CONFIG_COND_EQ;
+}
+cond(A) ::= MATCH. {
+  A = CONFIG_COND_MATCH;
+}
+cond(A) ::= NE. {
+  A = CONFIG_COND_NE;
+}
+cond(A) ::= NOMATCH. {
+  A = CONFIG_COND_NOMATCH;
+}
+
+stringop(A) ::= expression(B). {
+  A = NULL;
+  if (ctx->ok) {
+    if (B->type == TYPE_STRING) {
+      A = buffer_init_buffer(((data_string*)B)->value);
+    } else if (B->type == TYPE_INTEGER) {
+      A = buffer_init();
+      buffer_copy_long(A, ((data_integer *)B)->value);
+    } else {
+      fprintf(stderr, "operand must be string");
+      ctx->ok = 0;
+    }
+  }
+  B->free(B);
+  B = NULL;
+}
+
+include ::= INCLUDE stringop(A). {
+  if (ctx->ok) {
+    if (0 != config_parse_file(ctx->srv, ctx, A->ptr)) {
+      ctx->ok = 0;
+    }
+    buffer_free(A);
+    A = NULL;
+  }
+}
+
+include_shell ::= INCLUDE_SHELL stringop(A). {
+  if (ctx->ok) {
+    if (0 != config_parse_cmd(ctx->srv, ctx, A->ptr)) {
+      ctx->ok = 0;
+    }
+    buffer_free(A);
+    A = NULL;
+  }
+}

Added: test-suite/trunk/MultiSource/Applications/lemon/lighttpd_mod_ssi_exprparser.y
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/lemon/lighttpd_mod_ssi_exprparser.y?rev=48828&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/lemon/lighttpd_mod_ssi_exprparser.y (added)
+++ test-suite/trunk/MultiSource/Applications/lemon/lighttpd_mod_ssi_exprparser.y Wed Mar 26 12:03:57 2008
@@ -0,0 +1,121 @@
+%token_prefix TK_
+%token_type {buffer *}
+%extra_argument {ssi_ctx_t *ctx}
+%name ssiexprparser
+
+%include {
+#include <assert.h>
+#include <string.h>
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "mod_ssi_expr.h"
+#include "buffer.h"
+}
+
+%parse_failure {
+  ctx->ok = 0;
+}
+
+%type expr { ssi_val_t * }
+%type value { buffer * }
+%type exprline { ssi_val_t * }
+%type cond { int }
+%token_destructor { buffer_free($$); }
+
+%left AND.
+%left OR.
+%nonassoc EQ NE GT GE LT LE.
+%right NOT.
+
+input ::= exprline(B). {
+  ctx->val.bo = ssi_val_tobool(B);
+  ctx->val.type = SSI_TYPE_BOOL;
+
+  ssi_val_free(B);
+}
+
+exprline(A) ::= expr(B) cond(C) expr(D). {
+  int cmp;
+
+  if (B->type == SSI_TYPE_STRING &&
+      D->type == SSI_TYPE_STRING) {
+       cmp = strcmp(B->str->ptr, D->str->ptr);
+  } else {
+    cmp = ssi_val_tobool(B) - ssi_val_tobool(D);
+  }
+
+  A = B;
+
+  switch(C) {
+  case SSI_COND_EQ: A->bo = (cmp == 0) ? 1 : 0; break;
+  case SSI_COND_NE: A->bo = (cmp != 0) ? 1 : 0; break;
+  case SSI_COND_GE: A->bo = (cmp >= 0) ? 1 : 0; break;
+  case SSI_COND_GT: A->bo = (cmp > 0) ? 1 : 0; break;
+  case SSI_COND_LE: A->bo = (cmp <= 0) ? 1 : 0; break;
+  case SSI_COND_LT: A->bo = (cmp < 0) ? 1 : 0; break;
+  }
+
+  A->type = SSI_TYPE_BOOL;
+
+  ssi_val_free(D);
+}
+exprline(A) ::= expr(B). {
+  A = B;
+}
+expr(A) ::= expr(B) AND expr(C). {
+  int e;
+
+  e = ssi_val_tobool(B) && ssi_val_tobool(C);
+
+  A = B;
+  A->bo = e;
+  A->type = SSI_TYPE_BOOL;
+  ssi_val_free(C);
+}
+
+expr(A) ::= expr(B) OR expr(C). {
+  int e;
+
+  e = ssi_val_tobool(B) || ssi_val_tobool(C);
+
+  A = B;
+  A->bo = e;
+  A->type = SSI_TYPE_BOOL;
+  ssi_val_free(C);
+}
+
+expr(A) ::= NOT expr(B). {
+  int e;
+
+  e = !ssi_val_tobool(B);
+
+  A = B;
+  A->bo = e;
+  A->type = SSI_TYPE_BOOL;
+}
+expr(A) ::= LPARAN exprline(B) RPARAN. {
+  A = B;
+}
+
+expr(A) ::= value(B). {
+  A = ssi_val_init();
+  A->str = B;
+  A->type = SSI_TYPE_STRING;
+}
+
+value(A) ::= VALUE(B). {
+  A = buffer_init_string(B->ptr);
+}
+
+value(A) ::= value(B) VALUE(C). {
+  A = B;
+  buffer_append_string_buffer(A, C);
+}
+
+cond(A) ::= EQ. { A = SSI_COND_EQ; }
+cond(A) ::= NE. { A = SSI_COND_NE; }
+cond(A) ::= LE. { A = SSI_COND_LE; }
+cond(A) ::= GE. { A = SSI_COND_GE; }
+cond(A) ::= LT. { A = SSI_COND_LT; }
+cond(A) ::= GT. { A = SSI_COND_GT; }

Added: test-suite/trunk/MultiSource/Applications/lemon/parse.y
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/lemon/parse.y?rev=48828&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/lemon/parse.y (added)
+++ test-suite/trunk/MultiSource/Applications/lemon/parse.y Wed Mar 26 12:03:57 2008
@@ -0,0 +1,1114 @@
+/*
+** 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.240 2008/01/22 23:37:10 drh Exp $
+*/
+
+// All token codes are small integers with #defines that begin with "TK_"
+%token_prefix TK_
+
+// The type of the data attached to each token is Token.  This is also the
+// default type for non-terminals.
+//
+%token_type {Token}
+%default_type {Token}
+
+// The generated parser function takes a 4th argument as follows:
+%extra_argument {Parse *pParse}
+
+// This code runs whenever there is a syntax error
+//
+%syntax_error {
+  assert( TOKEN.z[0] );  /* The tokenizer always gives us a token */
+  sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
+  pParse->parseError = 1;
+}
+%stack_overflow {
+  sqlite3ErrorMsg(pParse, "parser stack overflow");
+  pParse->parseError = 1;
+}
+
+// The name of the generated procedure that implements the parser
+// is as follows:
+%name sqlite3Parser
+
+// The following text is included near the beginning of the C source
+// code file that implements the parser.
+//
+%include {
+#include "sqliteInt.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 {
+  Token eOperator;  /* "like" or "glob" or "regexp" */
+  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
+
+// 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); }
+explain ::= EXPLAIN QUERY PLAN.   { sqlite3BeginParse(pParse, 2); }
+%endif  SQLITE_OMIT_EXPLAIN
+
+///////////////////// 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 temp(T) TABLE ifnotexists(E) nm(Y) dbnm(Z). {
+   sqlite3StartTable(pParse,&Y,&Z,T,0,0,E);
+}
+%type ifnotexists {int}
+ifnotexists(A) ::= .              {A = 0;}
+ifnotexists(A) ::= IF NOT EXISTS. {A = 1;}
+%type temp {int}
+%ifndef SQLITE_OMIT_TEMPDB
+temp(A) ::= TEMP.  {A = 1;}
+%endif  SQLITE_OMIT_TEMPDB
+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.
+
+// A "column" is a complete description of a single column in a
+// CREATE TABLE statement.  This includes the column name, its
+// datatype, and other keywords such as PRIMARY KEY, UNIQUE, REFERENCES,
+// NOT NULL and so forth.
+//
+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 ANALYZE ASC ATTACH BEFORE BEGIN CASCADE CAST CONFLICT
+  DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR
+  IGNORE IMMEDIATE INITIALLY INSTEAD LIKE_KW MATCH PLAN
+  QUERY KEY OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW
+  TEMP TRIGGER VACUUM VIEW VIRTUAL
+%ifdef SQLITE_OMIT_COMPOUND_SELECT
+  EXCEPT INTERSECT UNION
+%endif SQLITE_OMIT_COMPOUND_SELECT
+  REINDEX RENAME CTIME_KW IF
+  .
+%wildcard ANY.
+
+// 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 MATCH LIKE_KW 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.
+%left COLLATE.
+%right UMINUS UPLUS BITNOT.
+
+// And "ids" is an identifer-or-string.
+//
+%type ids {Token}
+ids(A) ::= ID|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;}
+
+// A typetoken is really one or more tokens that form a type name such
+// as can be found after the column name in a CREATE TABLE statement.
+// Multiple tokens are concatenated to form the value of the typetoken.
+//
+%type typetoken {Token}
+type ::= .
+type ::= typetoken(X).                   {sqlite3AddColumnType(pParse,&X);}
+typetoken(A) ::= typename(X).   {A = X;}
+typetoken(A) ::= typename(X) LP signed RP(Y). {
+  A.z = X.z;
+  A.n = &Y.z[Y.n] - X.z;
+}
+typetoken(A) ::= typename(X) LP signed COMMA signed RP(Y). {
+  A.z = X.z;
+  A.n = &Y.z[Y.n] - X.z;
+}
+%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);}
+signed ::= plus_num.
+signed ::= minus_num.
+
+// "carglist" is a list of additional constraints that come after the
+// column name and column type in a CREATE TABLE statement.
+//
+carglist ::= carglist carg.
+carglist ::= .
+carg ::= CONSTRAINT nm ccons.
+carg ::= ccons.
+ccons ::= DEFAULT term(X).            {sqlite3AddDefaultValue(pParse,X);}
+ccons ::= DEFAULT LP expr(X) RP.      {sqlite3AddDefaultValue(pParse,X);}
+ccons ::= DEFAULT PLUS term(X).       {sqlite3AddDefaultValue(pParse,X);}
+ccons ::= DEFAULT MINUS term(X).      {
+  Expr *p = sqlite3PExpr(pParse, TK_UMINUS, X, 0, 0);
+  sqlite3AddDefaultValue(pParse,p);
+}
+ccons ::= DEFAULT id(X).              {
+  Expr *p = sqlite3PExpr(pParse, 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(Z) onconf(R) autoinc(I).
+                                     {sqlite3AddPrimaryKey(pParse,0,R,I,Z);}
+ccons ::= UNIQUE onconf(R).    {sqlite3CreateIndex(pParse,0,0,0,0,R,0,0,0,0);}
+ccons ::= CHECK LP expr(X) RP.       {sqlite3AddCheckConstraint(pParse,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 ids(C).  {sqlite3AddCollateType(pParse, &C);}
+
+// 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,0);}
+tcons ::= UNIQUE LP idxlist(X) RP onconf(R).
+                                 {sqlite3CreateIndex(pParse,0,0,0,X,R,0,0,0,0);}
+tcons ::= CHECK LP expr(E) RP onconf. {sqlite3AddCheckConstraint(pParse,E);}
+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 ifexists(E) fullname(X). {
+  sqlite3DropTable(pParse, X, 0, E);
+}
+%type ifexists {int}
+ifexists(A) ::= IF EXISTS.   {A = 1;}
+ifexists(A) ::= .            {A = 0;}
+
+///////////////////// The CREATE VIEW statement /////////////////////////////
+//
+%ifndef SQLITE_OMIT_VIEW
+cmd ::= CREATE(X) temp(T) VIEW ifnotexists(E) nm(Y) dbnm(Z) AS select(S). {
+  sqlite3CreateView(pParse, &X, &Y, &Z, S, T, E);
+}
+cmd ::= DROP VIEW ifexists(E) fullname(X). {
+  sqlite3DropTable(pParse, X, 1, E);
+}
+%endif  SQLITE_OMIT_VIEW
+
+//////////////////////// The SELECT statement /////////////////////////////////
+//
+cmd ::= select(X).  {
+  SelectDest dest = {SRT_Callback, 0, 0};
+  sqlite3Select(pParse, X, &dest, 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;
+  }else{
+    sqlite3SelectDelete(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) ::= EXCEPT|INTERSECT(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(pParse,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(pParse,P,X,Y.n?&Y:0);
+}
+selcollist(A) ::= sclp(P) STAR. {
+  Expr *p = sqlite3PExpr(pParse, TK_ALL, 0, 0, 0);
+  A = sqlite3ExprListAppend(pParse, P, p, 0);
+}
+selcollist(A) ::= sclp(P) nm(X) DOT STAR. {
+  Expr *pRight = sqlite3PExpr(pParse, TK_ALL, 0, 0, 0);
+  Expr *pLeft = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);
+  Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0);
+  A = sqlite3ExprListAppend(pParse,P, pDot, 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 = sqlite3DbMallocZero(pParse->db, sizeof(*A));}
+from(A) ::= FROM seltablist(X).  {
+  A = X;
+  sqlite3SrcListShiftJoinType(A);
+}
+
+// "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 = sqlite3SrcListAppendFromTerm(pParse,X,&Y,&D,&Z,0,N,U);
+}
+%ifndef SQLITE_OMIT_SUBQUERY
+  seltablist(A) ::= stl_prefix(X) LP seltablist_paren(S) RP
+                    as(Z) on_opt(N) using_opt(U). {
+    A = sqlite3SrcListAppendFromTerm(pParse,X,0,0,&Z,S,N,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).  {
+     sqlite3SrcListShiftJoinType(F);
+     A = sqlite3SelectNew(pParse,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(pParse->db,0,&X,&Y);}
+
+%type joinop {int}
+%type joinop2 {int}
+joinop(X) ::= COMMA|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) sortorder(Z). {
+  A = sqlite3ExprListAppend(pParse,X,Y,0);
+  if( A ) A->a[A->nExpr-1].sortOrder = Z;
+}
+sortlist(A) ::= sortitem(Y) sortorder(Z). {
+  A = sqlite3ExprListAppend(pParse,0,Y,0);
+  if( A && A->a ) A->a[0].sortOrder = Z;
+}
+sortitem(A) ::= expr(X).   {A = X;}
+
+%type sortorder {int}
+
+sortorder(A) ::= ASC.           {A = SQLITE_SO_ASC;}
+sortorder(A) ::= DESC.          {A = SQLITE_SO_DESC;}
+sortorder(A) ::= .              {A = SQLITE_SO_ASC;}
+
+%type groupby_opt {ExprList*}
+%destructor groupby_opt {sqlite3ExprListDelete($$);}
+groupby_opt(A) ::= .                      {A = 0;}
+groupby_opt(A) ::= GROUP BY nexprlist(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}
+
+// The destructor for limit_opt will never fire in the current grammar.
+// The limit_opt non-terminal only occurs at the end of a single production
+// rule for SELECT statements.  As soon as the rule that create the 
+// limit_opt non-terminal reduces, the SELECT statement rule will also
+// reduce.  So there is never a limit_opt non-terminal on the stack 
+// except as a transient.  So there is never anything to destroy.
+//
+//%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;}
+
+////////////////////////// The UPDATE command ////////////////////////////////
+//
+cmd ::= UPDATE orconf(R) fullname(X) SET setlist(Y) where_opt(Z).  {
+  sqlite3ExprListCheckLength(pParse,Y,SQLITE_MAX_COLUMN,"set list"); 
+  sqlite3Update(pParse,X,Y,Z,R);
+}
+
+%type setlist {ExprList*}
+%destructor setlist {sqlite3ExprListDelete($$);}
+
+setlist(A) ::= setlist(Z) COMMA nm(X) EQ expr(Y).
+    {A = sqlite3ExprListAppend(pParse,Z,Y,&X);}
+setlist(A) ::= nm(X) EQ expr(Y).
+    {A = sqlite3ExprListAppend(pParse,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);}
+cmd ::= insert_cmd(R) INTO fullname(X) inscollist_opt(F) DEFAULT VALUES.
+            {sqlite3Insert(pParse, X, 0, 0, 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(pParse,X,Y,0);}
+itemlist(A) ::= expr(X).
+    {A = sqlite3ExprListAppend(pParse,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(pParse->db,X,&Y);}
+inscollist(A) ::= nm(Y).
+    {A = sqlite3IdListAppend(pParse->db,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 = sqlite3PExpr(pParse, @X, 0, 0, &X);}
+expr(A) ::= ID(X).               {A = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);}
+expr(A) ::= JOIN_KW(X).          {A = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);}
+expr(A) ::= nm(X) DOT nm(Y). {
+  Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);
+  Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &Y);
+  A = sqlite3PExpr(pParse, TK_DOT, temp1, temp2, 0);
+}
+expr(A) ::= nm(X) DOT nm(Y) DOT nm(Z). {
+  Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);
+  Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &Y);
+  Expr *temp3 = sqlite3PExpr(pParse, TK_ID, 0, 0, &Z);
+  Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3, 0);
+  A = sqlite3PExpr(pParse, TK_DOT, temp1, temp4, 0);
+}
+term(A) ::= INTEGER|FLOAT|BLOB(X).  {A = sqlite3PExpr(pParse, @X, 0, 0, &X);}
+term(A) ::= STRING(X).       {A = sqlite3PExpr(pParse, @X, 0, 0, &X);}
+expr(A) ::= REGISTER(X).     {A = sqlite3RegisterExpr(pParse, &X);}
+expr(A) ::= VARIABLE(X).     {
+  Token *pToken = &X;
+  Expr *pExpr = A = sqlite3PExpr(pParse, TK_VARIABLE, 0, 0, pToken);
+  sqlite3ExprAssignVarNumber(pParse, pExpr);
+}
+expr(A) ::= expr(E) COLLATE ids(C). {
+  A = sqlite3ExprSetColl(pParse, E, &C);
+}
+%ifndef SQLITE_OMIT_CAST
+expr(A) ::= CAST(X) LP expr(E) AS typetoken(T) RP(Y). {
+  A = sqlite3PExpr(pParse, TK_CAST, E, 0, &T);
+  sqlite3ExprSpan(A,&X,&Y);
+}
+%endif  SQLITE_OMIT_CAST
+expr(A) ::= ID(X) LP distinct(D) exprlist(Y) RP(E). {
+  if( Y && Y->nExpr>SQLITE_MAX_FUNCTION_ARG ){
+    sqlite3ErrorMsg(pParse, "too many arguments on function %T", &X);
+  }
+  A = sqlite3ExprFunction(pParse, Y, &X);
+  sqlite3ExprSpan(A,&X,&E);
+  if( D && A ){
+    A->flags |= EP_Distinct;
+  }
+}
+expr(A) ::= ID(X) LP STAR RP(E). {
+  A = sqlite3ExprFunction(pParse, 0, &X);
+  sqlite3ExprSpan(A,&X,&E);
+}
+term(A) ::= CTIME_KW(OP). {
+  /* The CURRENT_TIME, CURRENT_DATE, and CURRENT_TIMESTAMP values are
+  ** treated as functions that return constants */
+  A = sqlite3ExprFunction(pParse, 0,&OP);
+  if( A ){
+    A->op = TK_CONST_FUNC;  
+    A->span = OP;
+  }
+}
+expr(A) ::= expr(X) AND(OP) expr(Y).       {A = sqlite3PExpr(pParse, at OP,X,Y,0);}
+expr(A) ::= expr(X) OR(OP) expr(Y).        {A = sqlite3PExpr(pParse, at OP,X,Y,0);}
+expr(A) ::= expr(X) LT|GT|GE|LE(OP) expr(Y).
+                                           {A = sqlite3PExpr(pParse, at OP,X,Y,0);}
+expr(A) ::= expr(X) EQ|NE(OP) expr(Y).     {A = sqlite3PExpr(pParse, at OP,X,Y,0);}
+expr(A) ::= expr(X) BITAND|BITOR|LSHIFT|RSHIFT(OP) expr(Y).
+                                           {A = sqlite3PExpr(pParse, at OP,X,Y,0);}
+expr(A) ::= expr(X) PLUS|MINUS(OP) expr(Y).{A = sqlite3PExpr(pParse, at OP,X,Y,0);}
+expr(A) ::= expr(X) STAR|SLASH|REM(OP) expr(Y).
+                                           {A = sqlite3PExpr(pParse, at OP,X,Y,0);}
+expr(A) ::= expr(X) CONCAT(OP) expr(Y).    {A = sqlite3PExpr(pParse, at OP,X,Y,0);}
+%type likeop {struct LikeOp}
+likeop(A) ::= LIKE_KW(X).     {A.eOperator = X; A.not = 0;}
+likeop(A) ::= NOT LIKE_KW(X). {A.eOperator = X; A.not = 1;}
+likeop(A) ::= MATCH(X).       {A.eOperator = X; A.not = 0;}
+likeop(A) ::= NOT MATCH(X).   {A.eOperator = X; A.not = 1;}
+%type escape {Expr*}
+%destructor escape {sqlite3ExprDelete($$);}
+escape(X) ::= ESCAPE expr(A). [ESCAPE] {X = A;}
+escape(X) ::= .               [ESCAPE] {X = 0;}
+expr(A) ::= expr(X) likeop(OP) expr(Y) escape(E).  [LIKE_KW]  {
+  ExprList *pList;
+  pList = sqlite3ExprListAppend(pParse,0, Y, 0);
+  pList = sqlite3ExprListAppend(pParse,pList, X, 0);
+  if( E ){
+    pList = sqlite3ExprListAppend(pParse,pList, E, 0);
+  }
+  A = sqlite3ExprFunction(pParse, pList, &OP.eOperator);
+  if( OP.not ) A = sqlite3PExpr(pParse, TK_NOT, A, 0, 0);
+  sqlite3ExprSpan(A, &X->span, &Y->span);
+  if( A ) A->flags |= EP_InfixFunc;
+}
+
+expr(A) ::= expr(X) ISNULL|NOTNULL(E). {
+  A = sqlite3PExpr(pParse, @E, X, 0, 0);
+  sqlite3ExprSpan(A,&X->span,&E);
+}
+expr(A) ::= expr(X) IS NULL(E). {
+  A = sqlite3PExpr(pParse, TK_ISNULL, X, 0, 0);
+  sqlite3ExprSpan(A,&X->span,&E);
+}
+expr(A) ::= expr(X) NOT NULL(E). {
+  A = sqlite3PExpr(pParse, TK_NOTNULL, X, 0, 0);
+  sqlite3ExprSpan(A,&X->span,&E);
+}
+expr(A) ::= expr(X) IS NOT NULL(E). {
+  A = sqlite3PExpr(pParse, TK_NOTNULL, X, 0, 0);
+  sqlite3ExprSpan(A,&X->span,&E);
+}
+expr(A) ::= NOT(B) expr(X). {
+  A = sqlite3PExpr(pParse, @B, X, 0, 0);
+  sqlite3ExprSpan(A,&B,&X->span);
+}
+expr(A) ::= BITNOT(B) expr(X). {
+  A = sqlite3PExpr(pParse, @B, X, 0, 0);
+  sqlite3ExprSpan(A,&B,&X->span);
+}
+expr(A) ::= MINUS(B) expr(X). [UMINUS] {
+  A = sqlite3PExpr(pParse, TK_UMINUS, X, 0, 0);
+  sqlite3ExprSpan(A,&B,&X->span);
+}
+expr(A) ::= PLUS(B) expr(X). [UPLUS] {
+  A = sqlite3PExpr(pParse, 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(pParse,0, X, 0);
+  pList = sqlite3ExprListAppend(pParse,pList, Y, 0);
+  A = sqlite3PExpr(pParse, TK_BETWEEN, W, 0, 0);
+  if( A ){
+    A->pList = pList;
+  }else{
+    sqlite3ExprListDelete(pList);
+  } 
+  if( N ) A = sqlite3PExpr(pParse, 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 = sqlite3PExpr(pParse, TK_IN, X, 0, 0);
+    if( A ){
+      A->pList = Y;
+      sqlite3ExprSetHeight(A);
+    }else{
+      sqlite3ExprListDelete(Y);
+    }
+    if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0, 0);
+    sqlite3ExprSpan(A,&X->span,&E);
+  }
+  expr(A) ::= LP(B) select(X) RP(E). {
+    A = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0);
+    if( A ){
+      A->pSelect = X;
+      sqlite3ExprSetHeight(A);
+    }else{
+      sqlite3SelectDelete(X);
+    }
+    sqlite3ExprSpan(A,&B,&E);
+  }
+  expr(A) ::= expr(X) in_op(N) LP select(Y) RP(E).  [IN] {
+    A = sqlite3PExpr(pParse, TK_IN, X, 0, 0);
+    if( A ){
+      A->pSelect = Y;
+      sqlite3ExprSetHeight(A);
+    }else{
+      sqlite3SelectDelete(Y);
+    }
+    if( N ) A = sqlite3PExpr(pParse, 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(pParse->db, 0,&Y,&Z);
+    A = sqlite3PExpr(pParse, TK_IN, X, 0, 0);
+    if( A ){
+      A->pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
+      sqlite3ExprSetHeight(A);
+    }else{
+      sqlite3SrcListDelete(pSrc);
+    }
+    if( N ) A = sqlite3PExpr(pParse, 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 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0);
+    if( p ){
+      p->pSelect = Y;
+      sqlite3ExprSpan(p,&B,&E);
+      sqlite3ExprSetHeight(A);
+    }else{
+      sqlite3SelectDelete(Y);
+    }
+  }
+%endif SQLITE_OMIT_SUBQUERY
+
+/* CASE expressions */
+expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
+  A = sqlite3PExpr(pParse, TK_CASE, X, Z, 0);
+  if( A ){
+    A->pList = Y;
+    sqlite3ExprSetHeight(A);
+  }else{
+    sqlite3ExprListDelete(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(pParse,X, Y, 0);
+  A = sqlite3ExprListAppend(pParse,A, Z, 0);
+}
+case_exprlist(A) ::= WHEN expr(Y) THEN expr(Z). {
+  A = sqlite3ExprListAppend(pParse,0, Y, 0);
+  A = sqlite3ExprListAppend(pParse,A, Z, 0);
+}
+%type case_else {Expr*}
+%destructor case_else {sqlite3ExprDelete($$);}
+case_else(A) ::=  ELSE expr(X).         {A = X;}
+case_else(A) ::=  .                     {A = 0;} 
+%type case_operand {Expr*}
+%destructor case_operand {sqlite3ExprDelete($$);}
+case_operand(A) ::= expr(X).            {A = X;} 
+case_operand(A) ::= .                   {A = 0;} 
+
+%type exprlist {ExprList*}
+%destructor exprlist {sqlite3ExprListDelete($$);}
+%type nexprlist {ExprList*}
+%destructor nexprlist {sqlite3ExprListDelete($$);}
+
+exprlist(A) ::= nexprlist(X).                {A = X;}
+exprlist(A) ::= .                            {A = 0;}
+nexprlist(A) ::= nexprlist(X) COMMA expr(Y).
+    {A = sqlite3ExprListAppend(pParse,X,Y,0);}
+nexprlist(A) ::= expr(Y).
+    {A = sqlite3ExprListAppend(pParse,0,Y,0);}
+
+
+///////////////////////////// The CREATE INDEX command ///////////////////////
+//
+cmd ::= CREATE(S) uniqueflag(U) INDEX ifnotexists(NE) nm(X) dbnm(D)
+        ON nm(Y) LP idxlist(Z) RP(E). {
+  sqlite3CreateIndex(pParse, &X, &D, 
+                     sqlite3SrcListAppend(pParse->db,0,&Y,0), Z, U,
+                      &S, &E, SQLITE_SO_ASC, NE);
+}
+
+%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(Z).  {
+  Expr *p = 0;
+  if( C.n>0 ){
+    p = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0);
+    sqlite3ExprSetColl(pParse, p, &C);
+  }
+  A = sqlite3ExprListAppend(pParse,X, p, &Y);
+  sqlite3ExprListCheckLength(pParse, A, SQLITE_MAX_COLUMN, "index");
+  if( A ) A->a[A->nExpr-1].sortOrder = Z;
+}
+idxlist(A) ::= idxitem(Y) collate(C) sortorder(Z). {
+  Expr *p = 0;
+  if( C.n>0 ){
+    p = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0);
+    sqlite3ExprSetColl(pParse, p, &C);
+  }
+  A = sqlite3ExprListAppend(pParse,0, p, &Y);
+  sqlite3ExprListCheckLength(pParse, A, SQLITE_MAX_COLUMN, "index");
+  if( A ) A->a[A->nExpr-1].sortOrder = Z;
+}
+idxitem(A) ::= nm(X).              {A = X;}
+
+%type collate {Token}
+collate(C) ::= .                {C.z = 0; C.n = 0;}
+collate(C) ::= COLLATE ids(X).   {C = X;}
+
+
+///////////////////////////// The DROP INDEX command /////////////////////////
+//
+cmd ::= DROP INDEX ifexists(E) fullname(X).   {sqlite3DropIndex(pParse, X, E);}
+
+///////////////////////////// The VACUUM command /////////////////////////////
+//
+%ifndef SQLITE_OMIT_VACUUM
+%ifndef SQLITE_OMIT_ATTACH
+cmd ::= VACUUM.                {sqlite3Vacuum(pParse);}
+cmd ::= VACUUM nm.             {sqlite3Vacuum(pParse);}
+%endif  SQLITE_OMIT_ATTACH
+%endif  SQLITE_OMIT_VACUUM
+
+///////////////////////////// The PRAGMA command /////////////////////////////
+//
+%ifndef SQLITE_OMIT_PRAGMA
+cmd ::= PRAGMA nm(X) dbnm(Z) EQ nmnum(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 minus_num(Y). {
+  sqlite3Pragma(pParse,&X,&Z,&Y,1);
+}
+cmd ::= PRAGMA nm(X) dbnm(Z) LP nmnum(Y) RP. {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
+cmd ::= PRAGMA nm(X) dbnm(Z).             {sqlite3Pragma(pParse,&X,&Z,0,0);}
+nmnum(A) ::= plus_num(X).             {A = X;}
+nmnum(A) ::= nm(X).                   {A = X;}
+%endif SQLITE_OMIT_PRAGMA
+plus_num(A) ::= plus_opt number(X).   {A = X;}
+minus_num(A) ::= MINUS number(X).     {A = X;}
+number(A) ::= INTEGER|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 ifnotexists(NOERR) nm(B) dbnm(Z) 
+                    trigger_time(C) trigger_event(D)
+                    ON fullname(E) foreach_clause when_clause(G). {
+  sqlite3BeginTrigger(pParse, &B, &Z, C, D.a, D.b, E, G, T, NOERR);
+  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|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;}
+
+foreach_clause ::= .
+foreach_clause ::= FOR EACH ROW.
+
+%type when_clause {Expr*}
+%destructor when_clause {sqlite3ExprDelete($$);}
+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_list(Y) trigger_cmd(X) SEMI. {
+  if( Y ){
+    Y->pLast->pNext = X;
+  }else{
+    Y = X;
+  }
+  Y->pLast = X;
+  A = Y;
+}
+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(pParse->db, &X, Y, Z, R); }
+
+// INSERT
+trigger_cmd(A) ::= insert_cmd(R) INTO nm(X) inscollist_opt(F) 
+                   VALUES LP itemlist(Y) RP.  
+               {A = sqlite3TriggerInsertStep(pParse->db, &X, F, Y, 0, R);}
+
+trigger_cmd(A) ::= insert_cmd(R) INTO nm(X) inscollist_opt(F) select(S).
+               {A = sqlite3TriggerInsertStep(pParse->db, &X, F, 0, S, R);}
+
+// DELETE
+trigger_cmd(A) ::= DELETE FROM nm(X) where_opt(Y).
+               {A = sqlite3TriggerDeleteStep(pParse->db, &X, Y);}
+
+// SELECT
+trigger_cmd(A) ::= select(X).  {A = sqlite3TriggerSelectStep(pParse->db, X); }
+
+// The special RAISE expression that may occur in trigger programs
+expr(A) ::= RAISE(X) LP IGNORE RP(Y).  {
+  A = sqlite3PExpr(pParse, TK_RAISE, 0, 0, 0); 
+  if( A ){
+    A->iColumn = OE_Ignore;
+    sqlite3ExprSpan(A, &X, &Y);
+  }
+}
+expr(A) ::= RAISE(X) LP raisetype(T) COMMA nm(Z) RP(Y).  {
+  A = sqlite3PExpr(pParse, TK_RAISE, 0, 0, &Z); 
+  if( A ) {
+    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 ifexists(NOERR) fullname(X). {
+  sqlite3DropTrigger(pParse,X,NOERR);
+}
+%endif  !SQLITE_OMIT_TRIGGER
+
+//////////////////////// ATTACH DATABASE file AS name /////////////////////////
+%ifndef SQLITE_OMIT_ATTACH
+cmd ::= ATTACH database_kw_opt expr(F) AS expr(D) key_opt(K). {
+  sqlite3Attach(pParse, F, D, K);
+}
+cmd ::= DETACH database_kw_opt expr(D). {
+  sqlite3Detach(pParse, D);
+}
+
+%type key_opt {Expr*}
+%destructor key_opt {sqlite3ExprDelete($$);}
+key_opt(A) ::= .                     { A = 0; }
+key_opt(A) ::= KEY expr(X).          { A = X; }
+
+database_kw_opt ::= DATABASE.
+database_kw_opt ::= .
+%endif SQLITE_OMIT_ATTACH
+
+////////////////////////// REINDEX collation //////////////////////////////////
+%ifndef SQLITE_OMIT_REINDEX
+cmd ::= REINDEX.                {sqlite3Reindex(pParse, 0, 0);}
+cmd ::= REINDEX nm(X) dbnm(Y).  {sqlite3Reindex(pParse, &X, &Y);}
+%endif  SQLITE_OMIT_REINDEX
+
+/////////////////////////////////// ANALYZE ///////////////////////////////////
+%ifndef SQLITE_OMIT_ANALYZE
+cmd ::= ANALYZE.                {sqlite3Analyze(pParse, 0, 0);}
+cmd ::= ANALYZE nm(X) dbnm(Y).  {sqlite3Analyze(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  SQLITE_OMIT_ALTERTABLE
+
+//////////////////////// CREATE VIRTUAL TABLE ... /////////////////////////////
+%ifndef SQLITE_OMIT_VIRTUALTABLE
+cmd ::= create_vtab.                       {sqlite3VtabFinishParse(pParse,0);}
+cmd ::= create_vtab LP vtabarglist RP(X).  {sqlite3VtabFinishParse(pParse,&X);}
+create_vtab ::= CREATE VIRTUAL TABLE nm(X) dbnm(Y) USING nm(Z). {
+    sqlite3VtabBeginParse(pParse, &X, &Y, &Z);
+}
+vtabarglist ::= vtabarg.
+vtabarglist ::= vtabarglist COMMA vtabarg.
+vtabarg ::= .                       {sqlite3VtabArgInit(pParse);}
+vtabarg ::= vtabarg vtabargtoken.
+vtabargtoken ::= ANY(X).            {sqlite3VtabArgExtend(pParse,&X);}
+vtabargtoken ::= lp anylist RP(X).  {sqlite3VtabArgExtend(pParse,&X);}
+lp ::= LP(X).                       {sqlite3VtabArgExtend(pParse,&X);}
+anylist ::= .
+anylist ::= anylist ANY(X).         {sqlite3VtabArgExtend(pParse,&X);}
+%endif  SQLITE_OMIT_VIRTUALTABLE

Added: test-suite/trunk/MultiSource/Applications/lemon/wireshark_COPYING
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/lemon/wireshark_COPYING?rev=48828&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/lemon/wireshark_COPYING (added)
+++ test-suite/trunk/MultiSource/Applications/lemon/wireshark_COPYING Wed Mar 26 12:03:57 2008
@@ -0,0 +1,378 @@
+This text consists of two parts:
+
+Part I: Some remarks regarding the license given in
+Part II: The actual license that covers Wireshark.
+
+When in doubt: Part II is the legally binding part, Part I is just
+there to make it easier for people that are not familiar with the
+GPLv2.
+
+
+------------------------------------------------------------------------
+Part I:
+
+Wireshark is distributed under the GNU GPLv2. There are no restrictions
+on its use. There are restrictions on its distribution in source or
+binary form.
+
+Most parts of Wireshark are covered by a "GPL version 2 or later" license.
+Some files are covered by different licenses that are compatible with
+the GPLv2.
+
+As a notable exception the pidl utility at tools/pidl is covered by a
+"GPL version 3 or later" license. Note that only the tool itself
+is covered by this license, not the source code generated by it. The
+pidl authors do not consider generated code a derived work of pidl.
+
+Parts of Wireshark can be built and distributed as libraries. These
+parts are still covered by the GPL, and NOT by the Lesser General Public
+License or any other license.
+
+If you integrate all or part of Wireshark into your own application, then 
+that application must be released under a license compatible with the GPL.
+
+The full text of the GNU GPL follows.
+
+------------------------------------------------------------------------
+Part II:
+
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.

Added: test-suite/trunk/MultiSource/Applications/lemon/wireshark_dtd_grammar.lemon
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/lemon/wireshark_dtd_grammar.lemon?rev=48828&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/lemon/wireshark_dtd_grammar.lemon (added)
+++ test-suite/trunk/MultiSource/Applications/lemon/wireshark_dtd_grammar.lemon Wed Mar 26 12:03:57 2008
@@ -0,0 +1,217 @@
+%include {
+
+/* dtd_parser.lemon
+* XML dissector for wireshark 
+* XML's DTD grammar
+*
+* Copyright 2005, Luis E. Garcia Ontanon <luis.ontanon at gmail.com>
+*
+* $Id: dtd_grammar.lemon 20443 2007-01-15 20:14:00Z lego $
+*
+* Wireshark - Network traffic analyzer
+* By Gerald Combs <gerald at wireshark.org>
+* Copyright 1998 Gerald Combs
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+* 
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+* 
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include <stdio.h>
+#include <glib.h>
+#include "dtd.h"
+#include "dtd_parse.h"
+
+static dtd_named_list_t* dtd_named_list_new(gchar* name, GPtrArray* list) {
+	dtd_named_list_t* nl = g_malloc(sizeof(dtd_named_list_t));
+
+	nl->name = name;
+	nl->list = list;
+	
+	return nl;
+}
+
+static GPtrArray* g_ptr_array_join(GPtrArray* a, GPtrArray* b){
+	
+	while(b->len > 0) {
+		g_ptr_array_add(a,g_ptr_array_remove_index_fast(b,0));
+	}
+	
+	g_ptr_array_free(b,TRUE);
+
+	return a;
+}
+
+}
+
+%name DtdParse
+
+%extra_argument { dtd_build_data_t *bd }
+
+%token_destructor { 
+	if ($$) {
+		if ($$->text) g_free($$->text);
+		if ($$->location) g_free($$->location);
+		g_free($$);
+	}
+}
+
+%syntax_error {
+	if (!TOKEN)
+		g_string_sprintfa(bd->error,"syntax error at end of file");
+	else 
+		g_string_sprintfa(bd->error,"syntax error in %s at or before '%s': \n", TOKEN->location,TOKEN->text);
+}
+
+%parse_failure {
+	g_string_sprintfa(bd->error,"DTD parsing failure\n");
+}
+
+%token_prefix TOKEN_
+
+%token_type { dtd_token_data_t* }
+
+dtd ::= doctype.
+dtd ::= dtd_parts.
+
+doctype ::= TAG_START DOCTYPE_KW NAME(Name) OPEN_BRACKET dtd_parts CLOSE_BRACKET TAG_STOP. {
+    dtd_named_list_t* root;
+    GPtrArray* root_elems = g_ptr_array_new();
+    guint i;
+
+    if(! bd->proto_name) {
+        bd->proto_name = Name->text;
+    }
+
+    if(bd->proto_root)
+        g_free(bd->proto_root);
+
+	bd->proto_root = Name->text;
+    
+	g_strdown(bd->proto_name);
+    
+    for( i = 0; i< bd->elements->len; i++) {
+        dtd_named_list_t* el = g_ptr_array_index(bd->elements,i);
+        
+        g_ptr_array_add(root_elems,g_strdup(el->name));
+    }
+    
+    root = dtd_named_list_new(g_strdup(Name->text),root_elems);
+    
+    g_ptr_array_add(bd->elements,root);
+    
+    g_free(Name->location);
+    g_free(Name);
+
+}
+
+dtd_parts ::= dtd_parts element(Element). { g_ptr_array_add(bd->elements,Element); }
+dtd_parts ::= dtd_parts attlist(Attlist). { g_ptr_array_add(bd->attributes,Attlist); }
+dtd_parts ::= element(Element). { g_ptr_array_add(bd->elements,Element); }
+dtd_parts ::= attlist(Attlist). { g_ptr_array_add(bd->attributes,Attlist); }
+
+%type   attlist				{ dtd_named_list_t* }
+attlist(A) ::= TAG_START ATTLIST_KW NAME(B) attrib_list(TheList) TAG_STOP. {
+    g_strdown(B->text);
+    A = dtd_named_list_new(B->text,TheList);
+    g_free(B->location);
+    g_free(B);
+}
+
+%type element { dtd_named_list_t* }
+element(A) ::= TAG_START ELEMENT_KW NAME(B) sub_elements(C) TAG_STOP. {
+    g_strdown(B->text);
+    A = dtd_named_list_new(B->text,C);
+    g_free(B->location);
+    g_free(B);
+}
+
+%type   attrib_list			{ GPtrArray* }
+attrib_list(A) ::= attrib_list(B) attrib(C). { g_ptr_array_add(B,C); A = B; }
+attrib_list(A) ::= attrib(B).  { A = g_ptr_array_new(); g_ptr_array_add(A,B);  }
+
+%type   attrib				{ gchar* }
+attrib(A) ::= NAME(B) att_type att_default. {
+	A = B->text;
+	g_strdown(A);
+    g_free(B->location);
+    g_free(B);
+}
+
+att_type ::= ATT_TYPE.
+att_type ::= enumeration.
+
+att_default ::= ATT_DEF.
+att_default ::= ATT_DEF_WITH_VALUE QUOTED. 
+att_default ::= QUOTED.
+att_default ::= IMPLIED_KW.
+att_default ::= REQUIRED_KW.
+
+enumeration ::= OPEN_PARENS enum_list CLOSE_PARENS.
+
+enum_list ::= enum_list PIPE enum_item.
+enum_list ::= enum_item.
+enum_list ::= enumeration.
+enum_list ::= enum_list PIPE enumeration.
+
+enum_item ::= NAME.
+enum_item ::= QUOTED.
+
+
+%type   sub_elements		{ GPtrArray* }
+sub_elements(A) ::= sub_elements(B) STAR. {A=B;}
+sub_elements(A) ::= sub_elements(B) PLUS. {A=B;}
+sub_elements(A) ::= sub_elements(B) QUESTION. {A=B;}
+sub_elements(A) ::= OPEN_PARENS ELEM_DATA CLOSE_PARENS. { A = g_ptr_array_new(); }
+sub_elements(A) ::= OPEN_PARENS element_list(B) COMMA ELEM_DATA CLOSE_PARENS.	{ A = B; }
+sub_elements(A) ::= OPEN_PARENS element_list(B) PIPE ELEM_DATA CLOSE_PARENS.	{ A = B; }
+sub_elements(A) ::= OPEN_PARENS element_list(B) CLOSE_PARENS. { A = B; }
+sub_elements(A) ::= EMPTY_KW. { A = g_ptr_array_new(); }
+
+%type   element_list	{ GPtrArray* }
+element_list(A)	::= element_list(B) COMMA element_child(C).	{ g_ptr_array_add(B,C); A = B; }
+element_list(A)	::= element_list(B) PIPE element_child(C).	{ g_ptr_array_add(B,C); A = B; }
+element_list(A)	::= element_child(B).						{ A = g_ptr_array_new(); g_ptr_array_add(A,B); }
+element_list(A) ::= sub_elements(B).						{ A = B; }
+element_list(A) ::= element_list(B) COMMA sub_elements(C).   { A = g_ptr_array_join(B,C); }
+element_list(A) ::= element_list(B) PIPE sub_elements(C).   { A = g_ptr_array_join(B,C); }
+
+%type   element_child		{ gchar* }
+element_child(A) ::= NAME(B).			{
+	A = B->text;
+	g_strdown(A);
+    g_free(B->location);
+    g_free(B);
+}
+
+element_child(A) ::= NAME(B) STAR.		{
+	A = B->text;
+	g_strdown(A);
+    g_free(B->location);
+    g_free(B);
+}
+
+element_child(A) ::= NAME(B) QUESTION.	{
+	A = B->text;
+	g_strdown(A);
+    g_free(B->location);
+    g_free(B);
+}
+
+element_child(A) ::= NAME(B) PLUS.		{
+	A = B->text;
+	g_strdown(A);
+    g_free(B->location);
+    g_free(B);
+}
+

Added: test-suite/trunk/MultiSource/Applications/lemon/wireshark_grammar.lemon
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/lemon/wireshark_grammar.lemon?rev=48828&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/lemon/wireshark_grammar.lemon (added)
+++ test-suite/trunk/MultiSource/Applications/lemon/wireshark_grammar.lemon Wed Mar 26 12:03:57 2008
@@ -0,0 +1,294 @@
+/* $Id: grammar.lemon 21321 2007-04-03 19:08:00Z lego $ */
+
+%include {
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "dfilter-int.h"
+#include "syntax-tree.h"
+#include "sttype-range.h"
+#include "sttype-test.h"
+#include "sttype-function.h"
+#include "drange.h"
+
+#include "grammar.h"
+
+#ifdef _WIN32
+#pragma warning(disable:4671)
+#endif
+	
+/* End of C code */
+}
+
+/* Parser Information */
+%name		Dfilter
+%token_prefix	TOKEN_
+%extra_argument	{dfwork_t *dfw}
+
+/* Terminal and Non-Terminal types and destructors */
+%token_type			{stnode_t*}
+%token_destructor		{stnode_free($$);}
+
+%type		sentence	{stnode_t*}
+
+
+%type		expr		{stnode_t*}
+%destructor	expr		{stnode_free($$);}
+
+%type		entity		{stnode_t*}
+%destructor	entity		{stnode_free($$);}
+
+%type		relation_test	{stnode_t*}
+%destructor	relation_test	{stnode_free($$);}
+
+%type		logical_test	{stnode_t*}
+%destructor	logical_test	{stnode_free($$);}
+
+%type		rel_op2		{test_op_t}
+
+%type		range		{stnode_t*}
+%destructor	range		{stnode_free($$);}
+
+%type		drnode		{drange_node*}
+%destructor	drnode		{drange_node_free($$);}
+
+%type		drnode_list	{GSList*}
+%destructor	drnode_list	{drange_node_free_list($$);}
+
+%type		funcparams	{GSList*}
+%destructor	funcparams	{st_funcparams_free($$);}
+
+/* This is called as soon as a syntax error happens. After that, 
+any "error" symbols are shifted, if possible. */
+%syntax_error {
+
+	header_field_info	*hfinfo;
+
+	if (!TOKEN) {
+		dfilter_fail("Unexpected end of filter string.");
+		return;
+	}
+
+	switch(stnode_type_id(TOKEN)) {
+	        case STTYPE_UNINITIALIZED:
+			dfilter_fail("Syntax error.");
+			break;
+		case STTYPE_TEST:
+			dfilter_fail("Syntax error, TEST.");
+			break;
+		case STTYPE_STRING:
+			dfilter_fail("The string \"%s\" was unexpected in this context.",
+				stnode_data(TOKEN));
+			break;
+		case STTYPE_UNPARSED:
+			dfilter_fail("\"%s\" was unexpected in this context.",
+				stnode_data(TOKEN));
+			break;
+		case STTYPE_INTEGER:
+			dfilter_fail("The integer %d was unexpected in this context.",
+				stnode_value(TOKEN));
+			break;
+		case STTYPE_FIELD:
+			hfinfo = stnode_data(TOKEN);
+			dfilter_fail("Syntax error near \"%s\".", hfinfo->abbrev);
+			break;
+		case STTYPE_FUNCTION:
+			dfilter_fail("The function s was unexpected in this context.");
+			break;
+
+		/* These aren't handed to use as terminal tokens from
+		   the scanner, so was can assert that we'll never
+		   see them here. */
+		case STTYPE_NUM_TYPES:
+		case STTYPE_RANGE:
+		case STTYPE_FVALUE:
+			g_assert_not_reached();
+			break;
+	}
+}
+
+/* When a parse fails, mark an error. This occurs after
+the above syntax_error code and after the parser fails to
+use error recovery, shifting an "error" symbol and successfully
+shifting 3 more symbols. */
+%parse_failure {
+	dfw->syntax_error = TRUE;
+}
+
+/* ----------------- The grammar -------------- */
+
+/* Associativity */
+%left TEST_AND.
+%left TEST_OR.
+%nonassoc TEST_EQ TEST_NE TEST_LT TEST_LE TEST_GT TEST_GE TEST_CONTAINS TEST_MATCHES TEST_BITWISE_AND.
+%right TEST_NOT.
+
+/* Top-level targets */
+sentence ::= expr(X).  		{ dfw->st_root = X; }
+sentence ::= .  		{ dfw->st_root = NULL; }
+
+expr(X) ::= relation_test(R).	{ X = R; }
+expr(X) ::= logical_test(L).	{ X = L; }
+
+
+/* Logical tests */
+logical_test(T) ::= expr(E) TEST_AND expr(F).
+{
+	T = stnode_new(STTYPE_TEST, NULL);
+	sttype_test_set2(T, TEST_OP_AND, E, F);
+}
+
+logical_test(T) ::= expr(E) TEST_OR expr(F).
+{
+	T = stnode_new(STTYPE_TEST, NULL);
+	sttype_test_set2(T, TEST_OP_OR, E, F);
+}
+
+logical_test(T) ::= TEST_NOT expr(E).
+{
+	T = stnode_new(STTYPE_TEST, NULL);
+	sttype_test_set1(T, TEST_OP_NOT, E);
+}
+
+logical_test(T) ::= entity(E).
+{
+	T = stnode_new(STTYPE_TEST, NULL);
+	sttype_test_set1(T, TEST_OP_EXISTS, E);
+}
+
+
+
+/* Entities, or things that can be compared/tested/checked */
+entity(E) ::= FIELD(F).		{ E = F; }
+entity(E) ::= STRING(S).	{ E = S; }
+entity(E) ::= UNPARSED(U).	{ E = U; }
+entity(E) ::= range(R).		{ E = R; }
+
+
+/* Ranges */
+range(R) ::= FIELD(F) LBRACKET drnode_list(L) RBRACKET.
+{
+	R = stnode_new(STTYPE_RANGE, NULL);
+	sttype_range_set(R, F, L);
+
+	/* Delete the list, but not the drange_nodes that
+	 * the list contains. */
+	g_slist_free(L);
+}
+
+drnode_list(L) ::= drnode(D).
+{
+	L = g_slist_append(NULL, D);
+}
+
+drnode_list(L) ::= drnode_list(P) COMMA drnode(D).
+{
+	L = g_slist_append(P, D);
+}
+
+/* x:y is offset:length */
+drnode(D) ::= INTEGER(X) COLON INTEGER(Y).
+{
+	D = drange_node_new();
+	drange_node_set_start_offset(D, stnode_value(X));
+	drange_node_set_length(D, stnode_value(Y));
+	
+	stnode_free(X);
+	stnode_free(Y);
+}
+
+/* x-y == offset:offset */
+drnode(D) ::= INTEGER(X) HYPHEN INTEGER(Y).
+{
+	D = drange_node_new();
+	drange_node_set_start_offset(D, stnode_value(X));
+	drange_node_set_end_offset(D, stnode_value(Y));
+	
+	stnode_free(X);
+	stnode_free(Y);
+}
+
+
+/* :y == from start to offset */
+drnode(D) ::= COLON INTEGER(Y).
+{
+	D = drange_node_new();
+	drange_node_set_start_offset(D, 0);
+	drange_node_set_length(D, stnode_value(Y));
+
+	stnode_free(Y);
+}
+
+/* x: from offset to end */
+drnode(D) ::= INTEGER(X) COLON.
+{
+	D = drange_node_new();
+	drange_node_set_start_offset(D, stnode_value(X));
+	drange_node_set_to_the_end(D);
+
+	stnode_free(X);
+}
+
+/* x == x:1 */
+drnode(D) ::= INTEGER(X).
+{
+	D = drange_node_new();
+	drange_node_set_start_offset(D, stnode_value(X));
+	drange_node_set_length(D, 1);
+
+	stnode_free(X);
+}
+
+
+
+/* Relational tests */
+relation_test(T) ::= entity(E) rel_op2(O) entity(F).
+{
+	T = stnode_new(STTYPE_TEST, NULL);
+	sttype_test_set2(T, O, E, F);
+}
+
+rel_op2(O) ::= TEST_EQ.  { O = TEST_OP_EQ; }
+rel_op2(O) ::= TEST_NE.  { O = TEST_OP_NE; }
+rel_op2(O) ::= TEST_GT.  { O = TEST_OP_GT; }
+rel_op2(O) ::= TEST_GE.  { O = TEST_OP_GE; }
+rel_op2(O) ::= TEST_LT.  { O = TEST_OP_LT; }
+rel_op2(O) ::= TEST_LE.  { O = TEST_OP_LE; }
+rel_op2(O) ::= TEST_BITWISE_AND.  { O = TEST_OP_BITWISE_AND; }
+rel_op2(O) ::= TEST_CONTAINS.  { O = TEST_OP_CONTAINS; }
+rel_op2(O) ::= TEST_MATCHES.  { O = TEST_OP_MATCHES; }
+
+
+/* Functions */
+
+/* A function can have one or more parameters */
+entity(E) ::= FUNCTION(F) LPAREN funcparams(P) RPAREN.
+{
+    E = F;
+	sttype_function_set_params(E, P);
+}
+
+/* A function can have zero parameters. */
+entity(E) ::= FUNCTION(F) LPAREN RPAREN.
+{
+    E = F;
+}
+
+funcparams(P) ::= entity(E).
+{
+	P = g_slist_append(NULL, E);
+}
+
+funcparams(P) ::= funcparams(L) COMMA entity(E).
+{
+	P = g_slist_append(L, E);
+}
+
+
+/* Any expression inside parens is simply that expression */
+expr(X) ::= LPAREN expr(Y) RPAREN.
+{
+	X = Y;
+}
+

Added: test-suite/trunk/MultiSource/Applications/lemon/wireshark_mate_grammar.lemon
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/lemon/wireshark_mate_grammar.lemon?rev=48828&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/lemon/wireshark_mate_grammar.lemon (added)
+++ test-suite/trunk/MultiSource/Applications/lemon/wireshark_mate_grammar.lemon Wed Mar 26 12:03:57 2008
@@ -0,0 +1,719 @@
+%include {
+
+/* mate_grammar.lemon
+* MATE's configuration language grammar 
+*
+* Copyright 2005, Luis E. Garcia Ontanon <luis.ontanon at gmail.com>
+*
+* $Id: mate_grammar.lemon 23221 2007-10-17 21:25:16Z morriss $
+*
+* Wireshark - Network traffic analyzer
+* By Gerald Combs <gerald at wireshark.org>
+* Copyright 1998 Gerald Combs
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+* 
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+* 
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "mate.h"
+#include "mate_grammar.h"
+#include <epan/ws_strsplit.h>
+#include <wiretap/file_util.h>
+
+#define DUMMY void*
+
+typedef struct _extraction {
+	gchar* as;
+	header_field_info* hfi;
+	struct _extraction* next;
+	struct _extraction* last;
+} extraction_t;
+
+typedef struct _pdu_criteria_t {
+	AVPL* criterium_avpl;
+	avpl_match_mode criterium_match_mode;
+	accept_mode_t criterium_accept_mode;
+} pdu_criteria_t;
+
+typedef struct _gop_options {
+	gop_tree_mode_t pdu_tree_mode;
+	gboolean drop_unassigned;
+	gboolean show_times;
+	float expiration;
+	float idle_timeout;
+	float lifetime;
+	AVPL* start;
+	AVPL* stop;
+	AVPL* extras;
+} gop_options_t;
+
+typedef struct _gog_statements {
+	float expiration;
+	gop_tree_mode_t gop_tree_mode;
+	GPtrArray* transform_list;
+	AVPL* extras;
+	LoAL* current_gogkeys;
+} gog_statement_t;
+
+typedef struct _transf_match_t {
+    avpl_match_mode match_mode;
+    AVPL* avpl;
+} transf_match_t; 
+
+typedef struct _transf_action_t {
+    avpl_replace_mode replace_mode;
+    AVPL* avpl;
+} transf_action_t;
+
+static void configuration_error(mate_config* mc, const gchar* fmt, ...) {
+	static gchar error_buffer[256];
+	const gchar* incl;
+	gint i;
+	mate_config_frame* current_frame;
+	va_list list;
+	
+	va_start( list, fmt );
+	g_vsnprintf(error_buffer,sizeof(error_buffer),fmt,list);
+	va_end( list );
+
+	i = (gint) mc->config_stack->len;
+	
+	while (i--) {
+
+		if (i>0) {
+			incl = "\n   included from: ";
+		} else {
+			incl = " ";
+		}
+		
+		current_frame = g_ptr_array_index(mc->config_stack,(guint)i);
+		
+		g_string_sprintfa(mc->config_error,"%s%s at line %u",incl, current_frame->filename, current_frame->linenum);
+	}
+	
+	g_string_sprintfa(mc->config_error,": %s\n",error_buffer);
+	
+	THROW(MateConfigError);
+
+}
+
+static AVPL_Transf* new_transform_elem(AVPL* match, AVPL* replace, avpl_match_mode match_mode, avpl_replace_mode replace_mode) {
+	 AVPL_Transf* t = g_malloc(sizeof(AVPL_Transf));
+	 
+	 t->name = NULL;
+	 t->match = match;
+	 t->replace = replace;
+	 t->match_mode = match_mode;
+	 t->replace_mode = replace_mode;
+	 
+	 t->map = NULL;
+	 t->next = NULL;
+	 
+	 return t;
+}
+
+static gchar* recolonize(mate_config* mc, gchar* s) {
+	GString* str = g_string_new("");
+	gchar** vec;
+	gchar* r;
+	guint i,v;
+	gchar c;
+	
+	vec = g_strsplit(s,":",0);
+	
+	for (i = 0; vec[i]; i++) {
+		g_strdown(vec[i]);
+		
+		v = 0;
+		switch ( strlen(vec[i]) ) {
+		 case 2:
+		    c = vec[i][1];
+			vec[i][1] = vec[i][0];
+			vec[i][0] = c;
+			if (vec[i][0] >= '0' && vec[i][0] <= '9') {
+				v += (vec[i][1] - '0' )*16;
+			} else {
+				v += (vec[i][1] - 'a' + 10)*16;
+			}
+		 case 1:
+			if (vec[i][0] >= '0' && vec[i][0] <= '9') {
+				v += (vec[i][0] - '0' );
+			} else {
+				v += (vec[i][0] - 'a' + 10);
+			}
+		 case 0:
+			break;
+		  default:
+			configuration_error(mc,"bad token %s",s);
+		}
+		
+		g_string_sprintfa(str,":%.2X",v);					
+	}
+	
+	g_strfreev(vec);
+	
+	g_string_erase(str,0,1);
+	
+	r = str->str;
+	
+	g_string_free(str,FALSE);
+
+	return r;
+}
+
+}
+
+%name MateParser
+
+%token_prefix TOKEN_
+
+%token_type { gchar* }
+%token_destructor { if ($$) g_free($$); }
+
+%extra_argument { mate_config* mc }
+
+%syntax_error {
+	configuration_error(mc,"Syntax Error before %s",yyminor);
+}
+
+%parse_failure {
+	configuration_error(mc,"Parse Error");
+}
+
+%type   transform_decl  { AVPL_Transf* }
+%type   transform_body { AVPL_Transf* }
+%type   transform_statements { AVPL_Transf* }
+%type   transform_statement { AVPL_Transf* }
+%type   transform_match { transf_match_t* }
+%type   transform_action { transf_action_t* }
+%type   match_mode { avpl_match_mode }
+%type   action_mode { avpl_replace_mode }
+
+%type gop_name { gchar* }
+%type time_value { float }
+%type pdu_name { gchar* }
+%type gop_tree_mode { gop_tree_mode_t }
+%type true_false { gboolean }
+
+%type criteria_statement { pdu_criteria_t* }
+%type accept_mode { accept_mode_t }
+%type pdu_drop_unassigned_statement { gboolean } 
+%type discard_pdu_data_statement { gboolean } 
+%type last_extracted_statement { gboolean } 
+
+%type extraction_statement {extraction_t*}
+%type extraction_statements {extraction_t*}
+
+%type gop_options { gop_options_t* }
+
+%type gop_start_statement { AVPL* }
+%type gop_stop_statement { AVPL* }
+%type extra_statement { AVPL* }
+%type gop_drop_unassigned_statement { gboolean }
+%type show_goptree_statement { gop_tree_mode_t }
+%type show_times_statement { gboolean }
+%type gop_expiration_statement { float }
+%type idle_timeout_statement { float }
+%type lifetime_statement { float }
+
+%type gog_statements { gog_statement_t* }
+%type gog_expiration_statement { float }
+%type gog_goptree_statement { gop_tree_mode_t }
+%type gog_key_statements { LoAL* }
+%type gog_key_statement { AVPL* }
+%type transform_list_statement { GPtrArray* }
+%type transform { AVPL_Transf* }
+%type gop_tree_type { gop_tree_mode_t }
+
+%type payload_statement { GPtrArray* }
+%type proto_stack { GPtrArray*  }
+%type field { header_field_info* }
+%type transform_list { GPtrArray* }
+%type avpl { AVPL* }
+%type avps { AVPL* }
+%type avp { AVP* }
+%type value { gchar* }
+%type avp_oneoff { gchar* }
+
+
+mate_config ::= decls.
+
+decls ::= decls decl.
+decls ::= .
+
+decl ::= pdu_decl.
+decl ::= gop_decl.
+decl ::= gog_decl.
+decl ::= transform_decl.
+decl ::= defaults_decl.
+decl ::= debug_decl.
+decl ::= DONE_KW SEMICOLON.
+
+/************* DEBUG
+*/
+
+debug_decl ::= DEBUG_KW OPEN_BRACE dbgfile_default dbglevel_default pdu_dbglevel_default gop_dbglevel_default gog_dbglevel_default CLOSE_BRACE SEMICOLON.
+
+dbgfile_default ::= FILENAME_KW QUOTED(Filename) SEMICOLON. { mc->dbg_facility = eth_fopen(Filename,"w"); if (mc->dbg_facility == NULL) report_open_failure(Filename,errno,TRUE); }
+dbgfile_default ::= FILENAME_KW NAME(Filename) SEMICOLON. { mc->dbg_facility = eth_fopen(Filename,"w"); if (mc->dbg_facility == NULL) report_open_failure(Filename,errno,TRUE);  }
+dbgfile_default ::= .
+
+dbglevel_default ::= LEVEL_KW INTEGER(LevelString) SEMICOLON. { mc->dbg_lvl = (int) strtol(LevelString,NULL,10); }
+dbglevel_default ::= .
+
+pdu_dbglevel_default ::= PDU_KW LEVEL_KW INTEGER(LevelString) SEMICOLON. { mc->dbg_pdu_lvl = (int) strtol(LevelString,NULL,10); }
+pdu_dbglevel_default ::= .
+
+gop_dbglevel_default ::= GOP_KW LEVEL_KW INTEGER(LevelString) SEMICOLON. { mc->dbg_gop_lvl = (int) strtol(LevelString,NULL,10); }
+gop_dbglevel_default ::= .
+
+gog_dbglevel_default ::= GOG_KW LEVEL_KW INTEGER(LevelString) SEMICOLON. { mc->dbg_gog_lvl = (int) strtol(LevelString,NULL,10); }
+gog_dbglevel_default ::= .
+
+
+/************* DEFAULTS
+*/
+
+defaults_decl ::= DEFAULT_KW OPEN_BRACE pdu_defaults gop_defaults gog_defaults CLOSE_BRACE SEMICOLON.
+
+pdu_defaults ::= PDU_KW OPEN_BRACE pdu_last_extracted_default pdu_drop_unassigned_default pdu_discard_default CLOSE_BRACE SEMICOLON.
+pdu_defaults ::= .
+
+pdu_last_extracted_default ::= LAST_EXTRACTED_KW true_false(Flag) SEMICOLON. { mc->defaults.pdu.last_extracted = Flag; }
+pdu_last_extracted_default ::= .
+
+pdu_drop_unassigned_default ::= DROP_UNASSIGNED_KW true_false(Flag) SEMICOLON. { mc->defaults.pdu.drop_unassigned = Flag; }
+pdu_drop_unassigned_default ::= .
+
+pdu_discard_default ::= DISCARD_PDU_DATA_KW true_false(Flag) SEMICOLON. { mc->defaults.pdu.discard = Flag; }
+pdu_discard_default ::= .
+
+gop_defaults ::= GOP_KW OPEN_BRACE gop_expiration_default gop_idle_timeout_default gop_lifetime_default gop_drop_unassigned_default gop_tree_mode_default gop_show_times_default  CLOSE_BRACE SEMICOLON.
+gop_defaults ::= .
+
+gop_expiration_default ::= EXPIRATION_KW time_value(B) SEMICOLON. { mc->defaults.gop.expiration = B; }
+gop_expiration_default ::= .
+
+gop_idle_timeout_default ::= IDLE_TIMEOUT_KW time_value(B) SEMICOLON. { mc->defaults.gop.idle_timeout = B; }
+gop_idle_timeout_default ::= .
+
+gop_lifetime_default ::= LIFETIME_KW time_value(B) SEMICOLON. { mc->defaults.gop.lifetime = B; }
+gop_lifetime_default ::= .
+
+gop_drop_unassigned_default ::= DROP_UNASSIGNED_KW true_false(B) SEMICOLON. { mc->defaults.gop.drop_unassigned = B; }
+gop_drop_unassigned_default ::= .
+
+gop_tree_mode_default ::= SHOW_TREE_KW gop_tree_mode(B) SEMICOLON. { mc->defaults.gop.pdu_tree_mode = B; }
+gop_tree_mode_default ::= .
+
+gop_show_times_default ::= SHOW_TIMES_KW true_false(B) SEMICOLON. { mc->defaults.gop.show_times = B; }
+gop_show_times_default ::= .
+
+gog_defaults ::= GOG_KW OPEN_BRACE gog_expiration_default gop_tree_mode_default gog_goptree_default CLOSE_BRACE SEMICOLON.
+gog_defaults ::= .
+
+gog_expiration_default ::= EXPIRATION_KW time_value(B) SEMICOLON. { mc->defaults.gop.expiration = B; }
+gog_expiration_default ::= .
+
+gog_goptree_default ::= GOP_TREE_KW gop_tree_type(B) SEMICOLON. { mc->defaults.gog.gop_tree_mode = B; }
+gog_goptree_default ::= .
+
+
+/******************************************* TRANSFORM
+*/
+
+transform_decl(A) ::= TRANSFORM_KW NAME(B) transform_body(C) SEMICOLON. {
+	AVPL_Transf* c;
+
+	if ( g_hash_table_lookup(mc->transfs,B) ) {
+		configuration_error(mc,"A transformation called '%s' exists already",B);
+	}
+
+	for ( c = C; c; c = c->next )
+		c->name = g_strdup(B);
+	
+	g_hash_table_insert(mc->transfs,C->name,C);
+	
+	A = NULL;
+}
+
+transform_body(A) ::= OPEN_BRACE transform_statements(B) CLOSE_BRACE. { A = B; }
+
+transform_statements(A) ::= transform_statements(C) transform_statement(B). {
+    AVPL_Transf* c;
+	
+	for ( c = C; c->next; c = c->next ) ;
+	c->next = B;
+	A = C;
+}
+
+transform_statements(A) ::= transform_statement(B). { A = B; }
+
+transform_statement(A) ::= transform_match(Match) transform_action(Action) SEMICOLON. {
+	A = new_transform_elem(Match->avpl,Action->avpl,Match->match_mode,Action->replace_mode);
+}
+
+transform_match(A) ::= MATCH_KW  match_mode(Mode) avpl(Avpl). {
+    A = g_malloc(sizeof(transf_match_t));
+    A->match_mode = Mode;
+    A->avpl = Avpl;
+}
+
+transform_match(A) ::= . {
+    A = g_malloc(sizeof(transf_match_t));
+    A->match_mode = AVPL_STRICT;
+    A->avpl = new_avpl("");
+
+}
+
+transform_action(A) ::= . {
+    A = g_malloc(sizeof(transf_action_t));
+    A->replace_mode = AVPL_INSERT;
+    A->avpl = new_avpl("");
+}
+transform_action(A) ::= action_mode(Mode) avpl(Avpl). {
+    A = g_malloc(sizeof(transf_action_t));
+    A->replace_mode = Mode;
+    A->avpl = Avpl;
+}
+
+match_mode(A) ::=  . { A = AVPL_STRICT; }
+match_mode(A) ::=  STRICT_KW. { A = AVPL_STRICT; }
+match_mode(A) ::=  EVERY_KW. { A = AVPL_EVERY; }
+match_mode(A) ::=  LOOSE_KW. { A = AVPL_LOOSE; }
+
+action_mode(A) ::= REPLACE_KW. { A = AVPL_REPLACE; }
+action_mode(A) ::= INSERT_KW. { A = AVPL_INSERT; }
+action_mode(A) ::= . { A = AVPL_INSERT; }
+
+/******************************************* PDU
+*/
+
+pdu_decl ::=
+    PDU_KW NAME(Name) PROTO_KW field(Field) TRANSPORT_KW proto_stack(Stack)
+        OPEN_BRACE
+            payload_statement(Payload)
+            extraction_statements(Extraction)
+            transform_list_statement(Transform)
+            criteria_statement(Criteria)
+            pdu_drop_unassigned_statement(DropUnassigned)
+            discard_pdu_data_statement(DistcardPduData)
+            last_extracted_statement(LastExtracted)
+        CLOSE_BRACE SEMICOLON.
+{
+    
+	mate_cfg_pdu* cfg  = new_pducfg(Name);
+	extraction_t *extraction, *next_extraction;
+	GPtrArray* transport_stack = g_ptr_array_new();
+	int i;
+	
+	if (! cfg ) configuration_error(mc,"could not create Pdu %s.",Name);
+
+	cfg->hfid_proto = Field->id;
+
+	cfg->last_extracted = LastExtracted;
+	cfg->discard = DistcardPduData;
+	cfg->drop_unassigned = DropUnassigned;
+	
+	g_string_sprintfa(mc->protos_filter,"||%s",Field->abbrev);
+
+	/* flip the transport_stack */
+	for (i = Stack->len - 1; Stack->len; i--) {
+		g_ptr_array_add(transport_stack,g_ptr_array_remove_index(Stack,i));
+	}
+	
+	g_ptr_array_free(Stack,FALSE);
+	
+	cfg->transport_ranges = transport_stack;
+	cfg->payload_ranges = Payload;
+	
+	if (Criteria) {
+		cfg->criterium = Criteria->criterium_avpl;
+		cfg->criterium_match_mode = Criteria->criterium_match_mode;
+		cfg->criterium_accept_mode = Criteria->criterium_accept_mode;
+	}
+	
+	cfg->transforms = Transform;
+	
+	for (extraction = Extraction; extraction; extraction = next_extraction) {
+		next_extraction = extraction->next;
+		
+		if ( ! add_hfid(extraction->hfi, extraction->as, cfg->hfids_attr) ) {
+			configuration_error(mc,"MATE: failed to create extraction rule '%s'",extraction->as);
+		}
+		
+		g_free(extraction);
+	}
+}
+
+payload_statement(A) ::= . { A = NULL; }
+payload_statement(A) ::= PAYLOAD_KW proto_stack(B) SEMICOLON. { A = B; }
+
+criteria_statement(A) ::= . { A = NULL; }
+criteria_statement(A) ::= CRITERIA_KW accept_mode(B) match_mode(C) avpl(D) SEMICOLON. {
+	A = g_malloc(sizeof(pdu_criteria_t));
+	A->criterium_avpl = D;
+	A->criterium_match_mode = C;
+	A->criterium_accept_mode = B;
+}
+
+accept_mode(A) ::= . { A = ACCEPT_MODE; }
+accept_mode(A) ::= ACCEPT_KW. { A = ACCEPT_MODE; }
+accept_mode(A) ::= REJECT_KW. { A = REJECT_MODE; }
+
+extraction_statements(A) ::= extraction_statements(B) extraction_statement(C). { A = B; A->last = A->last->next = C; }
+extraction_statements(A) ::= extraction_statement(B). { A = B; A->last = A; }
+
+extraction_statement(A) ::= EXTRACT_KW NAME(NAME) FROM_KW field(FIELD) SEMICOLON. {
+	A = g_malloc(sizeof(extraction_t));
+	A->as = NAME;
+	A->hfi = FIELD;
+	A->next = A->last = NULL;
+}
+
+
+pdu_drop_unassigned_statement(A) ::= DROP_UNASSIGNED_KW true_false(B) SEMICOLON. { A = B; } 
+pdu_drop_unassigned_statement(A) ::= . { A =  mc->defaults.pdu.drop_unassigned; }
+
+discard_pdu_data_statement(A) ::=  DISCARD_PDU_DATA_KW true_false(B) SEMICOLON. { A = B; }  
+discard_pdu_data_statement(A) ::=  . { A =  mc->defaults.pdu.discard; } 
+
+last_extracted_statement(A) ::= LAST_PDU_KW true_false(B) SEMICOLON. { A = B; }  
+last_extracted_statement(A) ::= . { A = mc->defaults.pdu.last_extracted; }  
+
+proto_stack(A) ::= proto_stack(B) SLASH field(C). {
+	int* hfidp = g_malloc(sizeof(int));
+
+	g_string_sprintfa(mc->fields_filter,"||%s",C->abbrev);
+	
+	*hfidp = C->id;
+	g_ptr_array_add(B,hfidp);
+	A = B;
+}
+
+proto_stack(A) ::= field(B). {
+	int* hfidp = g_malloc(sizeof(int));
+	*hfidp = B->id;
+	
+	g_string_sprintfa(mc->fields_filter,"||%s",B->abbrev);
+
+	A = g_ptr_array_new();
+	g_ptr_array_add(A,hfidp);
+}
+
+field(A) ::= NAME(B). {
+	A = proto_registrar_get_byname(B);
+}
+
+/******************************************* GOP
+*/
+
+gop_decl(A) ::= GOP_KW NAME(Name) ON_KW pdu_name(PduName) MATCH_KW avpl(Key) OPEN_BRACE 
+        gop_start_statement(Start)
+        gop_stop_statement(Stop)
+        extra_statement(Extra)
+        transform_list_statement(Transform)
+        gop_expiration_statement(Expiration)
+        idle_timeout_statement(IdleTimeout)
+        lifetime_statement(Lifetime)
+        gop_drop_unassigned_statement(DropUnassigned)
+        show_goptree_statement(TreeMode)
+        show_times_statement(ShowTimes)
+    CLOSE_BRACE SEMICOLON. {
+	mate_cfg_gop* cfg;
+	
+	if (g_hash_table_lookup(mc->gopcfgs,Name)) configuration_error(mc,"A Gop Named '%s' exists already.",Name);
+	if (g_hash_table_lookup(mc->gops_by_pduname,PduName) ) configuration_error(mc,"Gop for Pdu '%s' exists already",PduName);
+
+	cfg = new_gopcfg(Name);
+	g_hash_table_insert(mc->gops_by_pduname,PduName,cfg);
+	g_hash_table_insert(mc->gopcfgs,cfg->name,cfg);
+    
+	cfg->on_pdu = PduName;
+	cfg->key = Key;
+    cfg->drop_unassigned = DropUnassigned;
+    cfg->show_times = ShowTimes;
+    cfg->pdu_tree_mode = TreeMode;
+    cfg->expiration = Expiration;
+    cfg->idle_timeout = IdleTimeout;
+    cfg->lifetime = Lifetime;
+    cfg->start = Start;
+    cfg->stop = Stop;
+    cfg->transforms = Transform;
+    
+    merge_avpl(cfg->extra,Extra,TRUE);
+    delete_avpl(Extra,TRUE);
+}
+
+gop_drop_unassigned_statement(A) ::= DROP_UNASSIGNED_KW true_false(B) SEMICOLON. { A = B; } 
+gop_drop_unassigned_statement(A) ::= . { A =  mc->defaults.gop.drop_unassigned; }
+
+gop_start_statement(A) ::= START_KW avpl(B) SEMICOLON. { A = B; }
+gop_start_statement(A) ::= . { A = NULL; }
+
+gop_stop_statement(A) ::= STOP_KW avpl(B) SEMICOLON. { A = B; }
+gop_stop_statement(A) ::= . { A = NULL; }
+
+show_goptree_statement(A) ::= SHOW_TREE_KW gop_tree_mode(B) SEMICOLON. { A = B; }
+show_goptree_statement(A) ::= . { A = mc->defaults.gop.pdu_tree_mode; }
+
+show_times_statement(A) ::= SHOW_TIMES_KW true_false(B) SEMICOLON. { A = B; }
+show_times_statement(A) ::= . { A = mc->defaults.gop.show_times; }
+
+gop_expiration_statement(A) ::= EXPIRATION_KW time_value(B) SEMICOLON. { A = B; }
+gop_expiration_statement(A) ::= . { A = mc->defaults.gop.lifetime; }
+
+idle_timeout_statement(A) ::= IDLE_TIMEOUT_KW time_value(B) SEMICOLON. { A = B; }
+idle_timeout_statement(A) ::= . { A = mc->defaults.gop.lifetime; }
+
+lifetime_statement(A) ::= LIFETIME_KW time_value(B) SEMICOLON. { A = B; }
+lifetime_statement(A) ::= . { A = mc->defaults.gop.lifetime; }
+
+gop_tree_mode(A) ::= NO_TREE_KW.    { A = GOP_NO_TREE; }
+gop_tree_mode(A) ::= PDU_TREE_KW.   { A = GOP_PDU_TREE; }
+gop_tree_mode(A) ::= FRAME_TREE_KW. { A = GOP_FRAME_TREE; }
+gop_tree_mode(A) ::= BASIC_TREE_KW. { A = GOP_BASIC_PDU_TREE; }
+
+true_false(A) ::= TRUE_KW. { A = TRUE; }
+true_false(A) ::= FALSE_KW. { A = FALSE; }
+
+pdu_name(A) ::= NAME(B). {
+	mate_cfg_pdu* c;
+	if (( c =  g_hash_table_lookup(mc->pducfgs,B) )) {
+		A = c->name;
+	} else {
+		configuration_error(mc,"No such Pdu: '%s'",B);
+	}
+}
+
+
+time_value(A) ::= FLOATING(B). {
+	A = (float) strtod(B,NULL);
+}
+
+time_value(A) ::= INTEGER(B). {
+	A = (float) strtod(B,NULL);
+}
+
+/************* GOG
+*/
+
+gog_decl ::= GOG_KW NAME(Name) OPEN_BRACE 
+    gog_key_statements(Keys)
+    extra_statement(Extra)
+    transform_list_statement(Transforms)
+    gog_expiration_statement(Expiration)
+    gog_goptree_statement(Tree)
+ CLOSE_BRACE SEMICOLON. {
+	mate_cfg_gog* cfg = NULL;
+	
+	if ( g_hash_table_lookup(mc->gogcfgs,Name) ) {
+		configuration_error(mc,"Gog '%s' exists already ",Name);
+	}
+	
+	cfg = new_gogcfg(Name);
+
+	cfg->expiration = Expiration;
+	cfg->gop_tree_mode = Tree;
+	cfg->transforms = Transforms;
+	cfg->keys = Keys;
+	
+    merge_avpl(cfg->extra,Extra,TRUE);
+    delete_avpl(Extra,TRUE);
+}
+
+gog_goptree_statement(A) ::= GOP_TREE_KW gop_tree_type(B) SEMICOLON. { A = B; }
+gog_goptree_statement(A) ::= . { A = mc->defaults.gog.gop_tree_mode; }
+
+gog_expiration_statement(A) ::= EXPIRATION_KW time_value(B) SEMICOLON. { A = B; }
+gog_expiration_statement(A) ::= . { A = mc->defaults.gog.expiration; }
+
+gop_tree_type(A) ::= NULL_TREE_KW. { A = GOP_NULL_TREE; }
+gop_tree_type(A) ::= FULL_TREE_KW. { A = GOP_FULL_TREE; }
+gop_tree_type(A) ::= BASIC_TREE_KW. { A = GOP_BASIC_TREE; }
+
+gog_key_statements(A) ::= gog_key_statements(B) gog_key_statement(C). {
+	loal_append(B,C);
+	A = B;
+}
+
+gog_key_statements(A) ::= gog_key_statement(B). {
+	A = new_loal("");
+	loal_append(A,B);
+}
+
+
+gog_key_statement(A) ::= MEMBER_KW gop_name(B) avpl(C) SEMICOLON. {
+	rename_avpl(C,B);
+	A = C;
+}
+
+gop_name(A) ::= NAME(B). {
+	mate_cfg_gop* c;
+	if (( c = g_hash_table_lookup(mc->gopcfgs,B) )) {
+		A = c->name;
+	} else {
+		configuration_error(mc,"No Gop called '%s' has been already declared",B);
+	}
+}
+/******************************************** GENERAL
+*/
+
+
+extra_statement(A) ::= EXTRA_KW avpl(B) SEMICOLON. { A = B; }
+extra_statement(A) ::= . { A = new_avpl(""); }
+
+transform_list_statement(A) ::= TRANSFORM_KW transform_list(B) SEMICOLON. { A = B; }
+transform_list_statement(A) ::= . { A = g_ptr_array_new(); }
+
+transform_list(A) ::= transform_list(B) COMMA transform(C). { 
+	A = B;
+	g_ptr_array_add(B,C);
+}
+
+transform_list(A) ::= transform(B). {
+	A = g_ptr_array_new();
+	g_ptr_array_add(A,B);
+}
+
+transform(A) ::= NAME(B). {
+	AVPL_Transf* t;
+	
+	if (( t = g_hash_table_lookup(mc->transfs,B) )) {
+		A = t;
+	} else {
+		configuration_error(mc,"There's no such Transformation: %s",B);
+	}	
+}
+
+avpl(A) ::= OPEN_PARENS avps(B) CLOSE_PARENS. { A = B; }
+avpl(A) ::= OPEN_PARENS CLOSE_PARENS. { A = new_avpl(""); }
+
+avps(A) ::= avps(B) COMMA avp(C). { A = B; if ( ! insert_avp(B,C) ) delete_avp(C); }
+avps(A) ::= avp(B). { A = new_avpl(""); if ( ! insert_avp(A,B) ) delete_avp(B); }
+
+avp(A) ::= NAME(B) AVP_OPERATOR(C) value(D). { A = new_avp(B,D,*C); }
+avp(A) ::= NAME(B). { A = new_avp(B,"",'?'); }
+avp(A) ::= NAME(B) OPEN_BRACE avp_oneoff(C) CLOSE_BRACE. { A = new_avp(B,C,'|'); }
+
+avp_oneoff(A) ::= avp_oneoff(B) PIPE value(C). { A = g_strdup_printf("%s|%s",B,C); } 
+avp_oneoff(A) ::= value(B). { A = g_strdup(B); }
+
+value(A) ::= QUOTED(B). { A = g_strdup(B); }
+value(A) ::= NAME(B). { A = g_strdup(B); }
+value(A) ::= FLOATING(B). { A = g_strdup(B); }
+value(A) ::= INTEGER(B). { A = g_strdup(B); }
+value(A) ::= DOTED_IP(B). { A = g_strdup(B); }
+value(A) ::= COLONIZED(B). { A = recolonize(mc,B); }
+

Added: test-suite/trunk/MultiSource/Applications/lemon/xapian_COPYING
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/lemon/xapian_COPYING?rev=48828&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/lemon/xapian_COPYING (added)
+++ test-suite/trunk/MultiSource/Applications/lemon/xapian_COPYING Wed Mar 26 12:03:57 2008
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+	51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.

Added: test-suite/trunk/MultiSource/Applications/lemon/xapian_queryparser.lemony
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/lemon/xapian_queryparser.lemony?rev=48828&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/lemon/xapian_queryparser.lemony (added)
+++ test-suite/trunk/MultiSource/Applications/lemon/xapian_queryparser.lemony Wed Mar 26 12:03:57 2008
@@ -0,0 +1,1763 @@
+%include {
+/* queryparser.lemony: build a Xapian::Query object from a user query string.
+ *
+ * Copyright (C) 2004,2005,2006,2007 Olly Betts
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#include <config.h>
+
+#include "omassert.h"
+#include "queryparser_internal.h"
+#include <xapian/error.h>
+#include <xapian/unicode.h>
+#include "stringutils.h"
+
+// Include the list of token values lemon generates.
+#include "queryparser_token.h"
+
+#include <algorithm>
+#include <list>
+#include <string>
+
+#include <string.h>
+
+using namespace std;
+
+using namespace Xapian;
+
+inline bool
+U_isupper(unsigned ch) {
+    return (ch < 128 && C_isupper((unsigned char)ch));
+}
+
+inline bool
+U_isdigit(unsigned ch) {
+    return (ch < 128 && C_isdigit((unsigned char)ch));
+}
+
+inline bool
+U_isalpha(unsigned ch) {
+    return (ch < 128 && C_isalpha((unsigned char)ch));
+}
+
+using Xapian::Unicode::is_whitespace;
+
+inline bool
+is_not_whitespace(unsigned ch) {
+    return !is_whitespace(ch);
+}
+
+using Xapian::Unicode::is_wordchar;
+
+inline bool
+is_not_wordchar(unsigned ch) {
+    return !is_wordchar(ch);
+}
+
+inline bool
+is_digit(unsigned ch) {
+    return (Unicode::get_category(ch) == Unicode::DECIMAL_DIGIT_NUMBER);
+}
+
+// FIXME: we used to keep trailing "-" (e.g. Cl-) but it's of dubious utility
+// and there's the risk of hyphens getting stuck onto the end of terms...
+inline bool
+is_suffix(unsigned ch) {
+    return ch == '+' || ch == '#';
+}
+
+inline bool
+prefix_needs_colon(const string & prefix, unsigned ch)
+{
+    if (!U_isupper(ch)) return false;
+    string::size_type len = prefix.length();
+    return (len > 1 && prefix[len - 1] != ':');
+}
+
+using Unicode::is_currency;
+
+/// A structure identifying a group of filter terms.
+struct filter_group_id {
+    /** The prefix of the filter terms.
+     *  This is used for boolean filter terms.
+     */
+    list<string> prefixes;
+
+    /** The value number of the filter terms.
+     *  This is used for value range terms.
+     */
+    Xapian::valueno valno;
+
+    /// Make a new filter_group_id for boolean filter terms.
+    explicit filter_group_id(const list<string> & prefixes_)
+	: prefixes(prefixes_), valno(Xapian::BAD_VALUENO) {}
+
+    /// Make a new filter_group_id for value range terms.
+    explicit filter_group_id(Xapian::valueno valno_)
+	: prefixes(), valno(valno_) {}
+
+    /// Compare to another filter_group_id.
+    bool operator<(const filter_group_id & other) const {
+	if (prefixes != other.prefixes) {
+	    return prefixes < other.prefixes;
+	}
+	return valno < other.valno;
+    }
+};
+
+/** Class used to pass information about a token from lexer to parser.
+ *
+ *  Generally an instance of this class carries term information, but it can be
+ *  used for the start or end of a value range, with some operators (e.g. the
+ *  distance in NEAR/3 or ADJ/3, etc).
+ */
+class Term {
+    State * state;
+
+  public:
+    string name;
+    list<string> prefixes;
+    string unstemmed;
+    QueryParser::stem_strategy stem;
+    termpos pos;
+
+    Term(const string &name_, termpos pos_) : name(name_), stem(QueryParser::STEM_NONE), pos(pos_) { }
+    Term(const string &name_) : name(name_), stem(QueryParser::STEM_NONE), pos(0) { }
+    Term(const string &name_, const list<string> &prefixes_)
+	: name(name_), prefixes(prefixes_), stem(QueryParser::STEM_NONE), pos(0) { }
+    Term(termpos pos_) : stem(QueryParser::STEM_NONE), pos(pos_) { }
+    Term(State * state_, const string &name_, const list<string> &prefixes_,
+	 const string &unstemmed_,
+	 QueryParser::stem_strategy stem_ = QueryParser::STEM_NONE,
+	 termpos pos_ = 0)
+	: state(state_), name(name_), prefixes(prefixes_), unstemmed(unstemmed_),
+	  stem(stem_), pos(pos_) { }
+
+    std::string make_term(const string & prefix) const;
+
+    void need_positions() {
+	if (stem == QueryParser::STEM_SOME) stem = QueryParser::STEM_NONE;
+    }
+
+    termpos get_termpos() const { return pos; }
+
+    filter_group_id get_filter_group_id() const { return filter_group_id(prefixes); }
+
+    Query * as_wildcarded_query(State * state) const;
+
+    Query * as_partial_query(State * state_) const;
+
+    Query get_query() const;
+
+    Query get_query_with_synonyms() const;
+
+    Query get_query_with_auto_synonyms() const;
+};
+
+/// Parser State shared between the lexer and the parser.
+class State {
+    QueryParser::Internal * qpi;
+
+  public:
+    Query query;
+    const char * error;
+    unsigned flags;
+
+    State(QueryParser::Internal * qpi_, unsigned flags_)
+	: qpi(qpi_), error(NULL), flags(flags_) { }
+
+    string stem_term(const string &term) {
+	return qpi->stemmer(term);
+    }
+
+    void add_to_stoplist(const Term * term) {
+	qpi->stoplist.push_back(term->name);
+    }
+
+    void add_to_unstem(const string & term, const string & unstemmed) {
+	qpi->unstem.insert(make_pair(term, unstemmed));
+    }
+
+    valueno value_range(Query & q, Term *a, Term *b) {
+	string start = a->name;
+	string end = b->name;
+	Xapian::valueno valno = Xapian::BAD_VALUENO;
+	list<ValueRangeProcessor *>::const_iterator i;
+	for (i = qpi->valrangeprocs.begin(); i != qpi->valrangeprocs.end(); ++i) {
+	    valno = (**i)(start, end);
+	    if (valno != Xapian::BAD_VALUENO) {
+		delete a;
+		delete b;
+		q = Query(Query::OP_VALUE_RANGE, valno, start, end);
+		return valno;
+	    }
+	}
+	// FIXME: Do we want to report an error for this?  If not we need
+	// to perform the above check in the tokeniser and if none of the
+	// ValueRangeProcessor classes like the range, we rollback to
+	// parsing the query without treating this as a range.  Needs
+	// more thought and probably a look at queries users actually
+	// enter.
+	error = "Unknown range operation";
+	return valno;
+    }
+
+    Query::op default_op() const { return qpi->default_op; }
+
+    bool is_stopword(const Term *term) const {
+	return qpi->stopper && (*qpi->stopper)(term->name);
+    }
+
+    Database get_database() const {
+	return qpi->db;
+    }
+};
+
+string
+Term::make_term(const string & prefix) const
+{
+    string term;
+    if (stem == QueryParser::STEM_SOME) term += 'Z';
+    if (!prefix.empty()) {
+	term += prefix;
+	if (prefix_needs_colon(prefix, name[0])) term += ':';
+    }
+    if (stem != QueryParser::STEM_NONE) {
+	term += state->stem_term(name);
+    } else {
+	term += name;
+    }
+
+    if (!unstemmed.empty())
+	state->add_to_unstem(term, unstemmed);
+    return term;
+}
+
+Query
+Term::get_query_with_synonyms() const
+{
+    Query q = get_query();
+
+    // Handle single-word synonyms with each prefix.
+    list<string>::const_iterator piter;
+    for (piter = prefixes.begin(); piter != prefixes.end(); ++piter) {
+	// First try the unstemmed term:
+	string term;
+	if (!piter->empty()) {
+	    term += *piter;
+	    if (prefix_needs_colon(*piter, name[0])) term += ':';
+	}
+	term += name;
+
+	Xapian::Database db = state->get_database();
+	Xapian::TermIterator syn = db.synonyms_begin(term);
+	Xapian::TermIterator end = db.synonyms_end(term);
+	if (syn == end && stem != QueryParser::STEM_NONE) {
+	    // If that has no synonyms, try the stemmed form:
+	    term = 'Z';
+	    if (!piter->empty()) {
+		term += *piter;
+		if (prefix_needs_colon(*piter, name[0])) term += ':';
+	    }
+	    term += state->stem_term(name);
+	    syn = db.synonyms_begin(term);
+	    end = db.synonyms_end(term);
+	}
+	while (syn != end) {
+	    q = Query(Query::OP_OR, q, Query(*syn, 1, pos));
+	    ++syn;
+	}
+    }
+    return q;
+}
+
+Query
+Term::get_query_with_auto_synonyms() const
+{
+    if (state->flags & QueryParser::FLAG_AUTO_SYNONYMS)
+	return get_query_with_synonyms();
+
+    return get_query();
+}
+
+static void
+add_to_query(Query *& q, Query::op op, Query * term)
+{
+    Assert(term);
+    if (q) {
+	*q = Query(op, *q, *term);
+	delete term;
+    } else {
+	q = term;
+    }
+}
+
+static void
+add_to_query(Query *& q, Query::op op, const Query & term)
+{
+    if (q) {
+	*q = Query(op, *q, term);
+    } else {
+	q = new Query(term);
+    }
+}
+
+Query
+Term::get_query() const
+{
+    Assert(prefixes.size() >= 1);
+    list<string>::const_iterator piter = prefixes.begin();
+    Query q(make_term(*piter), 1, pos);
+    while (++piter != prefixes.end()) {
+	q = Query(Query::OP_OR, q, Query(make_term(*piter), 1, pos));
+    }
+    return q;
+}
+
+Query *
+Term::as_wildcarded_query(State * state_) const
+{
+    Database db = state_->get_database();
+    Query * q = new Query;
+    list<string>::const_iterator piter;
+    for (piter = prefixes.begin(); piter != prefixes.end(); ++piter) {
+	string root = *piter;
+	root += name;
+	TermIterator t = db.allterms_begin(root);
+	while (t != db.allterms_end(root)) {
+	    add_to_query(q, Query::OP_OR, Query(*t, 1, pos));
+	    ++t;
+	}
+    }
+    delete this;
+    return q;
+}
+
+Query *
+Term::as_partial_query(State * state_) const
+{
+    Database db = state_->get_database();
+    Query * q = new Query;
+    list<string>::const_iterator piter;
+    for (piter = prefixes.begin(); piter != prefixes.end(); ++piter) {
+	string root = *piter;
+	root += name;
+	TermIterator t = db.allterms_begin(root);
+	while (t != db.allterms_end(root)) {
+	    add_to_query(q, Query::OP_OR, Query(*t, 1, pos));
+	    ++t;
+	}
+	// Add the term, as it would normally be handled, as an alternative.
+	add_to_query(q, Query::OP_OR, Query(make_term(*piter), 1, pos));
+    }
+    delete this;
+    return q;
+}
+
+inline bool
+is_phrase_generator(unsigned ch)
+{
+    // These characters generate a phrase search.
+    // Ordered mostly by frequency of calls to this function done when
+    // running queryparsertest.
+    return (ch && ch < 128 && strchr(".-/:\\@", ch) != NULL);
+}
+
+inline bool
+is_stem_preventer(unsigned ch)
+{
+    return (ch && ch < 128 && strchr("(/\\@<>=*[{\"", ch) != NULL);
+}
+
+inline bool
+should_stem(const std::string & term)
+{
+    const unsigned int SHOULD_STEM_MASK =
+	(1 << Unicode::LOWERCASE_LETTER) |
+	(1 << Unicode::TITLECASE_LETTER) |
+	(1 << Unicode::MODIFIER_LETTER) |
+	(1 << Unicode::OTHER_LETTER);
+    Utf8Iterator u(term);
+    return ((SHOULD_STEM_MASK >> Unicode::get_category(*u)) & 1);
+}
+
+inline unsigned check_infix(unsigned ch) {
+    if (ch == '\'' || ch == '&' || ch == 0xb7 || ch == 0x5f4 || ch == 0x2027) {
+	// Unicode includes all these except '&' in it's word boundary rules,
+	// as well as 0x2019 (which we handle below) and ':' (for Swedish
+	// apparently, but we ignore this for now as it's problematic in
+	// real world cases).
+	return ch;
+    }
+    // 0x2019 is Unicode apostrophe and single closing quote.
+    // 0x201b is Unicode single opening quote with the tail rising.
+    if (ch == 0x2019 || ch == 0x201b) return '\'';
+    return 0;
+}
+
+inline unsigned check_infix_digit(unsigned ch) {
+    // This list of characters comes from Unicode's word identifying algorithm.
+    switch (ch) {
+	case ',':
+	case '.':
+	case ';':
+	case 0x037e: // GREEK QUESTION MARK
+	case 0x0589: // ARMENIAN FULL STOP
+	case 0x060D: // ARABIC DATE SEPARATOR
+	case 0x07F8: // NKO COMMA
+	case 0x2044: // FRACTION SLASH
+	case 0xFE10: // PRESENTATION FORM FOR VERTICAL COMMA
+	case 0xFE13: // PRESENTATION FORM FOR VERTICAL COLON
+	case 0xFE14: // PRESENTATION FORM FOR VERTICAL SEMICOLON
+	    return ch;
+    }
+    return 0;
+}
+
+struct yyParser;
+
+// Prototype the functions lemon generates.
+static yyParser *ParseAlloc();
+static void ParseFree(yyParser *);
+static void Parse(yyParser *, int, Term *, State *);
+
+void
+QueryParser::Internal::add_prefix(const string &field, const string &prefix,
+				  bool filter)
+{
+    map<string, PrefixInfo>::iterator p = prefixmap.find(field);
+    if (p == prefixmap.end()) {
+       prefixmap.insert(make_pair(field, PrefixInfo(filter, prefix)));
+    } else {
+       // Check that this is the same type of filter as the existing one(s).
+       if (p->second.filter != filter) {
+           throw Xapian::InvalidOperationError("Can't use add_prefix() and add_bool_prefix() on the same field name");
+       }
+       p->second.prefixes.push_back(prefix);
+    }
+}
+
+string
+QueryParser::Internal::parse_term(Utf8Iterator &it, const Utf8Iterator &end,
+				  bool &was_acronym)
+{
+    string term;
+    // Look for initials separated by '.' (e.g. P.T.O., U.N.C.L.E).
+    // Don't worry if there's a trailing '.' or not.
+    if (U_isupper(*it)) {
+	string t;
+	Utf8Iterator p = it;
+	do {
+	    Unicode::append_utf8(t, *p++);
+	} while (p != end && *p == '.' && ++p != end && U_isupper(*p));
+	// One letter does not make an acronym!  If we handled a single
+	// uppercase letter here, we wouldn't catch M&S below.
+	if (t.length() > 1) {
+	    // Check there's not a (lower case) letter or digit
+	    // immediately after it.
+	    // FIXME: should I.B.M..P.T.O be a range search?
+	    if (p == end || !is_wordchar(*p)) {
+		it = p;
+		swap(term, t);
+	    }
+	}
+    }
+    was_acronym = !term.empty();
+
+    if (term.empty()) {
+	unsigned prevch = *it;
+	Unicode::append_utf8(term, prevch);
+	while (++it != end) {
+	    unsigned ch = *it;
+	    if (!is_wordchar(ch)) {
+		// Treat a single embedded '&' or "'" or similar as a word
+		// character (e.g. AT&T, Fred's).  Also, normalise
+		// apostrophes to ASCII apostrophe.
+		Utf8Iterator p = it;
+		++p;
+		if (p == end || !is_wordchar(*p)) break;
+		unsigned nextch = *p;
+		if (is_digit(prevch) &&
+		    is_digit(nextch)) {
+		    ch = check_infix_digit(ch);
+		} else {
+		    ch = check_infix(ch);
+		}
+		if (!ch) break;
+	    }
+	    Unicode::append_utf8(term, ch);
+	    prevch = ch;
+	}
+	if (it != end && is_suffix(*it)) {
+	    string suff_term = term;
+	    Utf8Iterator p = it;
+	    // Keep trailing + (e.g. C++, Na+) or # (e.g. C#).
+	    do {
+		if (suff_term.size() - term.size() == 3) {
+		    suff_term.resize(0);
+		    break;
+		}
+		suff_term += *p;
+	    } while (is_suffix(*++p));
+	    if (!suff_term.empty() && (p == end || !is_wordchar(*p))) {
+		// If the suffixed term doesn't exist, check that the
+		// non-suffixed term does.  This also takes care of
+		// the case when QueryParser::set_database() hasn't
+		// been called.
+		bool use_suff_term = false;
+		string lc = Unicode::tolower(suff_term);
+		if (db.term_exists(lc)) {
+		    use_suff_term = true;
+		} else {
+		    lc = Unicode::tolower(term);
+		    if (!db.term_exists(lc)) use_suff_term = true;
+		}
+		if (use_suff_term) {
+		    term = suff_term;
+		    it = p;
+		}
+	    }
+	}
+    }
+    return term;
+}
+
+Query
+QueryParser::Internal::parse_query(const string &qs, unsigned flags,
+				   const string &default_prefix)
+{
+    yyParser * pParser = ParseAlloc();
+
+    // Set value_ranges if we may have to handle value ranges in the query.
+    bool value_ranges;
+    value_ranges = !valrangeprocs.empty() && (qs.find("..") != string::npos);
+
+    termpos term_pos = 1;
+    Utf8Iterator it(qs), end;
+
+    State state(this, flags);
+
+    // To successfully apply more than one spelling correction to a query
+    // string, we must keep track of the offset due to previous corrections.
+    int correction_offset = 0;
+    corrected_query.resize(0);
+
+    // Stack of prefixes, used for phrases and subexpressions.
+    list<const PrefixInfo *> prefix_stack;
+
+    // If default_prefix is specified, use it.  Otherwise, use any list
+    // that has been set for the empty prefix.
+    const PrefixInfo def_pfx(false, default_prefix);
+    {
+	const PrefixInfo * default_prefixinfo = &def_pfx;
+	if (default_prefix.empty()) {
+	    map<string, PrefixInfo>::const_iterator f = prefixmap.find("");
+	    if (f != prefixmap.end()) default_prefixinfo = &(f->second);
+	}
+
+	// We always have the current prefix on the top of the stack.
+	prefix_stack.push_back(default_prefixinfo);
+    }
+
+    unsigned newprev = ' ';
+main_lex_loop:
+    enum {
+	DEFAULT, IN_QUOTES, IN_PREFIXED_QUOTES, IN_PHRASED_TERM, IN_GROUP
+    } mode = DEFAULT;
+    while (it != end) {
+	bool last_was_operator = false;
+	if (false) {
+just_had_operator:
+	    if (it == end) break;
+	    last_was_operator = true;
+	    mode = DEFAULT;
+	}
+	if (mode == IN_PHRASED_TERM) mode = DEFAULT;
+	if (is_whitespace(*it)) {
+	    newprev = ' ';
+	    ++it;
+	    it = find_if(it, end, is_not_whitespace);
+	    if (it == end) break;
+	}
+
+	if ((mode == DEFAULT || mode == IN_GROUP) && value_ranges) {
+	    // Scan forward to see if this could be the "start of range"
+	    // token.  Sadly this has O(n^2) tendencies, though at least
+	    // "n" is the number of words in a query which is likely to
+	    // remain fairly small.  FIXME: can we tokenise more elegantly?
+	    Utf8Iterator p = it;
+	    unsigned ch = 0;
+	    while (p != end) {
+		if (ch == '.' && *p == '.') {
+		    ++p;
+		    if (p == end || *p <= ' ' || *p == ')') break;
+
+		    string r;
+		    do {
+			Unicode::append_utf8(r, *it++);
+		    } while (it != p);
+		    // Trim off the trailing "..".
+		    r.resize(r.size() - 2);
+		    Parse(pParser, RANGE_START, new Term(r), &state);
+		    r.resize(0);
+		    // Allow any character except whitespace and ')' in a
+		    // RANGE_END.  Or should we be consistent with RANGE_START?
+		    do {
+			Unicode::append_utf8(r, *p++);
+		    } while (p != end && *p > ' ' && *p != ')');
+		    Parse(pParser, RANGE_END, new Term(r), &state);
+		    it = p;
+		    goto main_lex_loop;
+		}
+		ch = *p;
+		if (!(is_wordchar(ch) || is_currency(ch) ||
+		      (ch < 128 && strchr("%,-./:@", ch)))) break;
+		++p;
+	    }
+	}
+
+	if (!is_wordchar(*it)) {
+	    unsigned prev = newprev;
+	    unsigned ch = *it++;
+	    newprev = ch;
+	    // Drop out of IN_GROUP mode.
+	    if (mode == IN_GROUP) mode = DEFAULT;
+	    switch (ch) {
+	      case '"': // Quoted phrase.
+		if (mode == DEFAULT) {
+		    // Skip whitespace.
+		    it = find_if(it, end, is_not_whitespace);
+		    if (it == end) {
+			// Ignore an unmatched " at the end of the query to
+			// avoid generating an empty pair of QUOTEs which will
+			// cause a parse error.
+			goto done;
+		    }
+		    if (*it == '"') {
+			// Ignore empty "" (but only if we're not already
+			// IN_QUOTES as we don't merge two adjacent quoted
+			// phrases!)
+			newprev = *it++;
+			break;
+		    }
+		}
+		if (flags & QueryParser::FLAG_PHRASE) {
+		    Parse(pParser, QUOTE, NULL, &state);
+		    if (mode == DEFAULT) {
+			mode = IN_QUOTES;
+		    } else {
+			// Remove the prefix we pushed for this phrase.
+			if (mode == IN_PREFIXED_QUOTES)
+			    prefix_stack.pop_back();
+			mode = DEFAULT;
+		    }
+		}
+		break;
+
+	      case '+': case '-': // Loved or hated term/phrase/subexpression.
+		// Ignore + or - at the end of the query string.
+		if (it == end) goto done;
+		if (prev > ' ' && prev != '(') {
+		    // Or if not after whitespace or an open bracket.
+		    break;
+		}
+		if (is_whitespace(*it) || *it == '+' || *it == '-') {
+		    // Ignore + or - followed by a space, or further + or -.
+		    // Postfix + (such as in C++ and H+) is handled as part of
+		    // the term lexing code in parse_term().
+		    newprev = *it++;
+		    break;
+		}
+		if (mode == DEFAULT && (flags & FLAG_LOVEHATE)) {
+		    Parse(pParser, (ch == '+' ? LOVE : HATE), NULL, &state);
+		    goto just_had_operator;
+		}
+		// Need to prevent the term after a LOVE or HATE starting a
+		// term group...
+		break;
+
+	      case '(': // Bracketed subexpression.
+		// Skip whitespace.
+		it = find_if(it, end, is_not_whitespace);
+		// Ignore ( at the end of the query string.
+		if (it == end) goto done;
+		if (prev > ' ' && strchr("()+-", prev) == NULL) {
+		    // Or if not after whitespace or a bracket or '+' or '-'.
+		    break;
+		}
+		if (*it == ')') {
+		    // Ignore empty ().
+		    newprev = *it++;
+		    break;
+		}
+		if (mode == DEFAULT && (flags & FLAG_BOOLEAN)) {
+		    prefix_stack.push_back(prefix_stack.back());
+		    Parse(pParser, BRA, NULL, &state);
+		}
+		break;
+
+	      case ')': // End of bracketed subexpression.
+		if (mode == DEFAULT && (flags & FLAG_BOOLEAN)) {
+		    // Remove the prefix we pushed for the corresponding BRA.
+		    // If brackets are unmatched, it's a syntax error, but
+		    // that's no excuse to SEGV!
+		    if (prefix_stack.size() > 1) prefix_stack.pop_back();
+		    Parse(pParser, KET, NULL, &state);
+		}
+		break;
+
+	      case '~': // Synonym expansion.
+		// Ignore at the end of the query string.
+		if (it == end) goto done;
+		if (prev > ' ' && prev != '+' && prev != '-' && prev != '(') {
+		    // Or if not after whitespace, +, -, or an open bracket.
+		    break;
+		}
+		if (!is_wordchar(*it)) {
+		    // Ignore if not followed by a word character.
+		    break;
+		}
+		if (mode == DEFAULT && (flags & FLAG_SYNONYM)) {
+		    Parse(pParser, SYNONYM, NULL, &state);
+		    goto just_had_operator;
+		}
+		break;
+	    }
+	    // Skip any other characters.
+	    continue;
+	}
+
+	Assert(is_wordchar(*it));
+
+	size_t term_start_index = it.raw() - qs.data();
+
+	newprev = 'A'; // Any letter will do...
+
+	// A term, a prefix, or a boolean operator.
+	const PrefixInfo * prefixinfo = NULL;
+	if ((mode == DEFAULT || mode == IN_GROUP) && !prefixmap.empty()) {
+	    // Check for a fieldname prefix (e.g. title:historical).
+	    Utf8Iterator p = find_if(it, end, is_not_wordchar);
+	    if (p != end && *p == ':' && ++p != end && *p > ' ' && *p != ')') {
+		string field;
+		p = it;
+		while (*p != ':')
+		    Unicode::append_utf8(field, *p++);
+		map<string, PrefixInfo>::const_iterator f;
+		f = prefixmap.find(field);
+		if (f != prefixmap.end()) {
+		    // Special handling for prefixed fields, depending on the
+		    // type of the prefix.
+		    unsigned ch = *++p;
+		    prefixinfo = &(f->second);
+
+		    if (prefixinfo->filter) {
+			// Drop out of IN_GROUP if we're in it.
+			mode = DEFAULT;
+			// Can't boolean filter prefix a subexpression or
+			// phrase; just use anything following the prefix
+			// until the next space or ')' as part of the boolean
+			// filter term.
+			it = p;
+			string name;
+			while (it != end && *it > ' ' && *it != ')')
+			    Unicode::append_utf8(name, *it++);
+			// Build the unstemmed form in field.
+			field += ':';
+			field += name;
+			const list<string> & prefixes = prefixinfo->prefixes;
+			Term * token = new Term(&state, name, prefixes, field);
+			Parse(pParser, BOOLEAN_FILTER, token, &state);
+			continue;
+		    }
+
+		    if (ch == '"' && (flags & FLAG_PHRASE)) {
+			// Prefixed phrase, e.g.: subject:"space flight"
+			mode = IN_PREFIXED_QUOTES;
+			Parse(pParser, QUOTE, NULL, &state);
+			it = p;
+			newprev = ch;
+			++it;
+			prefix_stack.push_back(prefixinfo);
+			continue;
+		    }
+
+		    if (ch == '(' && (flags & FLAG_BOOLEAN)) {
+			// Prefixed subexpression, e.g.: title:(fast NEAR food)
+			mode = DEFAULT;
+			Parse(pParser, BRA, NULL, &state);
+			it = p;
+			newprev = ch;
+			++it;
+			prefix_stack.push_back(prefixinfo);
+			continue;
+		    }
+
+		    if (is_wordchar(ch)) {
+			// Prefixed term.
+			it = p;
+		    } else {
+			// It looks like a prefix but isn't, so parse it as
+			// text instead.
+			prefixinfo = NULL;
+		    }
+		}
+	    }
+	}
+
+phrased_term:
+	bool was_acronym;
+	string term = parse_term(it, end, was_acronym);
+
+	// Boolean operators.
+	if ((mode == DEFAULT || mode == IN_GROUP) &&
+	    (flags & FLAG_BOOLEAN) &&
+	    // Don't want to interpret A.N.D. as an AND operator.
+	    !was_acronym &&
+	    !prefixinfo &&
+	    term.size() >= 2 && term.size() <= 4 && U_isalpha(term[0])) {
+
+	    string op = term;
+	    if (flags & FLAG_BOOLEAN_ANY_CASE) {
+		for (string::iterator i = op.begin(); i != op.end(); ++i) {
+		    *i = C_toupper(*i);
+		}
+	    }
+	    if (op.size() == 3) {
+		if (op == "AND") {
+		    Parse(pParser, AND, NULL, &state);
+		    goto just_had_operator;
+		}
+		if (op == "NOT") {
+		    Parse(pParser, NOT, NULL, &state);
+		    goto just_had_operator;
+		}
+		if (op == "XOR") {
+		    Parse(pParser, XOR, NULL, &state);
+		    goto just_had_operator;
+		}
+		if (op == "ADJ") {
+		    if (it != end && *it == '/') {
+			size_t width = 0;
+			Utf8Iterator p = it;
+			while (++p != end && U_isdigit(*p)) {
+			    width = (width * 10) + (*p - '0');
+			}
+			if (width && (p == end || is_whitespace(*p))) {
+			    it = p;
+			    Parse(pParser, ADJ, new Term(width), &state);
+			    goto just_had_operator;
+			}
+		    }
+
+		    Parse(pParser, ADJ, NULL, &state);
+		    goto just_had_operator;
+		}
+	    } else if (op.size() == 2) {
+		if (op == "OR") {
+		    Parse(pParser, OR, NULL, &state);
+		    goto just_had_operator;
+		}
+	    } else if (op.size() == 4) {
+		if (op == "NEAR") {
+		    if (it != end && *it == '/') {
+			size_t width = 0;
+			Utf8Iterator p = it;
+			while (++p != end && U_isdigit(*p)) {
+			    width = (width * 10) + (*p - '0');
+			}
+			if (width && (p == end || is_whitespace(*p))) {
+			    it = p;
+			    Parse(pParser, NEAR, new Term(width), &state);
+			    goto just_had_operator;
+			}
+		    }
+
+		    Parse(pParser, NEAR, NULL, &state);
+		    goto just_had_operator;
+		}
+	    }
+	}
+
+	// If no prefix is set, use the default one.
+	if (!prefixinfo) prefixinfo = prefix_stack.back();
+
+	Assert(!prefixinfo->filter);
+
+	{
+	    string unstemmed_term(term);
+	    term = Unicode::tolower(term);
+
+	    // Reuse stem_strategy - STEM_SOME here means "stem terms except
+	    // when used with positional operators".
+	    stem_strategy stem_term = stem_action;
+	    if (stem_term != STEM_NONE) {
+		if (!stemmer.internal.get()) {
+		    // No stemmer is set.
+		    stem_term = STEM_NONE;
+		} else if (stem_term == STEM_SOME) {
+		    if (!should_stem(unstemmed_term) ||
+			(it != end && is_stem_preventer(*it))) {
+			// Don't stem this particular term.
+			stem_term = STEM_NONE;
+		    }
+		}
+	    }
+
+	    Term * term_obj = new Term(&state, term, prefixinfo->prefixes,
+				       unstemmed_term, stem_term, term_pos++);
+
+	    // Check spelling, if we're a normal term, and any of the prefixes
+	    // are empty.
+	    if ((flags & FLAG_SPELLING_CORRECTION) && !was_acronym) {
+		list<string>::const_iterator prefixiter;
+		for (prefixiter = prefixinfo->prefixes.begin();
+		     prefixiter != prefixinfo->prefixes.end();
+		     ++prefixiter) {
+		    if (!prefixiter->empty())
+			continue;
+		    if (!db.term_exists(term)) {
+			string suggestion = db.get_spelling_suggestion(term);
+			if (!suggestion.empty()) {
+			    if (corrected_query.empty()) corrected_query = qs;
+			    size_t term_end_index = it.raw() - qs.data();
+			    size_t n = term_end_index - term_start_index;
+			    size_t pos = term_start_index + correction_offset;
+			    corrected_query.replace(pos, n, suggestion);
+			    correction_offset += suggestion.size();
+			    correction_offset -= n;
+			}
+		    }
+		    break;
+		}
+	    }
+
+	    if (mode == IN_PHRASED_TERM) {
+		Parse(pParser, PHR_TERM, term_obj, &state);
+	    } else {
+		if (mode == DEFAULT || mode == IN_GROUP) {
+		    if (it != end) {
+			if ((flags & FLAG_WILDCARD) && *it == '*') {
+			    Utf8Iterator p(it);
+			    ++p;
+			    if (p == end || !is_wordchar(*p)) {
+				it = p;
+				// Wildcard at end of term (also known as
+				// "right truncation").
+				Parse(pParser, WILD_TERM, term_obj, &state);
+				continue;
+			    }
+			}
+		    } else {
+			if (flags & FLAG_PARTIAL) {
+			    // Final term of a partial match query, with no
+			    // following characters - treat as a wildcard.
+			    Parse(pParser, PARTIAL_TERM, term_obj, &state);
+			    continue;
+			}
+		    }
+		}
+
+		// See if the next token will be PHR_TERM - if so, this one
+		// needs to be TERM not GROUP_TERM.
+		if (mode == IN_GROUP && is_phrase_generator(*it)) {
+		    // FIXME: can we clean this up?
+		    Utf8Iterator p = it;
+		    do {
+			++p;
+		    } while (p != end && is_phrase_generator(*p));
+		    // Don't generate a phrase unless the phrase generators are
+		    // immediately followed by another term.
+		    if (p != end && is_wordchar(*p)) {
+			mode = DEFAULT;
+		    }
+		}
+
+		Parse(pParser, (mode == IN_GROUP ? GROUP_TERM : TERM),
+		      term_obj, &state);
+		if (mode != DEFAULT && mode != IN_GROUP) continue;
+	    }
+	}
+
+	if (it == end) break;
+
+	if (is_phrase_generator(*it)) {
+	    // Skip multiple phrase generators.
+	    do {
+		++it;
+	    } while (it != end && is_phrase_generator(*it));
+	    // Don't generate a phrase unless the phrase generators are
+	    // immediately followed by another term.
+	    if (it != end && is_wordchar(*it)) {
+		mode = IN_PHRASED_TERM;
+		term_start_index = it.raw() - qs.data();
+		goto phrased_term;
+	    }
+	} else if (mode == DEFAULT || mode == IN_GROUP) {
+	    mode = DEFAULT;
+	    if (!last_was_operator && is_whitespace(*it)) {
+		newprev = ' ';
+		// Skip multiple whitespace.
+		do {
+		    ++it;
+		} while (it != end && is_whitespace(*it));
+		// Don't generate a group unless the terms are only separated
+		// by whitespace.
+		if (it != end && is_wordchar(*it)) {
+		    mode = IN_GROUP;
+		}
+	    }
+	}
+    }
+done:
+    // Implicitly close any unclosed quotes...
+    if (mode == IN_QUOTES || mode == IN_PREFIXED_QUOTES)
+	Parse(pParser, QUOTE, NULL, &state);
+    Parse(pParser, 0, NULL, &state);
+    ParseFree(pParser);
+
+    errmsg = state.error;
+    return state.query;
+}
+
+struct ProbQuery {
+    Query * query;
+    Query * love;
+    Query * hate;
+    // filter is a map from prefix to a query for that prefix.  Queries with
+    // the same prefix are combined with OR, and the results of this are
+    // combined with AND to get the full filter.
+    map<filter_group_id, Query> filter;
+
+    ProbQuery() : query(0), love(0), hate(0) { }
+    ~ProbQuery() {
+	delete query;
+	delete love;
+	delete hate;
+    }
+
+    Query merge_filters() const {
+	map<filter_group_id, Query>::const_iterator i = filter.begin();
+	Assert(i != filter.end());
+	Query q = i->second;
+	while (++i != filter.end()) {
+	    q = Query(Query::OP_AND, q, i->second);
+	}
+	return q;
+    }
+};
+
+class TermGroup {
+    list<Term *> terms;
+
+  public:
+    TermGroup() { }
+
+    /// Add a Term object to this TermGroup object.
+    void add_term(Term * term) {
+	terms.push_back(term);
+    }
+
+    /// Convert to a Xapian::Query * using default_op.
+    Query * as_group(State *state) const;
+
+    /** Provide a way to explicitly delete an object of this class.  The
+     *  destructor is protected to prevent auto-variables of this type.
+     */
+    void destroy() { delete this; }
+
+  protected:
+    /** Protected destructor, so an auto-variable of this type is a
+     *  compile-time error - you must allocate this object with new.
+     */
+    ~TermGroup() {
+	list<Term*>::const_iterator i;
+	for (i = terms.begin(); i != terms.end(); ++i) {
+	    delete *i;
+	}
+    }
+};
+
+Query *
+TermGroup::as_group(State *state) const
+{
+    Query * query = NULL;
+    Query::op default_op = state->default_op();
+    if (state->flags & QueryParser::FLAG_AUTO_MULTIWORD_SYNONYMS) {
+	// Check for multi-word synonyms.
+	Database db = state->get_database();
+
+	string key;
+	list<Term*>::const_iterator begin = terms.begin();
+	list<Term*>::const_iterator i = begin;
+	while (i != terms.end()) {
+	    key.resize(0);
+	    while (i != terms.end()) {
+		if (!key.empty()) key += ' ';
+		key += (*i)->name;
+		++i;
+	    }
+	    // Greedily try to match as many consecutive words as possible.
+	    TermIterator syn, end;
+	    while (true) {
+		syn = db.synonyms_begin(key);
+		end = db.synonyms_end(key);
+		if (syn != end) break;
+		if (--i == begin) break;
+		key.resize(key.size() - (*i)->name.size() - 1);
+	    }
+	    if (i == begin) {
+		// No multi-synonym matches.
+		if (state->is_stopword(*i)) {
+		    state->add_to_stoplist(*i);
+		} else {
+		    add_to_query(query, default_op,
+				 (*i)->get_query_with_auto_synonyms());
+		}
+		begin = ++i;
+		continue;
+	    }
+
+	    Query * q = NULL;
+	    list<Term*>::const_iterator j;
+	    for (j = begin; j != i; ++j) {
+		if (state->is_stopword(*j)) {
+		    state->add_to_stoplist(*j);
+		} else {
+		    add_to_query(q, default_op, (*j)->get_query());
+		}
+	    }
+
+	    // Use the position of the first term for the synonyms.
+	    Xapian::termpos pos = (*begin)->pos;
+	    begin = i;
+	    while (syn != end) {
+		add_to_query(q, Query::OP_OR, Query(*syn, 1, pos));
+		++syn;
+	    }
+	    add_to_query(query, default_op, q);
+	}
+    } else {
+	list<Term*>::const_iterator i;
+	for (i = terms.begin(); i != terms.end(); ++i) {
+	    if (state->is_stopword(*i)) {
+		state->add_to_stoplist(*i);
+	    } else {
+		add_to_query(query, default_op,
+			     (*i)->get_query_with_auto_synonyms());
+	    }
+	}
+    }
+    delete this;
+    return query;
+}
+
+class TermList {
+    list<Term *> terms;
+    size_t window;
+
+    /** Keep track of whether the terms added all have the same list of
+     *  prefixes.  If so, we'll build a set of phrases, one using each prefix.
+     *  This works around the limitation that a phrase cannot have multiple
+     *  components which are "OR" combinations of terms, but is also probably
+     *  what users expect: ie, if a user specifies a phrase in a field, and that
+     *  field maps to multiple prefixes, the user probably wants a phrase
+     *  returned with all terms having one of those prefixes, rather than a
+     *  phrase comprised of terms with differing prefixes.
+     */
+    bool uniform_prefixes;
+
+    /** The list of prefixes of the terms added.
+     *  This will be empty if the terms have different prefixes.
+     */
+    list<string> prefixes;
+
+  public:
+    TermList() : window(0), uniform_prefixes(true) { }
+
+    /// Add an unstemmed Term object to this TermList object.
+    void add_positional_term(Term * term) {
+        if (terms.empty()) {
+	    prefixes = term->prefixes;
+	} else if (uniform_prefixes && prefixes != term->prefixes)  {
+	    prefixes.clear();
+	    uniform_prefixes = false;
+	}
+	term->need_positions();
+	terms.push_back(term);
+    }
+
+    void adjust_window(size_t alternative_window) {
+	if (alternative_window > window) window = alternative_window;
+    }
+
+    /// Convert to a query using the given operator and window size.
+    Query * as_opwindow_query(Query::op op, Xapian::termcount w_delta) const {
+	Query * q = NULL;
+	// Call terms.size() just once since std::list::size() may be O(n).
+	size_t n_terms = terms.size();
+	Xapian::termcount w = w_delta + terms.size();
+	if (uniform_prefixes) {
+	    list<string>::const_iterator piter;
+	    for (piter = prefixes.begin(); piter != prefixes.end(); ++piter) {
+		vector<Query> subqs;
+		subqs.reserve(n_terms);
+		list<Term *>::const_iterator titer;
+		for (titer = terms.begin(); titer != terms.end(); ++titer) {
+		    Term * t = *titer;
+		    subqs.push_back(Query(t->make_term(*piter), 1, t->pos));
+		}
+		add_to_query(q, Query::OP_OR,
+			     Query(op, subqs.begin(), subqs.end(), w));
+	    }
+	} else {
+	    vector<Query> subqs;
+	    subqs.reserve(n_terms);
+	    list<Term *>::const_iterator titer;
+	    for (titer = terms.begin(); titer != terms.end(); ++titer) {
+		subqs.push_back((*titer)->get_query());
+	    }
+	    q = new Query(op, subqs.begin(), subqs.end(), w);
+	}
+
+	delete this;
+	return q;
+    }
+
+    /// Convert to a Xapian::Query * using adjacent OP_PHRASE.
+    Query * as_phrase_query() const {
+	return as_opwindow_query(Query::OP_PHRASE, 0);
+    }
+
+    /// Convert to a Xapian::Query * using OP_NEAR.
+    Query * as_near_query() const {
+	// The common meaning of 'a NEAR b' is "a within 10 terms of b", which
+	// means a window size of 11.  For more than 2 terms, we just add one
+	// to the window size for each extra term.
+	size_t w = window;
+	if (w == 0) w = 10;
+	return as_opwindow_query(Query::OP_NEAR, w - 1);
+    }
+
+    /// Convert to a Xapian::Query * using OP_PHRASE to implement ADJ.
+    Query * as_adj_query() const {
+	// The common meaning of 'a ADJ b' is "a at most 10 terms before b",
+	// which means a window size of 11.  For more than 2 terms, we just add
+	// one to the window size for each extra term.
+	size_t w = window;
+	if (w == 0) w = 10;
+	return as_opwindow_query(Query::OP_PHRASE, w - 1);
+    }
+
+    /** Provide a way to explicitly delete an object of this class.  The
+     *  destructor is protected to prevent auto-variables of this type.
+     */
+    void destroy() { delete this; }
+
+  protected:
+    /** Protected destructor, so an auto-variable of this type is a
+     *  compile-time error - you must allocate this object with new.
+     */
+    ~TermList() {
+	list<Term *>::const_iterator t;
+	for (t = terms.begin(); t != terms.end(); ++t) {
+	    delete *t;
+	}
+    }
+};
+
+// Helper macro for converting a boolean operation into a Xapian::Query.
+#define BOOL_OP_TO_QUERY(E, A, OP, B, OP_TXT) \
+    do {\
+	if (!A || !B) {\
+	    state->error = "Syntax: <expression> "OP_TXT" <expression>";\
+	    yy_parse_failed(yypParser);\
+	    return;\
+	}\
+	E = new Query(OP, *A, *B);\
+	delete A;\
+	delete B;\
+    } while (0)
+
+}
+
+%token_type {Term *}
+%token_destructor {delete $$;}
+
+%extra_argument {State * state}
+
+%parse_failure {
+    // If we've not already set an error message, set a default one.
+    if (!state->error) state->error = "parse error";
+}
+
+// Operators, grouped in order of increasing precedence:
+%nonassoc ERROR.
+%left OR.
+%left XOR.
+%left AND NOT.
+%left NEAR ADJ.
+%left LOVE HATE SYNONYM.
+
+// Destructors for terminal symbols:
+
+// TERM is a query term, including prefix (if any).
+%destructor TERM {delete $$;}
+
+// GROUP_TERM is a query term which follows a TERM or another GROUP_TERM and
+// is only separated by whitespace characters.
+%destructor GROUP_TERM {delete $$;}
+
+// PHR_TERM is a query term which follows a TERM or another PHR_TERM and is
+// separated only by one or more phrase generator characters (hyphen and
+// apostrophe are common examples - see is_phrase_generator() for the list
+// of all punctuation which does this).
+%destructor PHR_TERM {delete $$;}
+
+// WILD_TERM is like a TERM, but has a trailing wildcard which needs to be
+// expanded.
+%destructor WILD_TERM {delete $$;}
+
+// PARTIAL_TERM is like a TERM, but it's at the end of the query string and
+// we're doing "search as you type".  It expands to something like WILD_TERM
+// OR stemmed_form.
+%destructor PARTIAL_TERM {delete $$;}
+
+// BOOLEAN_FILTER is a query term with a prefix registered using
+// add_bool_prefix().  It's added to the query using an OP_FILTER operator,
+// (or OP_AND_NOT if it's negated) e.g. site:xapian.org or -site:xapian.org
+%destructor BOOLEAN_FILTER {delete $$;}
+
+// Grammar rules:
+
+// query - The whole query - just an expr or nothing.
+
+// query non-terminal doesn't need a type, so just give a dummy one.
+%type query {int}
+
+query ::= expr(E). {
+    // Save the parsed query in the State structure so we can return it.
+    if (E) {
+	state->query = *E;
+	delete E;
+    } else {
+	state->query = Query();
+    }
+}
+
+query ::= . {
+    // Handle a query string with no terms in.
+    state->query = Query();
+}
+
+// expr - A query expression.
+
+%type expr {Query *}
+%destructor expr {delete $$;}
+
+expr(E) ::= prob_expr(P).
+	{ E = P; }
+
+expr(E) ::= bool_arg(A) AND bool_arg(B).
+	{ BOOL_OP_TO_QUERY(E, A, Query::OP_AND, B, "AND"); }
+
+expr(E) ::= bool_arg(A) NOT bool_arg(B). {
+    // 'NOT foo' -> '<alldocuments> NOT foo'
+    if (!A && (state->flags & QueryParser::FLAG_PURE_NOT)) {
+	A = new Query("", 1, 0);
+    }
+    BOOL_OP_TO_QUERY(E, A, Query::OP_AND_NOT, B, "NOT");
+}
+
+expr(E) ::= bool_arg(A) AND NOT bool_arg(B). [NOT]
+	{ BOOL_OP_TO_QUERY(E, A, Query::OP_AND_NOT, B, "AND NOT"); }
+
+expr(E) ::= bool_arg(A) OR bool_arg(B).
+	{ BOOL_OP_TO_QUERY(E, A, Query::OP_OR, B, "OR"); }
+
+expr(E) ::= bool_arg(A) XOR bool_arg(B).
+	{ BOOL_OP_TO_QUERY(E, A, Query::OP_XOR, B, "XOR"); }
+
+// bool_arg - an argument to a boolean operator such as AND or OR.
+
+%type bool_arg {Query *}
+%destructor bool_arg {delete $$;}
+
+bool_arg(A) ::= expr(E). { A = E; }
+
+bool_arg(A) ::= . [ERROR] {
+    // Set the argument to NULL, which enables the bool_arg-using rules in
+    // expr above to report uses of AND, OR, etc which don't have two
+    // arguments.
+    A = NULL;
+}
+
+// prob_expr - a single compound term, or a prob.
+
+%type prob_expr {Query *}
+%destructor prob_expr {delete $$;}
+
+prob_expr(E) ::= prob(P). {
+    E = P->query;
+    P->query = NULL;
+    // Handle any "+ terms".
+    if (P->love) {
+	if (P->love->empty()) {
+	    // +<nothing>.
+	    delete E;
+	    E = P->love;
+	} else if (E) {
+	    swap(E, P->love);
+	    add_to_query(E, Query::OP_AND_MAYBE, P->love);
+	} else {
+	    E = P->love;
+	}
+	P->love = NULL;
+    }
+    // Handle any boolean filters.
+    if (!P->filter.empty()) {
+	if (E) {
+	    add_to_query(E, Query::OP_FILTER, P->merge_filters());
+	} else {
+	    // Make the query a boolean one.
+	    E = new Query(Query::OP_SCALE_WEIGHT, P->merge_filters(), 0.0);
+	}
+    }
+    // Handle any "- terms".
+    if (P->hate && !P->hate->empty()) {
+	if (!E) {
+	    // Can't just hate!
+	    yy_parse_failed(yypParser);
+	    return;
+	}
+	*E = Query(Query::OP_AND_NOT, *E, *P->hate);
+    }
+    // FIXME what if E && E->empty() (all terms are stopwords)?
+    delete P;
+}
+
+prob_expr(E) ::= term(T). {
+    E = T;
+}
+
+// prob - a probabilistic sub-expression consisting of stop_terms, "+" terms,
+// "-" terms, boolean filters, and/or value ranges.
+//
+// Note: stop_term can also be several other things other than a simple term!
+
+%type prob {ProbQuery *}
+%destructor prob {delete $$;}
+
+prob(P) ::= RANGE_START(A) RANGE_END(B). {
+    Query range;
+    Xapian::valueno valno = state->value_range(range, A, B);
+    if (valno == BAD_VALUENO) {
+	yy_parse_failed(yypParser);
+	return;
+    }
+    P = new ProbQuery;
+    P->filter[filter_group_id(valno)] = range;
+}
+
+prob(P) ::= stop_prob(Q) RANGE_START(A) RANGE_END(B). {
+    Query range;
+    Xapian::valueno valno = state->value_range(range, A, B);
+    if (valno == BAD_VALUENO) {
+	yy_parse_failed(yypParser);
+	return;
+    }
+    P = Q;
+    Query & q = P->filter[filter_group_id(valno)];
+    q = Query(Query::OP_OR, q, range);
+}
+
+prob(P) ::= stop_term(T) stop_term(U). {
+    P = new ProbQuery;
+    P->query = T;
+    if (U) add_to_query(P->query, state->default_op(), U);
+}
+
+prob(P) ::= prob(Q) stop_term(T). {
+    P = Q;
+    // If T is a stopword, there's nothing to do here.
+    if (T) add_to_query(P->query, state->default_op(), T);
+}
+
+prob(P) ::= LOVE term(T). {
+    P = new ProbQuery;
+    if (state->default_op() == Query::OP_AND) {
+	P->query = T;
+    } else {
+	P->love = T;
+    }
+}
+
+prob(P) ::= stop_prob(Q) LOVE term(T). {
+    P = Q;
+    if (state->default_op() == Query::OP_AND) {
+	/* The default op is AND, so we just put loved terms into the query
+	 * (in this case the only effect of love is to ignore the stopword
+	 * list). */
+	add_to_query(P->query, Query::OP_AND, T);
+    } else {
+	add_to_query(P->love, Query::OP_AND, T);
+    }
+}
+
+prob(P) ::= HATE term(T). {
+    P = new ProbQuery;
+    P->hate = T;
+}
+
+prob(P) ::= stop_prob(Q) HATE term(T). {
+    P = Q;
+    add_to_query(P->hate, Query::OP_OR, T);
+}
+
+prob(P) ::= HATE BOOLEAN_FILTER(T). {
+    P = new ProbQuery;
+    P->hate = new Query(T->get_query());
+    delete T;
+}
+
+prob(P) ::= stop_prob(Q) HATE BOOLEAN_FILTER(T). {
+    P = Q;
+    add_to_query(P->hate, Query::OP_OR, T->get_query());
+    delete T;
+}
+
+prob(P) ::= BOOLEAN_FILTER(T). {
+    P = new ProbQuery;
+    P->filter[T->get_filter_group_id()] = T->get_query();
+    delete T;
+}
+
+prob(P) ::= stop_prob(Q) BOOLEAN_FILTER(T). {
+    P = Q;
+    // We OR filters with the same prefix...
+    Query & q = P->filter[T->get_filter_group_id()];
+    q = Query(Query::OP_OR, q, T->get_query());
+    delete T;
+}
+
+prob(P) ::= LOVE BOOLEAN_FILTER(T). {
+    // LOVE BOOLEAN_FILTER(T) is just the same as BOOLEAN_FILTER
+    P = new ProbQuery;
+    P->filter[T->get_filter_group_id()] = T->get_query();
+    delete T;
+}
+
+prob(P) ::= stop_prob(Q) LOVE BOOLEAN_FILTER(T). {
+    // LOVE BOOLEAN_FILTER(T) is just the same as BOOLEAN_FILTER
+    P = Q;
+    // We OR filters with the same prefix...
+    Query & q = P->filter[T->get_filter_group_id()];
+    q = Query(Query::OP_OR, q, T->get_query());
+    delete T;
+}
+
+// stop_prob - A prob or a stop_term.
+
+%type stop_prob {ProbQuery *}
+%destructor stop_prob {delete $$;}
+
+stop_prob(P) ::= prob(Q).
+    { P = Q; }
+
+stop_prob(P) ::= stop_term(T). {
+    P = new ProbQuery;
+    P->query = T;
+}
+
+// stop_term - A term which should be checked against the stopword list,
+// or a compound_term.
+//
+// If a term is loved, hated, or in a phrase, we don't want to consult the
+// stopword list, so stop_term isn't used there (instead term is).
+
+%type stop_term {Query *}
+%destructor stop_term {delete $$;}
+
+stop_term(T) ::= TERM(U). {
+    if (state->is_stopword(U)) {
+	T = NULL;
+	state->add_to_stoplist(U);
+    } else {
+	T = new Query(U->get_query_with_auto_synonyms());
+    }
+    delete U;
+}
+
+stop_term(T) ::= compound_term(U). {
+    T = U;
+}
+
+// term - A term or a compound_term.
+
+%type term {Query *}
+%destructor term {delete $$;}
+
+term(T) ::= TERM(U). {
+    T = new Query(U->get_query_with_auto_synonyms());
+    delete U;
+}
+
+term(T) ::= compound_term(U). {
+    T = U;
+}
+
+// compound_term - A WILD_TERM, a quoted phrase (with or without prefix), a
+// phrased_term, group, near_expr, adj_expr, or a bracketed subexpression (with
+// or without prefix).
+
+%type compound_term {Query *}
+%destructor compound_term {delete $$;}
+
+compound_term(T) ::= WILD_TERM(U).
+	{ T = U->as_wildcarded_query(state); }
+
+compound_term(T) ::= PARTIAL_TERM(U).
+	{ T = U->as_partial_query(state); }
+
+compound_term(T) ::= QUOTE phrase(P) QUOTE.
+	{ T = P->as_phrase_query(); }
+
+compound_term(T) ::= phrased_term(P).
+	{ T = P->as_phrase_query(); }
+
+compound_term(T) ::= group(P).  {
+    T = P->as_group(state);
+}
+
+compound_term(T) ::= near_expr(P).
+	{ T = P->as_near_query(); }
+
+compound_term(T) ::= adj_expr(P).
+	{ T = P->as_adj_query(); }
+
+compound_term(T) ::= BRA expr(E) KET.
+	{ T = E; }
+
+compound_term(T) ::= SYNONYM TERM(U). {
+    T = new Query(U->get_query_with_synonyms());
+    delete U;
+}
+
+// phrase - The "inside the quotes" part of a double-quoted phrase.
+
+%type phrase {TermList *}
+
+%destructor phrase {$$->destroy();}
+
+phrase(P) ::= TERM(T). {
+    P = new TermList;
+    P->add_positional_term(T);
+}
+
+phrase(P) ::= phrase(Q) TERM(T). {
+    P = Q;
+    P->add_positional_term(T);
+}
+
+// phrased_term - A phrased term works like a single term, but is actually
+// 2 or more terms linked together into a phrase by punctuation.  There must be
+// at least 2 terms in order to be able to have punctuation between the terms!
+
+%type phrased_term {TermList *}
+%destructor phrased_term {$$->destroy();}
+
+phrased_term(P) ::= TERM(T) PHR_TERM(U). {
+    P = new TermList;
+    P->add_positional_term(T);
+    P->add_positional_term(U);
+}
+
+phrased_term(P) ::= phrased_term(Q) PHR_TERM(T). {
+    P = Q;
+    P->add_positional_term(T);
+}
+
+// group - A group of terms separated only by whitespace - candidates for
+// multi-term synonyms.
+
+%type group {TermGroup *}
+%destructor group {$$->destroy();}
+
+group(P) ::= TERM(T) GROUP_TERM(U). {
+    P = new TermGroup;
+    P->add_term(T);
+    P->add_term(U);
+}
+
+group(P) ::= group(Q) GROUP_TERM(T). {
+    P = Q;
+    P->add_term(T);
+}
+
+// near_expr - 2 or more terms with NEAR in between.  There must be at least 2
+// terms in order for there to be any NEAR operators!
+
+%type near_expr {TermList *}
+%destructor near_expr {$$->destroy();}
+
+near_expr(P) ::= TERM(T) NEAR(N) TERM(U). {
+    P = new TermList;
+    P->add_positional_term(T);
+    P->add_positional_term(U);
+    if (N) {
+	P->adjust_window(N->get_termpos());
+	delete N;
+    }
+}
+
+near_expr(P) ::= near_expr(Q) NEAR(N) TERM(T). {
+    P = Q;
+    P->add_positional_term(T);
+    if (N) {
+	P->adjust_window(N->get_termpos());
+	delete N;
+    }
+}
+
+// adj_expr - 2 or more terms with ADJ in between.  There must be at least 2
+// terms in order for there to be any ADJ operators!
+
+%type adj_expr {TermList *}
+%destructor adj_expr {$$->destroy();}
+
+adj_expr(P) ::= TERM(T) ADJ(N) TERM(U). {
+    P = new TermList;
+    P->add_positional_term(T);
+    P->add_positional_term(U);
+    if (N) {
+	P->adjust_window(N->get_termpos());
+	delete N;
+    }
+}
+
+adj_expr(P) ::= adj_expr(Q) ADJ(N) TERM(T). {
+    P = Q;
+    P->add_positional_term(T);
+    if (N) {
+	P->adjust_window(N->get_termpos());
+	delete N;
+    }
+}
+
+// Select yacc syntax highlighting in vim editor: vim: syntax=yacc
+// (lemon syntax colouring isn't supplied by default; yacc does an OK job).

Added: test-suite/trunk/MultiSource/Applications/sqlite3/Makefile
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/sqlite3/Makefile?rev=48828&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/sqlite3/Makefile (added)
+++ test-suite/trunk/MultiSource/Applications/sqlite3/Makefile Wed Mar 26 12:03:57 2008
@@ -0,0 +1,26 @@
+LEVEL = ../../../
+#RUN_OPTIONS     = 
+
+Source = sqlite3.c shell.c
+
+PROG = sqlite3
+CPPFLAGS += -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_DLFCN_H=0 -DHAVE_FDATASYNC=0 -DHAVE_USLEEP=0 -DHAVE_LOCALTIME_R=0 -DHAVE_GMTIME_R=0 -DHAVE_READLINE=0 -I. -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION=1
+LDFLAGS =
+STDIN_FILENAME = commands
+RUN_OPTIONS = :memory: >/dev/null
+
+include $(LEVEL)/Makefile.config
+
+include ../../Makefile.multisrc
+#compare debug output
+DIFFPROG := $(PROGDIR)/DiffOutput.sh "diff "
+
+# the input files are generated from a tcl script
+# it needs to be generated before sqlite is run
+sqlite3.c: test15.sql 
+
+test15.sql: speedtest.tcl
+	$(TCLSH) speedtest.tcl
+
+clean::
+	rm -f test*.sql

Added: test-suite/trunk/MultiSource/Applications/sqlite3/README
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/sqlite3/README?rev=48828&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/sqlite3/README (added)
+++ test-suite/trunk/MultiSource/Applications/sqlite3/README Wed Mar 26 12:03:57 2008
@@ -0,0 +1,34 @@
+This directory contains source code to 
+
+    SQLite: An Embeddable SQL Database Engine
+
+To compile the project, first create a directory in which to place
+the build products.  It is recommended, but not required, that the
+build directory be separate from the source directory.  Cd into the
+build directory and then from the build directory run the configure
+script found at the root of the source tree.  Then run "make".
+
+For example:
+
+    tar xzf sqlite.tar.gz    ;#  Unpack the source tree into "sqlite"
+    mkdir bld                ;#  Build will occur in a sibling directory
+    cd bld                   ;#  Change to the build directory
+    ../sqlite/configure      ;#  Run the configure script
+    make                     ;#  Run the makefile.
+    make install             ;#  (Optional) Install the build products
+
+The configure script uses autoconf 2.61 and libtool.  If the configure
+script does not work out for you, there is a generic makefile named
+"Makefile.linux-gcc" in the top directory of the source tree that you
+can copy and edit to suit your needs.  Comments on the generic makefile
+show what changes are needed.
+
+The linux binaries on the website are created using the generic makefile,
+not the configure script.
+The windows binaries on the website are created using MinGW32 configured
+as a cross-compiler running under Linux.  For details, see the ./publish.sh
+script at the top-level of the source tree.
+
+Contacts:
+
+   http://www.sqlite.org/

Added: test-suite/trunk/MultiSource/Applications/sqlite3/VERSION
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/sqlite3/VERSION?rev=48828&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/sqlite3/VERSION (added)
+++ test-suite/trunk/MultiSource/Applications/sqlite3/VERSION Wed Mar 26 12:03:57 2008
@@ -0,0 +1 @@
+3.5.7

Added: test-suite/trunk/MultiSource/Applications/sqlite3/commands
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/sqlite3/commands?rev=48828&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/sqlite3/commands (added)
+++ test-suite/trunk/MultiSource/Applications/sqlite3/commands Wed Mar 26 12:03:57 2008
@@ -0,0 +1,15 @@
+.read test1.sql
+.read test2.sql
+.read test3.sql
+.read test4.sql
+.read test5.sql
+.read test6.sql
+.read test7.sql
+.read test8.sql
+.read test9.sql
+.read test10.sql
+.read test11.sql
+.read test12.sql
+.read test13.sql
+.read test14.sql
+.read test15.sql

Added: test-suite/trunk/MultiSource/Applications/sqlite3/copyright-release.html
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/sqlite3/copyright-release.html?rev=48828&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/sqlite3/copyright-release.html (added)
+++ test-suite/trunk/MultiSource/Applications/sqlite3/copyright-release.html Wed Mar 26 12:03:57 2008
@@ -0,0 +1,109 @@
+<html>
+<body bgcolor="white">
+<h1 align="center">
+Copyright Release for<br>
+Contributions To SQLite
+</h1>
+
+<p>
+SQLite is software that implements an embeddable SQL database engine.
+SQLite is available for free download from http://www.sqlite.org/.
+The principal author and maintainer of SQLite has disclaimed all
+copyright interest in his contributions to SQLite
+and thus released his contributions into the public domain.
+In order to keep the SQLite software unencumbered by copyright
+claims, the principal author asks others who may from time to
+time contribute changes and enhancements to likewise disclaim
+their own individual copyright interest.
+</p>
+
+<p>
+Because the SQLite software found at http://www.sqlite.org/ is in the
+public domain, anyone is free to download the SQLite software
+from that website, make changes to the software, use, distribute,
+or sell the modified software, under either the original name or
+under some new name, without any need to obtain permission, pay
+royalties, acknowledge the original source of the software, or
+in any other way compensate, identify, or notify the original authors.  
+Nobody is in any way compelled to contribute their SQLite changes and 
+enhancements back to the SQLite website.  This document concerns
+only changes and enhancements to SQLite that are intentionally and
+deliberately contributed back to the SQLite website.  
+</p>
+
+<p>
+For the purposes of this document, "SQLite software" shall mean any
+computer source code, documentation, makefiles, test scripts, or
+other information that is published on the SQLite website, 
+http://www.sqlite.org/.  Precompiled binaries are excluded from
+the definition of "SQLite software" in this document because the
+process of compiling the software may introduce information from
+outside sources which is not properly a part of SQLite.
+</p>
+
+<p>
+The header comments on the SQLite source files exhort the reader to
+share freely and to never take more than one gives.
+In the spirit of that exhortation I make the following declarations:
+</p>
+
+<ol>
+<li><p>
+I dedicate to the public domain 
+any and all copyright interest in the SQLite software that
+was publicly available on the SQLite website (http://www.sqlite.org/) prior
+to the date of the signature below and any changes or enhancements to
+the SQLite software 
+that I may cause to be published on that website in the future.
+I make this dedication for the benefit of the public at large and
+to the detriment of my heirs and successors.  I intend this
+dedication to be an overt act of relinquishment in perpetuity of
+all present and future rights to the SQLite software under copyright
+law.
+</p></li>
+
+<li><p>
+To the best of my knowledge and belief, the changes and enhancements that
+I have contributed to SQLite are either originally written by me
+or are derived from prior works which I have verified are also
+in the public domain and are not subject to claims of copyright
+by other parties.
+</p></li>
+
+<li><p>
+To the best of my knowledge and belief, no individual, business, organization,
+government, or other entity has any copyright interest
+in the SQLite software as it existed on the
+SQLite website as of the date on the signature line below.
+</p></li>
+
+<li><p>
+I agree never to publish any additional information
+to the SQLite website (by CVS, email, scp, FTP, or any other means) unless
+that information is an original work of authorship by me or is derived from 
+prior published versions of SQLite.
+I agree never to copy and paste code into the SQLite code base from
+other sources.
+I agree never to publish on the SQLite website any information that
+would violate a law or breach a contract.
+</p></li>
+</ol>
+
+<p>
+<table width="100%" cellpadding="0" cellspacing="0">
+<tr>
+<td width="60%" valign="top">
+Signature:
+<p> </p>
+<p> </p>
+<p> </p>
+</td><td valign="top" align="left">
+Date:
+</td></tr>
+<td colspan=2>
+Name (printed):
+</td>
+</tr>
+</table>
+</body>
+</html>

Added: test-suite/trunk/MultiSource/Applications/sqlite3/shell.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/sqlite3/shell.c?rev=48828&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/sqlite3/shell.c (added)
+++ test-suite/trunk/MultiSource/Applications/sqlite3/shell.c Wed Mar 26 12:03:57 2008
@@ -0,0 +1,2087 @@
+/*
+** 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 code to implement the "sqlite" command line
+** utility for accessing SQLite databases.
+**
+** $Id: shell.c,v 1.174 2008/01/21 16:22:46 drh Exp $
+*/
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include "sqlite3.h"
+#include <ctype.h>
+#include <stdarg.h>
+
+#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__)
+# include <signal.h>
+# include <pwd.h>
+# include <unistd.h>
+# include <sys/types.h>
+#endif
+
+#ifdef __OS2__
+# include <unistd.h>
+#endif
+
+#if defined(HAVE_READLINE) && HAVE_READLINE==1
+# include <readline/readline.h>
+# include <readline/history.h>
+#else
+# define readline(p) local_getline(p,stdin)
+# define add_history(X)
+# define read_history(X)
+# define write_history(X)
+# define stifle_history(X)
+#endif
+
+#if defined(_WIN32) || defined(WIN32)
+# include <io.h>
+#else
+/* Make sure isatty() has a prototype.
+*/
+extern int isatty();
+#endif
+
+#if defined(_WIN32_WCE)
+/* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty()
+ * thus we always assume that we have a console. That can be
+ * overridden with the -batch command line option.
+ */
+#define isatty(x) 1
+#endif
+
+#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__)
+#include <sys/time.h>
+#include <sys/resource.h>
+
+/* Saved resource information for the beginning of an operation */
+static struct rusage sBegin;
+
+/* True if the timer is enabled */
+static int enableTimer = 0;
+
+/*
+** Begin timing an operation
+*/
+static void beginTimer(void){
+  if( enableTimer ){
+    getrusage(RUSAGE_SELF, &sBegin);
+  }
+}
+
+/* Return the difference of two time_structs in microseconds */
+static int timeDiff(struct timeval *pStart, struct timeval *pEnd){
+  return (pEnd->tv_usec - pStart->tv_usec) + 
+         1000000*(pEnd->tv_sec - pStart->tv_sec);
+}
+
+/*
+** Print the timing results.
+*/
+static void endTimer(void){
+  if( enableTimer ){
+    struct rusage sEnd;
+    getrusage(RUSAGE_SELF, &sEnd);
+    printf("CPU Time: user %f sys %f\n",
+       0.000001*timeDiff(&sBegin.ru_utime, &sEnd.ru_utime),
+       0.000001*timeDiff(&sBegin.ru_stime, &sEnd.ru_stime));
+  }
+}
+#define BEGIN_TIMER beginTimer()
+#define END_TIMER endTimer()
+#define HAS_TIMER 1
+#else
+#define BEGIN_TIMER 
+#define END_TIMER
+#define HAS_TIMER 0
+#endif
+
+
+/*
+** If the following flag is set, then command execution stops
+** at an error if we are not interactive.
+*/
+static int bail_on_error = 0;
+
+/*
+** Threat stdin as an interactive input if the following variable
+** is true.  Otherwise, assume stdin is connected to a file or pipe.
+*/
+static int stdin_is_interactive = 1;
+
+/*
+** The following is the open SQLite database.  We make a pointer
+** to this database a static variable so that it can be accessed
+** by the SIGINT handler to interrupt database processing.
+*/
+static sqlite3 *db = 0;
+
+/*
+** True if an interrupt (Control-C) has been received.
+*/
+static volatile int seenInterrupt = 0;
+
+/*
+** This is the name of our program. It is set in main(), used
+** in a number of other places, mostly for error messages.
+*/
+static char *Argv0;
+
+/*
+** Prompt strings. Initialized in main. Settable with
+**   .prompt main continue
+*/
+static char mainPrompt[20];     /* First line prompt. default: "sqlite> "*/
+static char continuePrompt[20]; /* Continuation prompt. default: "   ...> " */
+
+/*
+** Write I/O traces to the following stream.
+*/
+#ifdef SQLITE_ENABLE_IOTRACE
+static FILE *iotrace = 0;
+#endif
+
+/*
+** This routine works like printf in that its first argument is a
+** format string and subsequent arguments are values to be substituted
+** in place of % fields.  The result of formatting this string
+** is written to iotrace.
+*/
+#ifdef SQLITE_ENABLE_IOTRACE
+static void iotracePrintf(const char *zFormat, ...){
+  va_list ap;
+  char *z;
+  if( iotrace==0 ) return;
+  va_start(ap, zFormat);
+  z = sqlite3_vmprintf(zFormat, ap);
+  va_end(ap);
+  fprintf(iotrace, "%s", z);
+  sqlite3_free(z);
+}
+#endif
+
+
+/*
+** Determines if a string is a number of not.
+*/
+static int isNumber(const char *z, int *realnum){
+  if( *z=='-' || *z=='+' ) z++;
+  if( !isdigit(*z) ){
+    return 0;
+  }
+  z++;
+  if( realnum ) *realnum = 0;
+  while( isdigit(*z) ){ z++; }
+  if( *z=='.' ){
+    z++;
+    if( !isdigit(*z) ) return 0;
+    while( isdigit(*z) ){ z++; }
+    if( realnum ) *realnum = 1;
+  }
+  if( *z=='e' || *z=='E' ){
+    z++;
+    if( *z=='+' || *z=='-' ) z++;
+    if( !isdigit(*z) ) return 0;
+    while( isdigit(*z) ){ z++; }
+    if( realnum ) *realnum = 1;
+  }
+  return *z==0;
+}
+
+/*
+** A global char* and an SQL function to access its current value 
+** from within an SQL statement. This program used to use the 
+** sqlite_exec_printf() API to substitue a string into an SQL statement.
+** The correct way to do this with sqlite3 is to use the bind API, but
+** since the shell is built around the callback paradigm it would be a lot
+** of work. Instead just use this hack, which is quite harmless.
+*/
+static const char *zShellStatic = 0;
+static void shellstaticFunc(
+  sqlite3_context *context,
+  int argc,
+  sqlite3_value **argv
+){
+  assert( 0==argc );
+  assert( zShellStatic );
+  sqlite3_result_text(context, zShellStatic, -1, SQLITE_STATIC);
+}
+
+
+/*
+** This routine reads a line of text from FILE in, stores
+** the text in memory obtained from malloc() and returns a pointer
+** to the text.  NULL is returned at end of file, or if malloc()
+** fails.
+**
+** The interface is like "readline" but no command-line editing
+** is done.
+*/
+static char *local_getline(char *zPrompt, FILE *in){
+  char *zLine;
+  int nLine;
+  int n;
+  int eol;
+
+  if( zPrompt && *zPrompt ){
+    printf("%s",zPrompt);
+    fflush(stdout);
+  }
+  nLine = 100;
+  zLine = malloc( nLine );
+  if( zLine==0 ) return 0;
+  n = 0;
+  eol = 0;
+  while( !eol ){
+    if( n+100>nLine ){
+      nLine = nLine*2 + 100;
+      zLine = realloc(zLine, nLine);
+      if( zLine==0 ) return 0;
+    }
+    if( fgets(&zLine[n], nLine - n, in)==0 ){
+      if( n==0 ){
+        free(zLine);
+        return 0;
+      }
+      zLine[n] = 0;
+      eol = 1;
+      break;
+    }
+    while( zLine[n] ){ n++; }
+    if( n>0 && zLine[n-1]=='\n' ){
+      n--;
+      zLine[n] = 0;
+      eol = 1;
+    }
+  }
+  zLine = realloc( zLine, n+1 );
+  return zLine;
+}
+
+/*
+** Retrieve a single line of input text.
+**
+** zPrior is a string of prior text retrieved.  If not the empty
+** string, then issue a continuation prompt.
+*/
+static char *one_input_line(const char *zPrior, FILE *in){
+  char *zPrompt;
+  char *zResult;
+  if( in!=0 ){
+    return local_getline(0, in);
+  }
+  if( zPrior && zPrior[0] ){
+    zPrompt = continuePrompt;
+  }else{
+    zPrompt = mainPrompt;
+  }
+  zResult = readline(zPrompt);
+#if defined(HAVE_READLINE) && HAVE_READLINE==1
+  if( zResult && *zResult ) add_history(zResult);
+#endif
+  return zResult;
+}
+
+struct previous_mode_data {
+  int valid;        /* Is there legit data in here? */
+  int mode;
+  int showHeader;
+  int colWidth[100];
+};
+
+/*
+** An pointer to an instance of this structure is passed from
+** the main program to the callback.  This is used to communicate
+** state and mode information.
+*/
+struct callback_data {
+  sqlite3 *db;            /* The database */
+  int echoOn;            /* True to echo input commands */
+  int cnt;               /* Number of records displayed so far */
+  FILE *out;             /* Write results here */
+  int mode;              /* An output mode setting */
+  int writableSchema;    /* True if PRAGMA writable_schema=ON */
+  int showHeader;        /* True to show column names in List or Column mode */
+  char *zDestTable;      /* Name of destination table when MODE_Insert */
+  char separator[20];    /* Separator character for MODE_List */
+  int colWidth[100];     /* Requested width of each column when in column mode*/
+  int actualWidth[100];  /* Actual width of each column */
+  char nullvalue[20];    /* The text to print when a NULL comes back from
+                         ** the database */
+  struct previous_mode_data explainPrev;
+                         /* Holds the mode information just before
+                         ** .explain ON */
+  char outfile[FILENAME_MAX]; /* Filename for *out */
+  const char *zDbFilename;    /* name of the database file */
+};
+
+/*
+** These are the allowed modes.
+*/
+#define MODE_Line     0  /* One column per line.  Blank line between records */
+#define MODE_Column   1  /* One record per line in neat columns */
+#define MODE_List     2  /* One record per line with a separator */
+#define MODE_Semi     3  /* Same as MODE_List but append ";" to each line */
+#define MODE_Html     4  /* Generate an XHTML table */
+#define MODE_Insert   5  /* Generate SQL "insert" statements */
+#define MODE_Tcl      6  /* Generate ANSI-C or TCL quoted elements */
+#define MODE_Csv      7  /* Quote strings, numbers are plain */
+#define MODE_NUM_OF   8  /* The number of modes (not a mode itself) */
+#define MODE_Explain  9  /* Like MODE_Column, but do not truncate data */
+
+static const char *modeDescr[MODE_NUM_OF] = {
+  "line",
+  "column",
+  "list",
+  "semi",
+  "html",
+  "insert",
+  "tcl",
+  "csv",
+};
+
+/*
+** Number of elements in an array
+*/
+#define ArraySize(X)  (sizeof(X)/sizeof(X[0]))
+
+/*
+** Output the given string as a quoted string using SQL quoting conventions.
+*/
+static void output_quoted_string(FILE *out, const char *z){
+  int i;
+  int nSingle = 0;
+  for(i=0; z[i]; i++){
+    if( z[i]=='\'' ) nSingle++;
+  }
+  if( nSingle==0 ){
+    fprintf(out,"'%s'",z);
+  }else{
+    fprintf(out,"'");
+    while( *z ){
+      for(i=0; z[i] && z[i]!='\''; i++){}
+      if( i==0 ){
+        fprintf(out,"''");
+        z++;
+      }else if( z[i]=='\'' ){
+        fprintf(out,"%.*s''",i,z);
+        z += i+1;
+      }else{
+        fprintf(out,"%s",z);
+        break;
+      }
+    }
+    fprintf(out,"'");
+  }
+}
+
+/*
+** Output the given string as a quoted according to C or TCL quoting rules.
+*/
+static void output_c_string(FILE *out, const char *z){
+  unsigned int c;
+  fputc('"', out);
+  while( (c = *(z++))!=0 ){
+    if( c=='\\' ){
+      fputc(c, out);
+      fputc(c, out);
+    }else if( c=='\t' ){
+      fputc('\\', out);
+      fputc('t', out);
+    }else if( c=='\n' ){
+      fputc('\\', out);
+      fputc('n', out);
+    }else if( c=='\r' ){
+      fputc('\\', out);
+      fputc('r', out);
+    }else if( !isprint(c) ){
+      fprintf(out, "\\%03o", c&0xff);
+    }else{
+      fputc(c, out);
+    }
+  }
+  fputc('"', out);
+}
+
+/*
+** Output the given string with characters that are special to
+** HTML escaped.
+*/
+static void output_html_string(FILE *out, const char *z){
+  int i;
+  while( *z ){
+    for(i=0; z[i] && z[i]!='<' && z[i]!='&'; i++){}
+    if( i>0 ){
+      fprintf(out,"%.*s",i,z);
+    }
+    if( z[i]=='<' ){
+      fprintf(out,"<");
+    }else if( z[i]=='&' ){
+      fprintf(out,"&");
+    }else{
+      break;
+    }
+    z += i + 1;
+  }
+}
+
+/*
+** If a field contains any character identified by a 1 in the following
+** array, then the string must be quoted for CSV.
+*/
+static const char needCsvQuote[] = {
+  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
+  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
+  1, 0, 1, 0, 0, 0, 0, 1,   0, 0, 0, 0, 0, 0, 0, 0, 
+  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0, 
+  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0, 
+  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0, 
+  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0, 
+  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 1, 
+  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
+  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
+  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
+  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
+  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
+  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
+  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
+  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
+};
+
+/*
+** Output a single term of CSV.  Actually, p->separator is used for
+** the separator, which may or may not be a comma.  p->nullvalue is
+** the null value.  Strings are quoted using ANSI-C rules.  Numbers
+** appear outside of quotes.
+*/
+static void output_csv(struct callback_data *p, const char *z, int bSep){
+  FILE *out = p->out;
+  if( z==0 ){
+    fprintf(out,"%s",p->nullvalue);
+  }else{
+    int i;
+    int nSep = strlen(p->separator);
+    for(i=0; z[i]; i++){
+      if( needCsvQuote[((unsigned char*)z)[i]] 
+         || (z[i]==p->separator[0] && 
+             (nSep==1 || memcmp(z, p->separator, nSep)==0)) ){
+        i = 0;
+        break;
+      }
+    }
+    if( i==0 ){
+      putc('"', out);
+      for(i=0; z[i]; i++){
+        if( z[i]=='"' ) putc('"', out);
+        putc(z[i], out);
+      }
+      putc('"', out);
+    }else{
+      fprintf(out, "%s", z);
+    }
+  }
+  if( bSep ){
+    fprintf(p->out, "%s", p->separator);
+  }
+}
+
+#ifdef SIGINT
+/*
+** This routine runs when the user presses Ctrl-C
+*/
+static void interrupt_handler(int NotUsed){
+  seenInterrupt = 1;
+  if( db ) sqlite3_interrupt(db);
+}
+#endif
+
+/*
+** This is the callback routine that the SQLite library
+** invokes for each row of a query result.
+*/
+static int callback(void *pArg, int nArg, char **azArg, char **azCol){
+  int i;
+  struct callback_data *p = (struct callback_data*)pArg;
+  switch( p->mode ){
+    case MODE_Line: {
+      int w = 5;
+      if( azArg==0 ) break;
+      for(i=0; i<nArg; i++){
+        int len = strlen(azCol[i] ? azCol[i] : "");
+        if( len>w ) w = len;
+      }
+      if( p->cnt++>0 ) fprintf(p->out,"\n");
+      for(i=0; i<nArg; i++){
+        fprintf(p->out,"%*s = %s\n", w, azCol[i],
+                azArg[i] ? azArg[i] : p->nullvalue);
+      }
+      break;
+    }
+    case MODE_Explain:
+    case MODE_Column: {
+      if( p->cnt++==0 ){
+        for(i=0; i<nArg; i++){
+          int w, n;
+          if( i<ArraySize(p->colWidth) ){
+            w = p->colWidth[i];
+          }else{
+            w = 0;
+          }
+          if( w<=0 ){
+            w = strlen(azCol[i] ? azCol[i] : "");
+            if( w<10 ) w = 10;
+            n = strlen(azArg && azArg[i] ? azArg[i] : p->nullvalue);
+            if( w<n ) w = n;
+          }
+          if( i<ArraySize(p->actualWidth) ){
+            p->actualWidth[i] = w;
+          }
+          if( p->showHeader ){
+            fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": "  ");
+          }
+        }
+        if( p->showHeader ){
+          for(i=0; i<nArg; i++){
+            int w;
+            if( i<ArraySize(p->actualWidth) ){
+               w = p->actualWidth[i];
+            }else{
+               w = 10;
+            }
+            fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------"
+                   "----------------------------------------------------------",
+                    i==nArg-1 ? "\n": "  ");
+          }
+        }
+      }
+      if( azArg==0 ) break;
+      for(i=0; i<nArg; i++){
+        int w;
+        if( i<ArraySize(p->actualWidth) ){
+           w = p->actualWidth[i];
+        }else{
+           w = 10;
+        }
+        if( p->mode==MODE_Explain && azArg[i] && strlen(azArg[i])>w ){
+          w = strlen(azArg[i]);
+        }
+        fprintf(p->out,"%-*.*s%s",w,w,
+            azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": "  ");
+      }
+      break;
+    }
+    case MODE_Semi:
+    case MODE_List: {
+      if( p->cnt++==0 && p->showHeader ){
+        for(i=0; i<nArg; i++){
+          fprintf(p->out,"%s%s",azCol[i], i==nArg-1 ? "\n" : p->separator);
+        }
+      }
+      if( azArg==0 ) break;
+      for(i=0; i<nArg; i++){
+        char *z = azArg[i];
+        if( z==0 ) z = p->nullvalue;
+        fprintf(p->out, "%s", z);
+        if( i<nArg-1 ){
+          fprintf(p->out, "%s", p->separator);
+        }else if( p->mode==MODE_Semi ){
+          fprintf(p->out, ";\n");
+        }else{
+          fprintf(p->out, "\n");
+        }
+      }
+      break;
+    }
+    case MODE_Html: {
+      if( p->cnt++==0 && p->showHeader ){
+        fprintf(p->out,"<TR>");
+        for(i=0; i<nArg; i++){
+          fprintf(p->out,"<TH>%s</TH>",azCol[i]);
+        }
+        fprintf(p->out,"</TR>\n");
+      }
+      if( azArg==0 ) break;
+      fprintf(p->out,"<TR>");
+      for(i=0; i<nArg; i++){
+        fprintf(p->out,"<TD>");
+        output_html_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
+        fprintf(p->out,"</TD>\n");
+      }
+      fprintf(p->out,"</TR>\n");
+      break;
+    }
+    case MODE_Tcl: {
+      if( p->cnt++==0 && p->showHeader ){
+        for(i=0; i<nArg; i++){
+          output_c_string(p->out,azCol[i] ? azCol[i] : "");
+          fprintf(p->out, "%s", p->separator);
+        }
+        fprintf(p->out,"\n");
+      }
+      if( azArg==0 ) break;
+      for(i=0; i<nArg; i++){
+        output_c_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
+        fprintf(p->out, "%s", p->separator);
+      }
+      fprintf(p->out,"\n");
+      break;
+    }
+    case MODE_Csv: {
+      if( p->cnt++==0 && p->showHeader ){
+        for(i=0; i<nArg; i++){
+          output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
+        }
+        fprintf(p->out,"\n");
+      }
+      if( azArg==0 ) break;
+      for(i=0; i<nArg; i++){
+        output_csv(p, azArg[i], i<nArg-1);
+      }
+      fprintf(p->out,"\n");
+      break;
+    }
+    case MODE_Insert: {
+      if( azArg==0 ) break;
+      fprintf(p->out,"INSERT INTO %s VALUES(",p->zDestTable);
+      for(i=0; i<nArg; i++){
+        char *zSep = i>0 ? ",": "";
+        if( azArg[i]==0 ){
+          fprintf(p->out,"%sNULL",zSep);
+        }else if( isNumber(azArg[i], 0) ){
+          fprintf(p->out,"%s%s",zSep, azArg[i]);
+        }else{
+          if( zSep[0] ) fprintf(p->out,"%s",zSep);
+          output_quoted_string(p->out, azArg[i]);
+        }
+      }
+      fprintf(p->out,");\n");
+      break;
+    }
+  }
+  return 0;
+}
+
+/*
+** Set the destination table field of the callback_data structure to
+** the name of the table given.  Escape any quote characters in the
+** table name.
+*/
+static void set_table_name(struct callback_data *p, const char *zName){
+  int i, n;
+  int needQuote;
+  char *z;
+
+  if( p->zDestTable ){
+    free(p->zDestTable);
+    p->zDestTable = 0;
+  }
+  if( zName==0 ) return;
+  needQuote = !isalpha((unsigned char)*zName) && *zName!='_';
+  for(i=n=0; zName[i]; i++, n++){
+    if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ){
+      needQuote = 1;
+      if( zName[i]=='\'' ) n++;
+    }
+  }
+  if( needQuote ) n += 2;
+  z = p->zDestTable = malloc( n+1 );
+  if( z==0 ){
+    fprintf(stderr,"Out of memory!\n");
+    exit(1);
+  }
+  n = 0;
+  if( needQuote ) z[n++] = '\'';
+  for(i=0; zName[i]; i++){
+    z[n++] = zName[i];
+    if( zName[i]=='\'' ) z[n++] = '\'';
+  }
+  if( needQuote ) z[n++] = '\'';
+  z[n] = 0;
+}
+
+/* zIn is either a pointer to a NULL-terminated string in memory obtained
+** from malloc(), or a NULL pointer. The string pointed to by zAppend is
+** added to zIn, and the result returned in memory obtained from malloc().
+** zIn, if it was not NULL, is freed.
+**
+** If the third argument, quote, is not '\0', then it is used as a 
+** quote character for zAppend.
+*/
+static char *appendText(char *zIn, char const *zAppend, char quote){
+  int len;
+  int i;
+  int nAppend = strlen(zAppend);
+  int nIn = (zIn?strlen(zIn):0);
+
+  len = nAppend+nIn+1;
+  if( quote ){
+    len += 2;
+    for(i=0; i<nAppend; i++){
+      if( zAppend[i]==quote ) len++;
+    }
+  }
+
+  zIn = (char *)realloc(zIn, len);
+  if( !zIn ){
+    return 0;
+  }
+
+  if( quote ){
+    char *zCsr = &zIn[nIn];
+    *zCsr++ = quote;
+    for(i=0; i<nAppend; i++){
+      *zCsr++ = zAppend[i];
+      if( zAppend[i]==quote ) *zCsr++ = quote;
+    }
+    *zCsr++ = quote;
+    *zCsr++ = '\0';
+    assert( (zCsr-zIn)==len );
+  }else{
+    memcpy(&zIn[nIn], zAppend, nAppend);
+    zIn[len-1] = '\0';
+  }
+
+  return zIn;
+}
+
+
+/*
+** Execute a query statement that has a single result column.  Print
+** that result column on a line by itself with a semicolon terminator.
+**
+** This is used, for example, to show the schema of the database by
+** querying the SQLITE_MASTER table.
+*/
+static int run_table_dump_query(FILE *out, sqlite3 *db, const char *zSelect){
+  sqlite3_stmt *pSelect;
+  int rc;
+  rc = sqlite3_prepare(db, zSelect, -1, &pSelect, 0);
+  if( rc!=SQLITE_OK || !pSelect ){
+    return rc;
+  }
+  rc = sqlite3_step(pSelect);
+  while( rc==SQLITE_ROW ){
+    fprintf(out, "%s;\n", sqlite3_column_text(pSelect, 0));
+    rc = sqlite3_step(pSelect);
+  }
+  return sqlite3_finalize(pSelect);
+}
+
+
+/*
+** This is a different callback routine used for dumping the database.
+** Each row received by this callback consists of a table name,
+** the table type ("index" or "table") and SQL to create the table.
+** This routine should print text sufficient to recreate the table.
+*/
+static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
+  int rc;
+  const char *zTable;
+  const char *zType;
+  const char *zSql;
+  struct callback_data *p = (struct callback_data *)pArg;
+
+  if( nArg!=3 ) return 1;
+  zTable = azArg[0];
+  zType = azArg[1];
+  zSql = azArg[2];
+  
+  if( strcmp(zTable, "sqlite_sequence")==0 ){
+    fprintf(p->out, "DELETE FROM sqlite_sequence;\n");
+  }else if( strcmp(zTable, "sqlite_stat1")==0 ){
+    fprintf(p->out, "ANALYZE sqlite_master;\n");
+  }else if( strncmp(zTable, "sqlite_", 7)==0 ){
+    return 0;
+  }else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
+    char *zIns;
+    if( !p->writableSchema ){
+      fprintf(p->out, "PRAGMA writable_schema=ON;\n");
+      p->writableSchema = 1;
+    }
+    zIns = sqlite3_mprintf(
+       "INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"
+       "VALUES('table','%q','%q',0,'%q');",
+       zTable, zTable, zSql);
+    fprintf(p->out, "%s\n", zIns);
+    sqlite3_free(zIns);
+    return 0;
+  }else{
+    fprintf(p->out, "%s;\n", zSql);
+  }
+
+  if( strcmp(zType, "table")==0 ){
+    sqlite3_stmt *pTableInfo = 0;
+    char *zSelect = 0;
+    char *zTableInfo = 0;
+    char *zTmp = 0;
+   
+    zTableInfo = appendText(zTableInfo, "PRAGMA table_info(", 0);
+    zTableInfo = appendText(zTableInfo, zTable, '"');
+    zTableInfo = appendText(zTableInfo, ");", 0);
+
+    rc = sqlite3_prepare(p->db, zTableInfo, -1, &pTableInfo, 0);
+    if( zTableInfo ) free(zTableInfo);
+    if( rc!=SQLITE_OK || !pTableInfo ){
+      return 1;
+    }
+
+    zSelect = appendText(zSelect, "SELECT 'INSERT INTO ' || ", 0);
+    zTmp = appendText(zTmp, zTable, '"');
+    if( zTmp ){
+      zSelect = appendText(zSelect, zTmp, '\'');
+    }
+    zSelect = appendText(zSelect, " || ' VALUES(' || ", 0);
+    rc = sqlite3_step(pTableInfo);
+    while( rc==SQLITE_ROW ){
+      const char *zText = (const char *)sqlite3_column_text(pTableInfo, 1);
+      zSelect = appendText(zSelect, "quote(", 0);
+      zSelect = appendText(zSelect, zText, '"');
+      rc = sqlite3_step(pTableInfo);
+      if( rc==SQLITE_ROW ){
+        zSelect = appendText(zSelect, ") || ',' || ", 0);
+      }else{
+        zSelect = appendText(zSelect, ") ", 0);
+      }
+    }
+    rc = sqlite3_finalize(pTableInfo);
+    if( rc!=SQLITE_OK ){
+      if( zSelect ) free(zSelect);
+      return 1;
+    }
+    zSelect = appendText(zSelect, "|| ')' FROM  ", 0);
+    zSelect = appendText(zSelect, zTable, '"');
+
+    rc = run_table_dump_query(p->out, p->db, zSelect);
+    if( rc==SQLITE_CORRUPT ){
+      zSelect = appendText(zSelect, " ORDER BY rowid DESC", 0);
+      rc = run_table_dump_query(p->out, p->db, zSelect);
+    }
+    if( zSelect ) free(zSelect);
+  }
+  return 0;
+}
+
+/*
+** Run zQuery.  Use dump_callback() as the callback routine so that
+** the contents of the query are output as SQL statements.
+**
+** If we get a SQLITE_CORRUPT error, rerun the query after appending
+** "ORDER BY rowid DESC" to the end.
+*/
+static int run_schema_dump_query(
+  struct callback_data *p, 
+  const char *zQuery,
+  char **pzErrMsg
+){
+  int rc;
+  rc = sqlite3_exec(p->db, zQuery, dump_callback, p, pzErrMsg);
+  if( rc==SQLITE_CORRUPT ){
+    char *zQ2;
+    int len = strlen(zQuery);
+    if( pzErrMsg ) sqlite3_free(*pzErrMsg);
+    zQ2 = malloc( len+100 );
+    if( zQ2==0 ) return rc;
+    sqlite3_snprintf(sizeof(zQ2), zQ2, "%s ORDER BY rowid DESC", zQuery);
+    rc = sqlite3_exec(p->db, zQ2, dump_callback, p, pzErrMsg);
+    free(zQ2);
+  }
+  return rc;
+}
+
+/*
+** Text of a help message
+*/
+static char zHelp[] =
+  ".bail ON|OFF           Stop after hitting an error.  Default OFF\n"
+  ".databases             List names and files of attached databases\n"
+  ".dump ?TABLE? ...      Dump the database in an SQL text format\n"
+  ".echo ON|OFF           Turn command echo on or off\n"
+  ".exit                  Exit this program\n"
+  ".explain ON|OFF        Turn output mode suitable for EXPLAIN on or off.\n"
+  ".header(s) ON|OFF      Turn display of headers on or off\n"
+  ".help                  Show this message\n"
+  ".import FILE TABLE     Import data from FILE into TABLE\n"
+  ".indices TABLE         Show names of all indices on TABLE\n"
+#ifdef SQLITE_ENABLE_IOTRACE
+  ".iotrace FILE          Enable I/O diagnostic logging to FILE\n"
+#endif
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+  ".load FILE ?ENTRY?     Load an extension library\n"
+#endif
+  ".mode MODE ?TABLE?     Set output mode where MODE is one of:\n"
+  "                         csv      Comma-separated values\n"
+  "                         column   Left-aligned columns.  (See .width)\n"
+  "                         html     HTML <table> code\n"
+  "                         insert   SQL insert statements for TABLE\n"
+  "                         line     One value per line\n"
+  "                         list     Values delimited by .separator string\n"
+  "                         tabs     Tab-separated values\n"
+  "                         tcl      TCL list elements\n"
+  ".nullvalue STRING      Print STRING in place of NULL values\n"
+  ".output FILENAME       Send output to FILENAME\n"
+  ".output stdout         Send output to the screen\n"
+  ".prompt MAIN CONTINUE  Replace the standard prompts\n"
+  ".quit                  Exit this program\n"
+  ".read FILENAME         Execute SQL in FILENAME\n"
+  ".schema ?TABLE?        Show the CREATE statements\n"
+  ".separator STRING      Change separator used by output mode and .import\n"
+  ".show                  Show the current values for various settings\n"
+  ".tables ?PATTERN?      List names of tables matching a LIKE pattern\n"
+  ".timeout MS            Try opening locked tables for MS milliseconds\n"
+#if HAS_TIMER
+  ".timer ON|OFF          Turn the CPU timer measurement on or off\n"
+#endif
+  ".width NUM NUM ...     Set column widths for \"column\" mode\n"
+;
+
+/* Forward reference */
+static int process_input(struct callback_data *p, FILE *in);
+
+/*
+** Make sure the database is open.  If it is not, then open it.  If
+** the database fails to open, print an error message and exit.
+*/
+static void open_db(struct callback_data *p){
+  if( p->db==0 ){
+    sqlite3_open(p->zDbFilename, &p->db);
+    db = p->db;
+    sqlite3_create_function(db, "shellstatic", 0, SQLITE_UTF8, 0,
+        shellstaticFunc, 0, 0);
+    if( SQLITE_OK!=sqlite3_errcode(db) ){
+      fprintf(stderr,"Unable to open database \"%s\": %s\n", 
+          p->zDbFilename, sqlite3_errmsg(db));
+      exit(1);
+    }
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+    sqlite3_enable_load_extension(p->db, 1);
+#endif
+  }
+}
+
+/*
+** Do C-language style dequoting.
+**
+**    \t    -> tab
+**    \n    -> newline
+**    \r    -> carriage return
+**    \NNN  -> ascii character NNN in octal
+**    \\    -> backslash
+*/
+static void resolve_backslashes(char *z){
+  int i, j, c;
+  for(i=j=0; (c = z[i])!=0; i++, j++){
+    if( c=='\\' ){
+      c = z[++i];
+      if( c=='n' ){
+        c = '\n';
+      }else if( c=='t' ){
+        c = '\t';
+      }else if( c=='r' ){
+        c = '\r';
+      }else if( c>='0' && c<='7' ){
+        c -= '0';
+        if( z[i+1]>='0' && z[i+1]<='7' ){
+          i++;
+          c = (c<<3) + z[i] - '0';
+          if( z[i+1]>='0' && z[i+1]<='7' ){
+            i++;
+            c = (c<<3) + z[i] - '0';
+          }
+        }
+      }
+    }
+    z[j] = c;
+  }
+  z[j] = 0;
+}
+
+/*
+** Interpret zArg as a boolean value.  Return either 0 or 1.
+*/
+static int booleanValue(char *zArg){
+  int val = atoi(zArg);
+  int j;
+  for(j=0; zArg[j]; j++){
+    zArg[j] = tolower(zArg[j]);
+  }
+  if( strcmp(zArg,"on")==0 ){
+    val = 1;
+  }else if( strcmp(zArg,"yes")==0 ){
+    val = 1;
+  }
+  return val;
+}
+
+/*
+** If an input line begins with "." then invoke this routine to
+** process that line.
+**
+** Return 1 on error, 2 to exit, and 0 otherwise.
+*/
+static int do_meta_command(char *zLine, struct callback_data *p){
+  int i = 1;
+  int nArg = 0;
+  int n, c;
+  int rc = 0;
+  char *azArg[50];
+
+  /* Parse the input line into tokens.
+  */
+  while( zLine[i] && nArg<ArraySize(azArg) ){
+    while( isspace((unsigned char)zLine[i]) ){ i++; }
+    if( zLine[i]==0 ) break;
+    if( zLine[i]=='\'' || zLine[i]=='"' ){
+      int delim = zLine[i++];
+      azArg[nArg++] = &zLine[i];
+      while( zLine[i] && zLine[i]!=delim ){ i++; }
+      if( zLine[i]==delim ){
+        zLine[i++] = 0;
+      }
+      if( delim=='"' ) resolve_backslashes(azArg[nArg-1]);
+    }else{
+      azArg[nArg++] = &zLine[i];
+      while( zLine[i] && !isspace((unsigned char)zLine[i]) ){ i++; }
+      if( zLine[i] ) zLine[i++] = 0;
+      resolve_backslashes(azArg[nArg-1]);
+    }
+  }
+
+  /* Process the input line.
+  */
+  if( nArg==0 ) return rc;
+  n = strlen(azArg[0]);
+  c = azArg[0][0];
+  if( c=='b' && n>1 && strncmp(azArg[0], "bail", n)==0 && nArg>1 ){
+    bail_on_error = booleanValue(azArg[1]);
+  }else
+
+  if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 ){
+    struct callback_data data;
+    char *zErrMsg = 0;
+    open_db(p);
+    memcpy(&data, p, sizeof(data));
+    data.showHeader = 1;
+    data.mode = MODE_Column;
+    data.colWidth[0] = 3;
+    data.colWidth[1] = 15;
+    data.colWidth[2] = 58;
+    data.cnt = 0;
+    sqlite3_exec(p->db, "PRAGMA database_list; ", callback, &data, &zErrMsg);
+    if( zErrMsg ){
+      fprintf(stderr,"Error: %s\n", zErrMsg);
+      sqlite3_free(zErrMsg);
+    }
+  }else
+
+  if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
+    char *zErrMsg = 0;
+    open_db(p);
+    fprintf(p->out, "BEGIN TRANSACTION;\n");
+    p->writableSchema = 0;
+    if( nArg==1 ){
+      run_schema_dump_query(p, 
+        "SELECT name, type, sql FROM sqlite_master "
+        "WHERE sql NOT NULL AND type=='table'", 0
+      );
+      run_table_dump_query(p->out, p->db,
+        "SELECT sql FROM sqlite_master "
+        "WHERE sql NOT NULL AND type IN ('index','trigger','view')"
+      );
+    }else{
+      int i;
+      for(i=1; i<nArg; i++){
+        zShellStatic = azArg[i];
+        run_schema_dump_query(p,
+          "SELECT name, type, sql FROM sqlite_master "
+          "WHERE tbl_name LIKE shellstatic() AND type=='table'"
+          "  AND sql NOT NULL", 0);
+        run_table_dump_query(p->out, p->db,
+          "SELECT sql FROM sqlite_master "
+          "WHERE sql NOT NULL"
+          "  AND type IN ('index','trigger','view')"
+          "  AND tbl_name LIKE shellstatic()"
+        );
+        zShellStatic = 0;
+      }
+    }
+    if( p->writableSchema ){
+      fprintf(p->out, "PRAGMA writable_schema=OFF;\n");
+      p->writableSchema = 0;
+    }
+    if( zErrMsg ){
+      fprintf(stderr,"Error: %s\n", zErrMsg);
+      sqlite3_free(zErrMsg);
+    }else{
+      fprintf(p->out, "COMMIT;\n");
+    }
+  }else
+
+  if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 ){
+    p->echoOn = booleanValue(azArg[1]);
+  }else
+
+  if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
+    rc = 2;
+  }else
+
+  if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
+    int val = nArg>=2 ? booleanValue(azArg[1]) : 1;
+    if(val == 1) {
+      if(!p->explainPrev.valid) {
+        p->explainPrev.valid = 1;
+        p->explainPrev.mode = p->mode;
+        p->explainPrev.showHeader = p->showHeader;
+        memcpy(p->explainPrev.colWidth,p->colWidth,sizeof(p->colWidth));
+      }
+      /* We could put this code under the !p->explainValid
+      ** condition so that it does not execute if we are already in
+      ** explain mode. However, always executing it allows us an easy
+      ** was to reset to explain mode in case the user previously
+      ** did an .explain followed by a .width, .mode or .header
+      ** command.
+      */
+      p->mode = MODE_Explain;
+      p->showHeader = 1;
+      memset(p->colWidth,0,ArraySize(p->colWidth));
+      p->colWidth[0] = 4;                  /* addr */
+      p->colWidth[1] = 13;                 /* opcode */
+      p->colWidth[2] = 4;                  /* P1 */
+      p->colWidth[3] = 4;                  /* P2 */
+      p->colWidth[4] = 4;                  /* P3 */
+      p->colWidth[5] = 13;                 /* P4 */
+      p->colWidth[6] = 2;                  /* P5 */
+      p->colWidth[7] = 13;                  /* Comment */
+    }else if (p->explainPrev.valid) {
+      p->explainPrev.valid = 0;
+      p->mode = p->explainPrev.mode;
+      p->showHeader = p->explainPrev.showHeader;
+      memcpy(p->colWidth,p->explainPrev.colWidth,sizeof(p->colWidth));
+    }
+  }else
+
+  if( c=='h' && (strncmp(azArg[0], "header", n)==0 ||
+                 strncmp(azArg[0], "headers", n)==0 )&& nArg>1 ){
+    p->showHeader = booleanValue(azArg[1]);
+  }else
+
+  if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
+    fprintf(stderr,zHelp);
+  }else
+
+  if( c=='i' && strncmp(azArg[0], "import", n)==0 && nArg>=3 ){
+    char *zTable = azArg[2];    /* Insert data into this table */
+    char *zFile = azArg[1];     /* The file from which to extract data */
+    sqlite3_stmt *pStmt;        /* A statement */
+    int rc;                     /* Result code */
+    int nCol;                   /* Number of columns in the table */
+    int nByte;                  /* Number of bytes in an SQL string */
+    int i, j;                   /* Loop counters */
+    int nSep;                   /* Number of bytes in p->separator[] */
+    char *zSql;                 /* An SQL statement */
+    char *zLine;                /* A single line of input from the file */
+    char **azCol;               /* zLine[] broken up into columns */
+    char *zCommit;              /* How to commit changes */   
+    FILE *in;                   /* The input file */
+    int lineno = 0;             /* Line number of input file */
+
+    open_db(p);
+    nSep = strlen(p->separator);
+    if( nSep==0 ){
+      fprintf(stderr, "non-null separator required for import\n");
+      return 0;
+    }
+    zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable);
+    if( zSql==0 ) return 0;
+    nByte = strlen(zSql);
+    rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);
+    sqlite3_free(zSql);
+    if( rc ){
+      fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
+      nCol = 0;
+      rc = 1;
+    }else{
+      nCol = sqlite3_column_count(pStmt);
+    }
+    sqlite3_finalize(pStmt);
+    if( nCol==0 ) return 0;
+    zSql = malloc( nByte + 20 + nCol*2 );
+    if( zSql==0 ) return 0;
+    sqlite3_snprintf(nByte+20, zSql, "INSERT INTO '%q' VALUES(?", zTable);
+    j = strlen(zSql);
+    for(i=1; i<nCol; i++){
+      zSql[j++] = ',';
+      zSql[j++] = '?';
+    }
+    zSql[j++] = ')';
+    zSql[j] = 0;
+    rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);
+    free(zSql);
+    if( rc ){
+      fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
+      sqlite3_finalize(pStmt);
+      return 1;
+    }
+    in = fopen(zFile, "rb");
+    if( in==0 ){
+      fprintf(stderr, "cannot open file: %s\n", zFile);
+      sqlite3_finalize(pStmt);
+      return 0;
+    }
+    azCol = malloc( sizeof(azCol[0])*(nCol+1) );
+    if( azCol==0 ){
+      fclose(in);
+      return 0;
+    }
+    sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
+    zCommit = "COMMIT";
+    while( (zLine = local_getline(0, in))!=0 ){
+      char *z;
+      i = 0;
+      lineno++;
+      azCol[0] = zLine;
+      for(i=0, z=zLine; *z && *z!='\n' && *z!='\r'; z++){
+        if( *z==p->separator[0] && strncmp(z, p->separator, nSep)==0 ){
+          *z = 0;
+          i++;
+          if( i<nCol ){
+            azCol[i] = &z[nSep];
+            z += nSep-1;
+          }
+        }
+      }
+      *z = 0;
+      if( i+1!=nCol ){
+        fprintf(stderr,"%s line %d: expected %d columns of data but found %d\n",
+           zFile, lineno, nCol, i+1);
+        zCommit = "ROLLBACK";
+        break;
+      }
+      for(i=0; i<nCol; i++){
+        sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC);
+      }
+      sqlite3_step(pStmt);
+      rc = sqlite3_reset(pStmt);
+      free(zLine);
+      if( rc!=SQLITE_OK ){
+        fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
+        zCommit = "ROLLBACK";
+        rc = 1;
+        break;
+      }
+    }
+    free(azCol);
+    fclose(in);
+    sqlite3_finalize(pStmt);
+    sqlite3_exec(p->db, zCommit, 0, 0, 0);
+  }else
+
+  if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg>1 ){
+    struct callback_data data;
+    char *zErrMsg = 0;
+    open_db(p);
+    memcpy(&data, p, sizeof(data));
+    data.showHeader = 0;
+    data.mode = MODE_List;
+    zShellStatic = azArg[1];
+    sqlite3_exec(p->db,
+      "SELECT name FROM sqlite_master "
+      "WHERE type='index' AND tbl_name LIKE shellstatic() "
+      "UNION ALL "
+      "SELECT name FROM sqlite_temp_master "
+      "WHERE type='index' AND tbl_name LIKE shellstatic() "
+      "ORDER BY 1",
+      callback, &data, &zErrMsg
+    );
+    zShellStatic = 0;
+    if( zErrMsg ){
+      fprintf(stderr,"Error: %s\n", zErrMsg);
+      sqlite3_free(zErrMsg);
+    }
+  }else
+
+#ifdef SQLITE_ENABLE_IOTRACE
+  if( c=='i' && strncmp(azArg[0], "iotrace", n)==0 ){
+    extern void (*sqlite3_io_trace)(const char*, ...);
+    if( iotrace && iotrace!=stdout ) fclose(iotrace);
+    iotrace = 0;
+    if( nArg<2 ){
+      sqlite3_io_trace = 0;
+    }else if( strcmp(azArg[1], "-")==0 ){
+      sqlite3_io_trace = iotracePrintf;
+      iotrace = stdout;
+    }else{
+      iotrace = fopen(azArg[1], "w");
+      if( iotrace==0 ){
+        fprintf(stderr, "cannot open \"%s\"\n", azArg[1]);
+        sqlite3_io_trace = 0;
+      }else{
+        sqlite3_io_trace = iotracePrintf;
+      }
+    }
+  }else
+#endif
+
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+  if( c=='l' && strncmp(azArg[0], "load", n)==0 && nArg>=2 ){
+    const char *zFile, *zProc;
+    char *zErrMsg = 0;
+    int rc;
+    zFile = azArg[1];
+    zProc = nArg>=3 ? azArg[2] : 0;
+    open_db(p);
+    rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg);
+    if( rc!=SQLITE_OK ){
+      fprintf(stderr, "%s\n", zErrMsg);
+      sqlite3_free(zErrMsg);
+      rc = 1;
+    }
+  }else
+#endif
+
+  if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg>=2 ){
+    int n2 = strlen(azArg[1]);
+    if( strncmp(azArg[1],"line",n2)==0
+        ||
+        strncmp(azArg[1],"lines",n2)==0 ){
+      p->mode = MODE_Line;
+    }else if( strncmp(azArg[1],"column",n2)==0
+              ||
+              strncmp(azArg[1],"columns",n2)==0 ){
+      p->mode = MODE_Column;
+    }else if( strncmp(azArg[1],"list",n2)==0 ){
+      p->mode = MODE_List;
+    }else if( strncmp(azArg[1],"html",n2)==0 ){
+      p->mode = MODE_Html;
+    }else if( strncmp(azArg[1],"tcl",n2)==0 ){
+      p->mode = MODE_Tcl;
+    }else if( strncmp(azArg[1],"csv",n2)==0 ){
+      p->mode = MODE_Csv;
+      sqlite3_snprintf(sizeof(p->separator), p->separator, ",");
+    }else if( strncmp(azArg[1],"tabs",n2)==0 ){
+      p->mode = MODE_List;
+      sqlite3_snprintf(sizeof(p->separator), p->separator, "\t");
+    }else if( strncmp(azArg[1],"insert",n2)==0 ){
+      p->mode = MODE_Insert;
+      if( nArg>=3 ){
+        set_table_name(p, azArg[2]);
+      }else{
+        set_table_name(p, "table");
+      }
+    }else {
+      fprintf(stderr,"mode should be one of: "
+         "column csv html insert line list tabs tcl\n");
+    }
+  }else
+
+  if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 && nArg==2 ) {
+    sqlite3_snprintf(sizeof(p->nullvalue), p->nullvalue,
+                     "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);
+  }else
+
+  if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
+    if( p->out!=stdout ){
+      fclose(p->out);
+    }
+    if( strcmp(azArg[1],"stdout")==0 ){
+      p->out = stdout;
+      sqlite3_snprintf(sizeof(p->outfile), p->outfile, "stdout");
+    }else{
+      p->out = fopen(azArg[1], "wb");
+      if( p->out==0 ){
+        fprintf(stderr,"can't write to \"%s\"\n", azArg[1]);
+        p->out = stdout;
+      } else {
+         sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", azArg[1]);
+      }
+    }
+  }else
+
+  if( c=='p' && strncmp(azArg[0], "prompt", n)==0 && (nArg==2 || nArg==3)){
+    if( nArg >= 2) {
+      strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1);
+    }
+    if( nArg >= 3) {
+      strncpy(continuePrompt,azArg[2],(int)ArraySize(continuePrompt)-1);
+    }
+  }else
+
+  if( c=='q' && strncmp(azArg[0], "quit", n)==0 ){
+    rc = 2;
+  }else
+
+  if( c=='r' && strncmp(azArg[0], "read", n)==0 && nArg==2 ){
+    FILE *alt = fopen(azArg[1], "rb");
+    if( alt==0 ){
+      fprintf(stderr,"can't open \"%s\"\n", azArg[1]);
+    }else{
+      process_input(p, alt);
+      fclose(alt);
+    }
+  }else
+
+  if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
+    struct callback_data data;
+    char *zErrMsg = 0;
+    open_db(p);
+    memcpy(&data, p, sizeof(data));
+    data.showHeader = 0;
+    data.mode = MODE_Semi;
+    if( nArg>1 ){
+      int i;
+      for(i=0; azArg[1][i]; i++) azArg[1][i] = tolower(azArg[1][i]);
+      if( strcmp(azArg[1],"sqlite_master")==0 ){
+        char *new_argv[2], *new_colv[2];
+        new_argv[0] = "CREATE TABLE sqlite_master (\n"
+                      "  type text,\n"
+                      "  name text,\n"
+                      "  tbl_name text,\n"
+                      "  rootpage integer,\n"
+                      "  sql text\n"
+                      ")";
+        new_argv[1] = 0;
+        new_colv[0] = "sql";
+        new_colv[1] = 0;
+        callback(&data, 1, new_argv, new_colv);
+      }else if( strcmp(azArg[1],"sqlite_temp_master")==0 ){
+        char *new_argv[2], *new_colv[2];
+        new_argv[0] = "CREATE TEMP TABLE sqlite_temp_master (\n"
+                      "  type text,\n"
+                      "  name text,\n"
+                      "  tbl_name text,\n"
+                      "  rootpage integer,\n"
+                      "  sql text\n"
+                      ")";
+        new_argv[1] = 0;
+        new_colv[0] = "sql";
+        new_colv[1] = 0;
+        callback(&data, 1, new_argv, new_colv);
+      }else{
+        zShellStatic = azArg[1];
+        sqlite3_exec(p->db,
+          "SELECT sql FROM "
+          "  (SELECT * FROM sqlite_master UNION ALL"
+          "   SELECT * FROM sqlite_temp_master) "
+          "WHERE tbl_name LIKE shellstatic() AND type!='meta' AND sql NOTNULL "
+          "ORDER BY substr(type,2,1), name",
+          callback, &data, &zErrMsg);
+        zShellStatic = 0;
+      }
+    }else{
+      sqlite3_exec(p->db,
+         "SELECT sql FROM "
+         "  (SELECT * FROM sqlite_master UNION ALL"
+         "   SELECT * FROM sqlite_temp_master) "
+         "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%'"
+         "ORDER BY substr(type,2,1), name",
+         callback, &data, &zErrMsg
+      );
+    }
+    if( zErrMsg ){
+      fprintf(stderr,"Error: %s\n", zErrMsg);
+      sqlite3_free(zErrMsg);
+    }
+  }else
+
+  if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){
+    sqlite3_snprintf(sizeof(p->separator), p->separator,
+                     "%.*s", (int)sizeof(p->separator)-1, azArg[1]);
+  }else
+
+  if( c=='s' && strncmp(azArg[0], "show", n)==0){
+    int i;
+    fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off");
+    fprintf(p->out,"%9.9s: %s\n","explain", p->explainPrev.valid ? "on" :"off");
+    fprintf(p->out,"%9.9s: %s\n","headers", p->showHeader ? "on" : "off");
+    fprintf(p->out,"%9.9s: %s\n","mode", modeDescr[p->mode]);
+    fprintf(p->out,"%9.9s: ", "nullvalue");
+      output_c_string(p->out, p->nullvalue);
+      fprintf(p->out, "\n");
+    fprintf(p->out,"%9.9s: %s\n","output",
+                                 strlen(p->outfile) ? p->outfile : "stdout");
+    fprintf(p->out,"%9.9s: ", "separator");
+      output_c_string(p->out, p->separator);
+      fprintf(p->out, "\n");
+    fprintf(p->out,"%9.9s: ","width");
+    for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
+      fprintf(p->out,"%d ",p->colWidth[i]);
+    }
+    fprintf(p->out,"\n");
+  }else
+
+  if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 ){
+    char **azResult;
+    int nRow, rc;
+    char *zErrMsg;
+    open_db(p);
+    if( nArg==1 ){
+      rc = sqlite3_get_table(p->db,
+        "SELECT name FROM sqlite_master "
+        "WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%'"
+        "UNION ALL "
+        "SELECT name FROM sqlite_temp_master "
+        "WHERE type IN ('table','view') "
+        "ORDER BY 1",
+        &azResult, &nRow, 0, &zErrMsg
+      );
+    }else{
+      zShellStatic = azArg[1];
+      rc = sqlite3_get_table(p->db,
+        "SELECT name FROM sqlite_master "
+        "WHERE type IN ('table','view') AND name LIKE '%'||shellstatic()||'%' "
+        "UNION ALL "
+        "SELECT name FROM sqlite_temp_master "
+        "WHERE type IN ('table','view') AND name LIKE '%'||shellstatic()||'%' "
+        "ORDER BY 1",
+        &azResult, &nRow, 0, &zErrMsg
+      );
+      zShellStatic = 0;
+    }
+    if( zErrMsg ){
+      fprintf(stderr,"Error: %s\n", zErrMsg);
+      sqlite3_free(zErrMsg);
+    }
+    if( rc==SQLITE_OK ){
+      int len, maxlen = 0;
+      int i, j;
+      int nPrintCol, nPrintRow;
+      for(i=1; i<=nRow; i++){
+        if( azResult[i]==0 ) continue;
+        len = strlen(azResult[i]);
+        if( len>maxlen ) maxlen = len;
+      }
+      nPrintCol = 80/(maxlen+2);
+      if( nPrintCol<1 ) nPrintCol = 1;
+      nPrintRow = (nRow + nPrintCol - 1)/nPrintCol;
+      for(i=0; i<nPrintRow; i++){
+        for(j=i+1; j<=nRow; j+=nPrintRow){
+          char *zSp = j<=nPrintRow ? "" : "  ";
+          printf("%s%-*s", zSp, maxlen, azResult[j] ? azResult[j] : "");
+        }
+        printf("\n");
+      }
+    }else{
+      rc = 1;
+    }
+    sqlite3_free_table(azResult);
+  }else
+
+  if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 && nArg>=2 ){
+    open_db(p);
+    sqlite3_busy_timeout(p->db, atoi(azArg[1]));
+  }else
+  
+#if HAS_TIMER  
+  if( c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0 && nArg>1 ){
+    enableTimer = booleanValue(azArg[1]);
+  }else
+#endif
+
+  if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
+    int j;
+    assert( nArg<=ArraySize(azArg) );
+    for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
+      p->colWidth[j-1] = atoi(azArg[j]);
+    }
+  }else
+
+
+  {
+    fprintf(stderr, "unknown command or invalid arguments: "
+      " \"%s\". Enter \".help\" for help\n", azArg[0]);
+  }
+
+  return rc;
+}
+
+/*
+** Return TRUE if a semicolon occurs anywhere in the first N characters
+** of string z[].
+*/
+static int _contains_semicolon(const char *z, int N){
+  int i;
+  for(i=0; i<N; i++){  if( z[i]==';' ) return 1; }
+  return 0;
+}
+
+/*
+** Test to see if a line consists entirely of whitespace.
+*/
+static int _all_whitespace(const char *z){
+  for(; *z; z++){
+    if( isspace(*(unsigned char*)z) ) continue;
+    if( *z=='/' && z[1]=='*' ){
+      z += 2;
+      while( *z && (*z!='*' || z[1]!='/') ){ z++; }
+      if( *z==0 ) return 0;
+      z++;
+      continue;
+    }
+    if( *z=='-' && z[1]=='-' ){
+      z += 2;
+      while( *z && *z!='\n' ){ z++; }
+      if( *z==0 ) return 1;
+      continue;
+    }
+    return 0;
+  }
+  return 1;
+}
+
+/*
+** Return TRUE if the line typed in is an SQL command terminator other
+** than a semi-colon.  The SQL Server style "go" command is understood
+** as is the Oracle "/".
+*/
+static int _is_command_terminator(const char *zLine){
+  while( isspace(*(unsigned char*)zLine) ){ zLine++; };
+  if( zLine[0]=='/' && _all_whitespace(&zLine[1]) ) return 1;  /* Oracle */
+  if( tolower(zLine[0])=='g' && tolower(zLine[1])=='o'
+         && _all_whitespace(&zLine[2]) ){
+    return 1;  /* SQL Server */
+  }
+  return 0;
+}
+
+/*
+** Read input from *in and process it.  If *in==0 then input
+** is interactive - the user is typing it it.  Otherwise, input
+** is coming from a file or device.  A prompt is issued and history
+** is saved only if input is interactive.  An interrupt signal will
+** cause this routine to exit immediately, unless input is interactive.
+**
+** Return the number of errors.
+*/
+static int process_input(struct callback_data *p, FILE *in){
+  char *zLine = 0;
+  char *zSql = 0;
+  int nSql = 0;
+  int nSqlPrior = 0;
+  char *zErrMsg;
+  int rc;
+  int errCnt = 0;
+  int lineno = 0;
+  int startline = 0;
+
+  while( errCnt==0 || !bail_on_error || (in==0 && stdin_is_interactive) ){
+    fflush(p->out);
+    free(zLine);
+    zLine = one_input_line(zSql, in);
+    if( zLine==0 ){
+      break;  /* We have reached EOF */
+    }
+    if( seenInterrupt ){
+      if( in!=0 ) break;
+      seenInterrupt = 0;
+    }
+    lineno++;
+    if( p->echoOn ) printf("%s\n", zLine);
+    if( (zSql==0 || zSql[0]==0) && _all_whitespace(zLine) ) continue;
+    if( zLine && zLine[0]=='.' && nSql==0 ){
+      rc = do_meta_command(zLine, p);
+      if( rc==2 ){
+        break;
+      }else if( rc ){
+        errCnt++;
+      }
+      continue;
+    }
+    if( _is_command_terminator(zLine) ){
+      memcpy(zLine,";",2);
+    }
+    nSqlPrior = nSql;
+    if( zSql==0 ){
+      int i;
+      for(i=0; zLine[i] && isspace((unsigned char)zLine[i]); i++){}
+      if( zLine[i]!=0 ){
+        nSql = strlen(zLine);
+        zSql = malloc( nSql+1 );
+        if( zSql==0 ){
+          fprintf(stderr, "out of memory\n");
+          exit(1);
+        }
+        memcpy(zSql, zLine, nSql+1);
+        startline = lineno;
+      }
+    }else{
+      int len = strlen(zLine);
+      zSql = realloc( zSql, nSql + len + 2 );
+      if( zSql==0 ){
+        fprintf(stderr,"%s: out of memory!\n", Argv0);
+        exit(1);
+      }
+      zSql[nSql++] = '\n';
+      memcpy(&zSql[nSql], zLine, len+1);
+      nSql += len;
+    }
+    if( zSql && _contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior)
+                && sqlite3_complete(zSql) ){
+      p->cnt = 0;
+      open_db(p);
+      BEGIN_TIMER;
+      rc = sqlite3_exec(p->db, zSql, callback, p, &zErrMsg);
+      END_TIMER;
+      if( rc || zErrMsg ){
+        char zPrefix[100];
+        if( in!=0 || !stdin_is_interactive ){
+          sqlite3_snprintf(sizeof(zPrefix), zPrefix, 
+                           "SQL error near line %d:", startline);
+        }else{
+          sqlite3_snprintf(sizeof(zPrefix), zPrefix, "SQL error:");
+        }
+        if( zErrMsg!=0 ){
+          printf("%s %s\n", zPrefix, zErrMsg);
+          sqlite3_free(zErrMsg);
+          zErrMsg = 0;
+        }else{
+          printf("%s %s\n", zPrefix, sqlite3_errmsg(p->db));
+        }
+        errCnt++;
+      }
+      free(zSql);
+      zSql = 0;
+      nSql = 0;
+    }
+  }
+  if( zSql ){
+    if( !_all_whitespace(zSql) ) printf("Incomplete SQL: %s\n", zSql);
+    free(zSql);
+  }
+  free(zLine);
+  return errCnt;
+}
+
+/*
+** Return a pathname which is the user's home directory.  A
+** 0 return indicates an error of some kind.  Space to hold the
+** resulting string is obtained from malloc().  The calling
+** function should free the result.
+*/
+static char *find_home_dir(void){
+  char *home_dir = NULL;
+
+#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__) && !defined(_WIN32_WCE)
+  struct passwd *pwent;
+  uid_t uid = getuid();
+  if( (pwent=getpwuid(uid)) != NULL) {
+    home_dir = pwent->pw_dir;
+  }
+#endif
+
+#if defined(_WIN32_WCE)
+  /* Windows CE (arm-wince-mingw32ce-gcc) does not provide getenv()
+   */
+  home_dir = strdup("/");
+#else
+
+#if defined(_WIN32) || defined(WIN32) || defined(__OS2__)
+  if (!home_dir) {
+    home_dir = getenv("USERPROFILE");
+  }
+#endif
+
+  if (!home_dir) {
+    home_dir = getenv("HOME");
+  }
+
+#if defined(_WIN32) || defined(WIN32) || defined(__OS2__)
+  if (!home_dir) {
+    char *zDrive, *zPath;
+    int n;
+    zDrive = getenv("HOMEDRIVE");
+    zPath = getenv("HOMEPATH");
+    if( zDrive && zPath ){
+      n = strlen(zDrive) + strlen(zPath) + 1;
+      home_dir = malloc( n );
+      if( home_dir==0 ) return 0;
+      sqlite3_snprintf(n, home_dir, "%s%s", zDrive, zPath);
+      return home_dir;
+    }
+    home_dir = "c:\\";
+  }
+#endif
+
+#endif /* !_WIN32_WCE */
+
+  if( home_dir ){
+    int n = strlen(home_dir) + 1;
+    char *z = malloc( n );
+    if( z ) memcpy(z, home_dir, n);
+    home_dir = z;
+  }
+
+  return home_dir;
+}
+
+/*
+** Read input from the file given by sqliterc_override.  Or if that
+** parameter is NULL, take input from ~/.sqliterc
+*/
+static void process_sqliterc(
+  struct callback_data *p,        /* Configuration data */
+  const char *sqliterc_override   /* Name of config file. NULL to use default */
+){
+  char *home_dir = NULL;
+  const char *sqliterc = sqliterc_override;
+  char *zBuf = 0;
+  FILE *in = NULL;
+  int nBuf;
+
+  if (sqliterc == NULL) {
+    home_dir = find_home_dir();
+    if( home_dir==0 ){
+      fprintf(stderr,"%s: cannot locate your home directory!\n", Argv0);
+      return;
+    }
+    nBuf = strlen(home_dir) + 16;
+    zBuf = malloc( nBuf );
+    if( zBuf==0 ){
+      fprintf(stderr,"%s: out of memory!\n", Argv0);
+      exit(1);
+    }
+    sqlite3_snprintf(nBuf, zBuf,"%s/.sqliterc",home_dir);
+    free(home_dir);
+    sqliterc = (const char*)zBuf;
+  }
+  in = fopen(sqliterc,"rb");
+  if( in ){
+    if( stdin_is_interactive ){
+      printf("-- Loading resources from %s\n",sqliterc);
+    }
+    process_input(p,in);
+    fclose(in);
+  }
+  free(zBuf);
+  return;
+}
+
+/*
+** Show available command line options
+*/
+static const char zOptions[] = 
+  "   -init filename       read/process named file\n"
+  "   -echo                print commands before execution\n"
+  "   -[no]header          turn headers on or off\n"
+  "   -bail                stop after hitting an error\n"
+  "   -interactive         force interactive I/O\n"
+  "   -batch               force batch I/O\n"
+  "   -column              set output mode to 'column'\n"
+  "   -csv                 set output mode to 'csv'\n"
+  "   -html                set output mode to HTML\n"
+  "   -line                set output mode to 'line'\n"
+  "   -list                set output mode to 'list'\n"
+  "   -separator 'x'       set output field separator (|)\n"
+  "   -nullvalue 'text'    set text string for NULL values\n"
+  "   -version             show SQLite version\n"
+;
+static void usage(int showDetail){
+  fprintf(stderr,
+      "Usage: %s [OPTIONS] FILENAME [SQL]\n"  
+      "FILENAME is the name of an SQLite database. A new database is created\n"
+      "if the file does not previously exist.\n", Argv0);
+  if( showDetail ){
+    fprintf(stderr, "OPTIONS include:\n%s", zOptions);
+  }else{
+    fprintf(stderr, "Use the -help option for additional information\n");
+  }
+  exit(1);
+}
+
+/*
+** Initialize the state information in data
+*/
+static void main_init(struct callback_data *data) {
+  memset(data, 0, sizeof(*data));
+  data->mode = MODE_List;
+  memcpy(data->separator,"|", 2);
+  data->showHeader = 0;
+  sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> ");
+  sqlite3_snprintf(sizeof(continuePrompt), continuePrompt,"   ...> ");
+}
+
+int main(int argc, char **argv){
+  char *zErrMsg = 0;
+  struct callback_data data;
+  const char *zInitFile = 0;
+  char *zFirstCmd = 0;
+  int i;
+  int rc = 0;
+
+  Argv0 = argv[0];
+  main_init(&data);
+  stdin_is_interactive = isatty(0);
+
+  /* Make sure we have a valid signal handler early, before anything
+  ** else is done.
+  */
+#ifdef SIGINT
+  signal(SIGINT, interrupt_handler);
+#endif
+
+  /* Do an initial pass through the command-line argument to locate
+  ** the name of the database file, the name of the initialization file,
+  ** and the first command to execute.
+  */
+  for(i=1; i<argc-1; i++){
+    char *z;
+    if( argv[i][0]!='-' ) break;
+    z = argv[i];
+    if( z[0]=='-' && z[1]=='-' ) z++;
+    if( strcmp(argv[i],"-separator")==0 || strcmp(argv[i],"-nullvalue")==0 ){
+      i++;
+    }else if( strcmp(argv[i],"-init")==0 ){
+      i++;
+      zInitFile = argv[i];
+    }
+  }
+  if( i<argc ){
+    data.zDbFilename = argv[i++];
+  }else{
+#ifndef SQLITE_OMIT_MEMORYDB
+    data.zDbFilename = ":memory:";
+#else
+    data.zDbFilename = 0;
+#endif
+  }
+  if( i<argc ){
+    zFirstCmd = argv[i++];
+  }
+  data.out = stdout;
+
+#ifdef SQLITE_OMIT_MEMORYDB
+  if( data.zDbFilename==0 ){
+    fprintf(stderr,"%s: no database filename specified\n", argv[0]);
+    exit(1);
+  }
+#endif
+
+  /* Go ahead and open the database file if it already exists.  If the
+  ** file does not exist, delay opening it.  This prevents empty database
+  ** files from being created if a user mistypes the database name argument
+  ** to the sqlite command-line tool.
+  */
+  if( access(data.zDbFilename, 0)==0 ){
+    open_db(&data);
+  }
+
+  /* Process the initialization file if there is one.  If no -init option
+  ** is given on the command line, look for a file named ~/.sqliterc and
+  ** try to process it.
+  */
+  process_sqliterc(&data,zInitFile);
+
+  /* Make a second pass through the command-line argument and set
+  ** options.  This second pass is delayed until after the initialization
+  ** file is processed so that the command-line arguments will override
+  ** settings in the initialization file.
+  */
+  for(i=1; i<argc && argv[i][0]=='-'; i++){
+    char *z = argv[i];
+    if( z[1]=='-' ){ z++; }
+    if( strcmp(z,"-init")==0 ){
+      i++;
+    }else if( strcmp(z,"-html")==0 ){
+      data.mode = MODE_Html;
+    }else if( strcmp(z,"-list")==0 ){
+      data.mode = MODE_List;
+    }else if( strcmp(z,"-line")==0 ){
+      data.mode = MODE_Line;
+    }else if( strcmp(z,"-column")==0 ){
+      data.mode = MODE_Column;
+    }else if( strcmp(z,"-csv")==0 ){
+      data.mode = MODE_Csv;
+      memcpy(data.separator,",",2);
+    }else if( strcmp(z,"-separator")==0 ){
+      i++;
+      sqlite3_snprintf(sizeof(data.separator), data.separator,
+                       "%.*s",(int)sizeof(data.separator)-1,argv[i]);
+    }else if( strcmp(z,"-nullvalue")==0 ){
+      i++;
+      sqlite3_snprintf(sizeof(data.nullvalue), data.nullvalue,
+                       "%.*s",(int)sizeof(data.nullvalue)-1,argv[i]);
+    }else if( strcmp(z,"-header")==0 ){
+      data.showHeader = 1;
+    }else if( strcmp(z,"-noheader")==0 ){
+      data.showHeader = 0;
+    }else if( strcmp(z,"-echo")==0 ){
+      data.echoOn = 1;
+    }else if( strcmp(z,"-bail")==0 ){
+      bail_on_error = 1;
+    }else if( strcmp(z,"-version")==0 ){
+      printf("%s\n", sqlite3_libversion());
+      return 0;
+    }else if( strcmp(z,"-interactive")==0 ){
+      stdin_is_interactive = 1;
+    }else if( strcmp(z,"-batch")==0 ){
+      stdin_is_interactive = 0;
+    }else if( strcmp(z,"-help")==0 || strcmp(z, "--help")==0 ){
+      usage(1);
+    }else{
+      fprintf(stderr,"%s: unknown option: %s\n", Argv0, z);
+      fprintf(stderr,"Use -help for a list of options.\n");
+      return 1;
+    }
+  }
+
+  if( zFirstCmd ){
+    /* Run just the command that follows the database name
+    */
+    if( zFirstCmd[0]=='.' ){
+      do_meta_command(zFirstCmd, &data);
+      exit(0);
+    }else{
+      int rc;
+      open_db(&data);
+      rc = sqlite3_exec(data.db, zFirstCmd, callback, &data, &zErrMsg);
+      if( rc!=0 && zErrMsg!=0 ){
+        fprintf(stderr,"SQL error: %s\n", zErrMsg);
+        exit(1);
+      }
+    }
+  }else{
+    /* Run commands received from standard input
+    */
+    if( stdin_is_interactive ){
+      char *zHome;
+      char *zHistory = 0;
+      int nHistory;
+      printf(
+        "SQLite version %s\n"
+        "Enter \".help\" for instructions\n",
+        sqlite3_libversion()
+      );
+      zHome = find_home_dir();
+      if( zHome && (zHistory = malloc(nHistory = strlen(zHome)+20))!=0 ){
+        sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
+      }
+#if defined(HAVE_READLINE) && HAVE_READLINE==1
+      if( zHistory ) read_history(zHistory);
+#endif
+      rc = process_input(&data, 0);
+      if( zHistory ){
+        stifle_history(100);
+        write_history(zHistory);
+        free(zHistory);
+      }
+      free(zHome);
+    }else{
+      rc = process_input(&data, stdin);
+    }
+  }
+  set_table_name(&data, 0);
+  if( db ){
+    if( sqlite3_close(db)!=SQLITE_OK ){
+      fprintf(stderr,"error closing database: %s\n", sqlite3_errmsg(db));
+    }
+  }
+  return rc;
+}

Added: test-suite/trunk/MultiSource/Applications/sqlite3/speedtest.tcl
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/sqlite3/speedtest.tcl?rev=48828&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/sqlite3/speedtest.tcl (added)
+++ test-suite/trunk/MultiSource/Applications/sqlite3/speedtest.tcl Wed Mar 26 12:03:57 2008
@@ -0,0 +1,192 @@
+#!/usr/bin/tclsh
+#
+# Run this script using TCLSH to do a speed comparison between
+# various versions of SQLite and PostgreSQL and MySQL
+#
+
+# Run a test
+#
+set cnt 1
+proc runtest {title} {
+  global cnt
+  incr cnt
+}
+
+# Initialize the environment
+#
+expr srand(1)
+set ones {zero one two three four five six seven eight nine
+          ten eleven twelve thirteen fourteen fifteen sixteen seventeen
+          eighteen nineteen}
+set tens {{} ten twenty thirty forty fifty sixty seventy eighty ninety}
+proc number_name {n} {
+  if {$n>=1000} {
+    set txt "[number_name [expr {$n/1000}]] thousand"
+    set n [expr {$n%1000}]
+  } else {
+    set txt {}
+  }
+  if {$n>=100} {
+    append txt " [lindex $::ones [expr {$n/100}]] hundred"
+    set n [expr {$n%100}]
+  }
+  if {$n>=20} {
+    append txt " [lindex $::tens [expr {$n/10}]]"
+    set n [expr {$n%10}]
+  }
+  if {$n>0} {
+    append txt " [lindex $::ones $n]"
+  }
+  set txt [string trim $txt]
+  if {$txt==""} {set txt zero}
+  return $txt
+}
+
+
+
+set fd [open test$cnt.sql w]
+puts $fd "CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100));"
+for {set i 1} {$i<=1000} {incr i} {
+  set r [expr {int(rand()*100000)}]
+  puts $fd "INSERT INTO t1 VALUES($i,$r,'[number_name $r]');"
+}
+close $fd
+runtest {1000 INSERTs}
+
+
+
+set fd [open test$cnt.sql w]
+puts $fd "BEGIN;"
+puts $fd "CREATE TABLE t2(a INTEGER, b INTEGER, c VARCHAR(100));"
+for {set i 1} {$i<=25000} {incr i} {
+  set r [expr {int(rand()*500000)}]
+  puts $fd "INSERT INTO t2 VALUES($i,$r,'[number_name $r]');"
+}
+puts $fd "COMMIT;"
+close $fd
+runtest {25000 INSERTs in a transaction}
+
+
+
+set fd [open test$cnt.sql w]
+for {set i 0} {$i<100} {incr i} {
+  set lwr [expr {$i*100}]
+  set upr [expr {($i+10)*100}]
+  puts $fd "SELECT count(*), avg(b) FROM t2 WHERE b>=$lwr AND b<$upr;"
+}
+close $fd
+runtest {100 SELECTs without an index}
+
+
+
+set fd [open test$cnt.sql w]
+for {set i 1} {$i<=100} {incr i} {
+  puts $fd "SELECT count(*), avg(b) FROM t2 WHERE c LIKE '%[number_name $i]%';"
+}
+close $fd
+runtest {100 SELECTs on a string comparison}
+
+
+
+set fd [open test$cnt.sql w]
+puts $fd {CREATE INDEX i2a ON t2(a);}
+puts $fd {CREATE INDEX i2b ON t2(b);}
+close $fd
+runtest {Creating an index}
+
+
+
+set fd [open test$cnt.sql w]
+for {set i 0} {$i<5000} {incr i} {
+  set lwr [expr {$i*100}]
+  set upr [expr {($i+1)*100}]
+  puts $fd "SELECT count(*), avg(b) FROM t2 WHERE b>=$lwr AND b<$upr;"
+}
+close $fd
+runtest {5000 SELECTs with an index}
+
+
+
+set fd [open test$cnt.sql w]
+puts $fd "BEGIN;"
+for {set i 0} {$i<1000} {incr i} {
+  set lwr [expr {$i*10}]
+  set upr [expr {($i+1)*10}]
+  puts $fd "UPDATE t1 SET b=b*2 WHERE a>=$lwr AND a<$upr;"
+}
+puts $fd "COMMIT;"
+close $fd
+runtest {1000 UPDATEs without an index}
+
+
+
+set fd [open test$cnt.sql w]
+puts $fd "BEGIN;"
+for {set i 1} {$i<=25000} {incr i} {
+  set r [expr {int(rand()*500000)}]
+  puts $fd "UPDATE t2 SET b=$r WHERE a=$i;"
+}
+puts $fd "COMMIT;"
+close $fd
+runtest {25000 UPDATEs with an index}
+
+
+set fd [open test$cnt.sql w]
+puts $fd "BEGIN;"
+for {set i 1} {$i<=25000} {incr i} {
+  set r [expr {int(rand()*500000)}]
+  puts $fd "UPDATE t2 SET c='[number_name $r]' WHERE a=$i;"
+}
+puts $fd "COMMIT;"
+close $fd
+runtest {25000 text UPDATEs with an index}
+
+
+
+set fd [open test$cnt.sql w]
+puts $fd "BEGIN;"
+puts $fd "INSERT INTO t1 SELECT * FROM t2;"
+puts $fd "INSERT INTO t2 SELECT * FROM t1;"
+puts $fd "COMMIT;"
+close $fd
+runtest {INSERTs from a SELECT}
+
+
+
+set fd [open test$cnt.sql w]
+puts $fd {DELETE FROM t2 WHERE c LIKE '%fifty%';}
+close $fd
+runtest {DELETE without an index}
+
+
+
+set fd [open test$cnt.sql w]
+puts $fd {DELETE FROM t2 WHERE a>10 AND a<20000;}
+close $fd
+runtest {DELETE with an index}
+
+
+
+set fd [open test$cnt.sql w]
+puts $fd {INSERT INTO t2 SELECT * FROM t1;}
+close $fd
+runtest {A big INSERT after a big DELETE}
+
+
+
+set fd [open test$cnt.sql w]
+puts $fd {BEGIN;}
+puts $fd {DELETE FROM t1;}
+for {set i 1} {$i<=3000} {incr i} {
+  set r [expr {int(rand()*100000)}]
+  puts $fd "INSERT INTO t1 VALUES($i,$r,'[number_name $r]');"
+}
+puts $fd {COMMIT;}
+close $fd
+runtest {A big DELETE followed by many small INSERTs}
+
+set fd [open test$cnt.sql w]
+puts $fd {DROP TABLE t1;}
+puts $fd {DROP TABLE t2;}
+close $fd
+runtest {DROP TABLE}





More information about the llvm-commits mailing list