]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
initial check-in of the new version (CVS 1)
authordrh <drh@noemail.net>
Mon, 29 May 2000 14:26:00 +0000 (14:26 +0000)
committerdrh <drh@noemail.net>
Mon, 29 May 2000 14:26:00 +0000 (14:26 +0000)
FossilOrigin-Name: 6f3655f79f9b6fc9fb7baaa10a7e0f2b6a512dfa

25 files changed:
Makefile.in [new file with mode: 0644]
configure [new file with mode: 0755]
configure.in [new file with mode: 0644]
doc/lemon.html [new file with mode: 0644]
manifest
manifest.uuid
src/build.c [new file with mode: 0644]
src/dbbe.c [new file with mode: 0644]
src/dbbe.h [new file with mode: 0644]
src/main.c [new file with mode: 0644]
src/shell.c [new file with mode: 0644]
src/sqlite.h [new file with mode: 0644]
src/sqliteInt.h [new file with mode: 0644]
src/tclsqlite.c [new file with mode: 0644]
src/tokenize.c [new file with mode: 0644]
src/util.c [new file with mode: 0644]
src/vdbe.c [new file with mode: 0644]
src/vdbe.h [new file with mode: 0644]
src/where.c [new file with mode: 0644]
tool/gdbmdump.c [new file with mode: 0644]
tool/lemon.c [new file with mode: 0644]
tool/lempar.c [new file with mode: 0644]
tool/opNames.awk [new file with mode: 0644]
tool/opcodeDoc.awk [new file with mode: 0644]
tool/renumberOps.awk [new file with mode: 0644]

diff --git a/Makefile.in b/Makefile.in
new file mode 100644 (file)
index 0000000..5e9db18
--- /dev/null
@@ -0,0 +1,105 @@
+#!/usr/make
+#
+# Makefile for SQLITE
+
+# The toplevel directory of the source tree
+#
+TOP = @srcdir@
+
+# C Compiler and options for use in building executables that
+# will run on the platform that is doing the build.
+#
+BCC = @BUILD_CC@ @BUILD_CFLAGS@
+
+# C Compile and options for use in building executables that 
+# will run on the target platform.
+#
+TCC = @TARGET_CC@ @TARGET_CFLAGS@ -I. -I${TOP}/src
+
+# Tools used to build a static library.
+#
+AR = @TARGET_AR@
+RANLIB = @TARGET_RANLIB@
+
+# Compiler options needed for programs that use the GDBM library.
+#
+GDBM_FLAGS = @TARGET_GDBM_INC@
+
+# The library that programs using GDBM must link against.
+#
+LIBGDBM = @TARGET_GDBM_LIBS@
+
+# Compiler options needed for programs that use the readline() library.
+#
+READLINE_FLAGS = -DHAVE_READLINE=@TARGET_HAVE_READLINE@ @TARGET_READLINE_INC@
+
+# The library that programs using readline() must link against.
+#
+LIBREADLINE = @TARGET_READLINE_LIBS@
+
+# Object files for the SQLite library.
+#
+LIBOBJ = build.o dbbe.o main.o parse.o tokenize.o util.o vdbe.o where.o
+
+# This is the default Makefile target.  The objects listed here
+# are what get build when you type just "make" with no arguments.
+#
+all:   libsqlite.a sqlite
+# libtclsqlite.a tclsqlite
+
+libsqlite.a:   $(LIBOBJ)
+       $(AR) libsqlite.a $(LIBOBJ)
+       $(RANLIB) libsqlite.a
+
+sqlite:        $(TOP)/src/shell.c libsqlite.a $(TOP)/src/sqlite.h
+       $(TCC) $(READLINE_FLAGS) -o sqlite $(TOP)/src/shell.c \
+               libsqlite.a $(LIBGDBM) $(LIBREADLINE)
+
+# Rules to build the LEMON compiler generator
+#
+lemon: $(TOP)/tool/lemon.c $(TOP)/tool/lempar.c
+       $(BCC) -o lemon $(TOP)/tool/lemon.c
+       cp $(TOP)/tool/lempar.c .
+
+# Header files used by all library source files.
+#
+HDR = \
+   $(TOP)/src/sqlite.h  \
+   $(TOP)/src/sqliteInt.h  \
+   $(TOP)/src/dbbe.h  \
+   $(TOP)/src/vdbe.h  \
+   parse.h
+
+build.o:       $(TOP)/src/build.c $(HDR)
+       $(TCC) $(GDBM_FLAGS) -c $(TOP)/src/build.c
+
+dbbe.o:        $(TOP)/src/dbbe.c $(HDR)
+       $(TCC) $(GDBM_FLAGS) -c $(TOP)/src/dbbe.c
+
+main.o:        $(TOP)/src/main.c $(HDR)
+       $(TCC) $(GDBM_FLAGS) -c $(TOP)/src/main.c
+
+parse.o:       parse.c $(HDR)
+       $(TCC) $(GDBM_FLAGS) -c parse.c
+
+parse.h:       parse.c
+
+parse.c:       $(TOP)/src/parse.y lemon
+       cp $(TOP)/src/parse.y .
+       ./lemon parse.y
+
+tokenize.o:    $(TOP)/src/tokenize.c $(HDR)
+       $(TCC) $(GDBM_FLAGS) -c $(TOP)/src/tokenize.c
+
+util.o:        $(TOP)/src/util.c $(HDR)
+       $(TCC) $(GDBM_FLAGS) -c $(TOP)/src/util.c
+
+vdbe.o:        $(TOP)/src/vdbe.c $(HDR)
+       $(TCC) $(GDBM_FLAGS) -c $(TOP)/src/vdbe.c
+
+where.o:       $(TOP)/src/where.c $(HDR)
+       $(TCC) $(GDBM_FLAGS) -c $(TOP)/src/where.c
+
+clean: 
+       rm -f *.o sqlite libsqlite.a
+       rm -f lemon lempar.c parse.*
diff --git a/configure b/configure
new file mode 100755 (executable)
index 0000000..dbf4986
--- /dev/null
+++ b/configure
@@ -0,0 +1,2006 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13 
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+  --with-hints=FILE       Read configuration options from FILE"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval "$ac_prev=\$ac_option"
+    ac_prev=
+    continue
+  fi
+
+  case "$ac_option" in
+  -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) ac_optarg= ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case "$ac_option" in
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir="$ac_optarg" ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build="$ac_optarg" ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file="$ac_optarg" ;;
+
+  -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+  | --da=*)
+    datadir="$ac_optarg" ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    eval "enable_${ac_feature}=no" ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix="$ac_optarg" ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he)
+    # Omit some internal or obsolete options to make the list less imposing.
+    # This message is too long to be a string in the A/UX 3.1 sh.
+    cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+  --cache-file=FILE       cache test results in FILE
+  --help                  print this message
+  --no-create             do not create output files
+  --quiet, --silent       do not print \`checking...' messages
+  --version               print the version of autoconf that created configure
+Directory and file names:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [same as prefix]
+  --bindir=DIR            user executables in DIR [EPREFIX/bin]
+  --sbindir=DIR           system admin executables in DIR [EPREFIX/sbin]
+  --libexecdir=DIR        program executables in DIR [EPREFIX/libexec]
+  --datadir=DIR           read-only architecture-independent data in DIR
+                          [PREFIX/share]
+  --sysconfdir=DIR        read-only single-machine data in DIR [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data in DIR
+                          [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data in DIR [PREFIX/var]
+  --libdir=DIR            object code libraries in DIR [EPREFIX/lib]
+  --includedir=DIR        C header files in DIR [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc in DIR [/usr/include]
+  --infodir=DIR           info documentation in DIR [PREFIX/info]
+  --mandir=DIR            man documentation in DIR [PREFIX/man]
+  --srcdir=DIR            find the sources in DIR [configure dir or ..]
+  --program-prefix=PREFIX prepend PREFIX to installed program names
+  --program-suffix=SUFFIX append SUFFIX to installed program names
+  --program-transform-name=PROGRAM
+                          run sed PROGRAM on installed program names
+EOF
+    cat << EOF
+Host type:
+  --build=BUILD           configure for building on BUILD [BUILD=HOST]
+  --host=HOST             configure for HOST [guessed]
+  --target=TARGET         configure for TARGET [TARGET=HOST]
+Features and packages:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --x-includes=DIR        X include files are in DIR
+  --x-libraries=DIR       X library files are in DIR
+EOF
+    if test -n "$ac_help"; then
+      echo "--enable and --with options recognized:$ac_help"
+    fi
+    exit 0 ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host="$ac_optarg" ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir="$ac_optarg" ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir="$ac_optarg" ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir="$ac_optarg" ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir="$ac_optarg" ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst \
+  | --locals | --local | --loca | --loc | --lo)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+  | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+    localstatedir="$ac_optarg" ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir="$ac_optarg" ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir="$ac_optarg" ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix="$ac_optarg" ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix="$ac_optarg" ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix="$ac_optarg" ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name="$ac_optarg" ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir="$ac_optarg" ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir="$ac_optarg" ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site="$ac_optarg" ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir="$ac_optarg" ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir="$ac_optarg" ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target="$ac_optarg" ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers)
+    echo "configure generated by autoconf version 2.13"
+    exit 0 ;;
+
+  -with-* | --with-*)
+    ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "with_${ac_package}='$ac_optarg'" ;;
+
+  -without-* | --without-*)
+    ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    eval "with_${ac_package}=no" ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes="$ac_optarg" ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries="$ac_optarg" ;;
+
+  -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+    ;;
+
+  *)
+    if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+      echo "configure: warning: $ac_option: invalid host type" 1>&2
+    fi
+    if test "x$nonopt" != xNONE; then
+      { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+    fi
+    nonopt="$ac_option"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+  exec 6>/dev/null
+else
+  exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+  case "$ac_arg" in
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c) ;;
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+  *" "*|*"     "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+  ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+  *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+  esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set.  These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}"   = set; then LANG=C;   export LANG;   fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}"    = set; then LC_CTYPE=C;    export LC_CTYPE;    fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=src/sqlite.h
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then its parent.
+  ac_prog=$0
+  ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+  test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+  srcdir=$ac_confdir
+  if test ! -r $srcdir/$ac_unique_file; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+  if test "$ac_srcdir_defaulted" = yes; then
+    { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+  else
+    { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+  fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+  if test "x$prefix" != xNONE; then
+    CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+  else
+    CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+  fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+  if test -r "$ac_site_file"; then
+    echo "loading site script $ac_site_file"
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  echo "loading cache $cache_file"
+  . $cache_file
+else
+  echo "creating cache $cache_file"
+  > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+  # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+  if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+    ac_n= ac_c='
+' ac_t='       '
+  else
+    ac_n=-n ac_c= ac_t=
+  fi
+else
+  ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+# The following RCS revision string applies to configure.in
+# $Revision: 1.1 $
+
+#########
+# Make sure we are not building in a subdirectory of the source tree.
+#
+
+temp=`echo $srcdir | grep '[^./]'`
+
+if test "$temp" = ""; then
+  { echo "configure: error: 
+**************************************************************************
+** This program may not be compiled in the same directory that contains **
+** the configure script or any subdirectory of that directory.   Rerun  **
+** the configure script from a directory that is separate from the      **
+** source tree.                                                         **
+**************************************************************************" 1>&2; exit 1; }
+fi
+
+#########
+# Set up an appropriate program prefix
+#
+if test "$program_prefix" = "NONE"; then
+  program_prefix=""
+fi
+
+
+#########
+# Check to see if the --with-hints=FILE option is used.  If there is none,
+# then check for a files named "$host.hints" and ../$hosts.hints where
+# $host is the hostname of the build system.  If still no hints are
+# found, try looking in $system.hints and ../$system.hints where
+# $system is the result of uname -s.
+#
+# Check whether --with-hints or --without-hints was given.
+if test "${with_hints+set}" = set; then
+  withval="$with_hints"
+  hints=$withval
+fi
+
+if test "$hints" = ""; then
+  host=`hostname | sed 's/\..*//'`
+  if test -r $host.hints; then
+    hints=$host.hints
+  else
+     if test -r ../$host.hints; then
+       hints=../$host.hints
+     fi
+  fi
+fi
+if test "$hints" = ""; then
+  sys=`uname -s`
+  if test -r $sys.hints; then
+    hints=$sys.hints
+  else
+     if test -r ../$sys.hints; then
+       hints=../$sys.hints
+     fi
+  fi
+fi
+if test "$hints" != ""; then
+  echo "$ac_t""reading hints from $hints" 1>&6
+  . $hints
+fi
+
+#########
+# Locate a compiler for the build machine.  This compiler should
+# generate command-line programs that run on the build machine.
+#
+default_build_cflags="-g"
+if test "$config_BUILD_CC" = ""; then
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:602: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="gcc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:632: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_prog_rejected=no
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+        ac_prog_rejected=yes
+       continue
+      fi
+      ac_cv_prog_CC="cc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# -gt 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    set dummy "$ac_dir/$ac_word" "$@"
+    shift
+    ac_cv_prog_CC="$@"
+  fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+  if test -z "$CC"; then
+    case "`uname -s`" in
+    *win32* | *WIN32*)
+      # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:683: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="cl"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+ ;;
+    esac
+  fi
+  test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:715: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 726 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:731: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  ac_cv_prog_cc_works=yes
+  # If we can't run a trivial program, we are probably using a cross compiler.
+  if (./conftest; exit) 2>/dev/null; then
+    ac_cv_prog_cc_cross=no
+  else
+    ac_cv_prog_cc_cross=yes
+  fi
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+  { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:757: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:762: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.c <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:771: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gcc=yes
+else
+  ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:790: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+  ac_cv_prog_cc_g=yes
+else
+  ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+
+  if test "$cross_compiling" = "yes"; then
+    { echo "configure: error: unable to find a compiler for building build tools" 1>&2; exit 1; }
+  fi
+  BUILD_CC=$CC
+  default_build_cflags=$CFLAGS
+else
+  BUILD_CC=$config_BUILD_CC
+  echo $ac_n "checking host compiler""... $ac_c" 1>&6
+echo "configure:829: checking host compiler" >&5
+  CC=$BUILD_CC
+  echo "$ac_t""$BUILD_CC" 1>&6
+fi
+echo $ac_n "checking switches for the host compiler""... $ac_c" 1>&6
+echo "configure:834: checking switches for the host compiler" >&5
+if test "$config_BUILD_CFLAGS" != ""; then
+  CFLAGS=$config_BUILD_CFLAGS
+  BUILD_CFLAGS=$config_BUILD_CFLAGS
+else
+  BUILD_CFLAGS=$default_build_cflags
+fi
+echo "$ac_t""$BUILD_CFLAGS" 1>&6
+if test "$config_BUILD_LIBS" != ""; then
+  BUILD_LIBS=$config_BUILD_LIBS
+fi
+
+
+
+
+##########
+# Locate a compiler that converts C code into *.o files that run on
+# the target machine.
+#
+echo $ac_n "checking target compiler""... $ac_c" 1>&6
+echo "configure:854: checking target compiler" >&5
+if test "$config_TARGET_CC" != ""; then
+  TARGET_CC=$config_TARGET_CC
+else
+  TARGET_CC=$BUILD_CC
+fi
+echo "$ac_t""$TARGET_CC" 1>&6
+echo $ac_n "checking switches on the target compiler""... $ac_c" 1>&6
+echo "configure:862: checking switches on the target compiler" >&5
+if test "$config_TARGET_CFLAGS" != ""; then
+  TARGET_CFLAGS=$config_TARGET_CFLAGS
+else
+  TARGET_CFLAGS=$BUILD_CFLAGS
+fi
+echo "$ac_t""$TARGET_CFLAGS" 1>&6
+echo $ac_n "checking target linker""... $ac_c" 1>&6
+echo "configure:870: checking target linker" >&5
+if test "$config_TARGET_LINK" = ""; then
+  TARGET_LINK=$TARGET_CC
+else
+  TARGET_LINK=$config_TARGET_LINK
+fi
+echo "$ac_t""$TARGET_LINK" 1>&6
+echo $ac_n "checking switches on the target compiler""... $ac_c" 1>&6
+echo "configure:878: checking switches on the target compiler" >&5
+if test "$config_TARGET_TFLAGS" != ""; then
+  TARGET_TFLAGS=$config_TARGET_TFLAGS
+else
+  TARGET_TFLAGS=$BUILD_CFLAGS
+fi
+if test "$config_TARGET_RANLIB" != ""; then
+  TARGET_RANLIB=$config_TARGET_RANLIB
+else
+  # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:890: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_RANLIB="ranlib"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+  echo "$ac_t""$RANLIB" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+  TARGET_RANLIB=$RANLIB
+fi
+if test "$config_TARGET_AR" != ""; then
+  TARGET_RANLIB=$config_TARGET_AR
+else
+  TARGET_AR='ar cr'
+fi
+echo "$ac_t""$TARGET_TFLAGS" 1>&6
+
+
+
+
+
+
+
+# Set the $cross variable if we are cross-compiling.  Make
+# it 0 if we are not.
+#
+echo $ac_n "checking if host and target compilers are the same""... $ac_c" 1>&6
+echo "configure:936: checking if host and target compilers are the same" >&5
+if test "$BUILD_CC" = "$TARGET_CC"; then
+  cross=0
+  echo "$ac_t""yes" 1>&6
+else
+  cross=1
+  echo "$ac_t""no" 1>&6
+fi
+
+###########
+# Lots of things are different if we are compiling for Windows using
+# the CYGWIN environment.  So check for that special case and handle
+# things accordingly.
+#
+echo $ac_n "checking if executables have the .exe suffix""... $ac_c" 1>&6
+echo "configure:951: checking if executables have the .exe suffix" >&5
+if test "$config_BUILD_EXEEXT" = ".exe"; then
+  CYGWIN=yes
+  echo "$ac_t""yes" 1>&6
+else
+  echo "$ac_t""unknown" 1>&6
+fi
+if test "$CYGWIN" != "yes"; then
+  echo $ac_n "checking for Cygwin environment""... $ac_c" 1>&6
+echo "configure:960: checking for Cygwin environment" >&5
+if eval "test \"`echo '$''{'ac_cv_cygwin'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 965 "configure"
+#include "confdefs.h"
+
+int main() {
+
+#ifndef __CYGWIN__
+#define __CYGWIN__ __CYGWIN32__
+#endif
+return __CYGWIN__;
+; return 0; }
+EOF
+if { (eval echo configure:976: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_cygwin=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_cygwin=no
+fi
+rm -f conftest*
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_cygwin" 1>&6
+CYGWIN=
+test "$ac_cv_cygwin" = yes && CYGWIN=yes
+fi
+if test "$CYGWIN" = "yes"; then
+  BUILD_EXEEXT=.exe
+else
+  BUILD_EXEEXT=""
+fi
+if test "$cross" = "0"; then
+  TARGET_EXEEXT=$BUILD_EXEEXT
+else
+  TARGET_EXEEXT=$config_TARGET_EXEEXT
+fi
+if test "$TARGET_EXEEXT" = ".exe"; then
+  OS_UNIX=0
+  OS_WIN=1
+  tclsubdir=win
+else
+  OS_UNIX=1
+  OS_WIN=0
+  tclsubdir=unix
+fi
+TARGET_CFLAGS="$TARGET_CFLAGS -DOS_UNIX=$OS_UNIX -DOS_WIN=$OS_WIN"
+
+
+
+
+
+
+##########
+# Extract generic linker options from the environment.
+#
+if test "$config_TARGET_LIBS" != ""; then
+  TARGET_LIBS=$config_TARGET_LIBS
+else
+  TARGET_LIBS=""
+fi
+
+
+##########
+# Figure out what C libraries are required to compile Tcl programs.
+#
+if test "$config_TARGET_TCL_LIBS" != ""; then
+  TARGET_TCL_LIBS="$config_TARGET_TCL_LIBS"
+else
+  if test "$with_tcl" != ""; then
+    extra=`echo $with_tcl/$tclsubdir/libtcl8*.a`
+  fi
+  CC=$TARGET_CC
+  echo $ac_n "checking for sin""... $ac_c" 1>&6
+echo "configure:1040: checking for sin" >&5
+if eval "test \"`echo '$''{'ac_cv_func_sin'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1045 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char sin(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char sin();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_sin) || defined (__stub___sin)
+choke me
+#else
+sin();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1068: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_sin=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_sin=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'sin`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS=""
+else
+  echo "$ac_t""no" 1>&6
+LIBS="-lm"
+fi
+
+  echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6
+echo "configure:1089: checking for dlopen in -ldl" >&5
+ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-ldl  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1097 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char dlopen();
+
+int main() {
+dlopen()
+; return 0; }
+EOF
+if { (eval echo configure:1108: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo dl | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-ldl $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+  otherlibs=$LIBS
+  if test "$extra" != ""; then
+    LIBS=$extra
+  else 
+    LIBS=""
+    
+echo $ac_n "checking for library containing Tcl_Init""... $ac_c" 1>&6
+echo "configure:1142: checking for library containing Tcl_Init" >&5
+if eval "test \"`echo '$''{'ac_cv_search_Tcl_Init'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_func_search_save_LIBS="$LIBS"
+ac_cv_search_Tcl_Init="no"
+cat > conftest.$ac_ext <<EOF
+#line 1149 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char Tcl_Init();
+
+int main() {
+Tcl_Init()
+; return 0; }
+EOF
+if { (eval echo configure:1160: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  ac_cv_search_Tcl_Init="none required"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+test "$ac_cv_search_Tcl_Init" = "no" && for i in         tcl8.4 tcl8.3 tcl8.2 tcl8.1 tcl8.0 tcl80 tcl; do
+LIBS="-l$i $otherlibs $ac_func_search_save_LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1171 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char Tcl_Init();
+
+int main() {
+Tcl_Init()
+; return 0; }
+EOF
+if { (eval echo configure:1182: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  ac_cv_search_Tcl_Init="-l$i"
+break
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+done
+LIBS="$ac_func_search_save_LIBS"
+fi
+
+echo "$ac_t""$ac_cv_search_Tcl_Init" 1>&6
+if test "$ac_cv_search_Tcl_Init" != "no"; then
+  test "$ac_cv_search_Tcl_Init" = "none required" || LIBS="$ac_cv_search_Tcl_Init $LIBS"
+  
+else :
+  
+fi
+  fi
+  TARGET_TCL_LIBS="$LIBS $otherlibs"
+fi
+
+
+##########
+# Figure out where to get the TCL header files.
+#
+echo $ac_n "checking TCL header files""... $ac_c" 1>&6
+echo "configure:1211: checking TCL header files" >&5
+found=no
+if test "$config_TARGET_TCL_INC" != ""; then
+  TARGET_TCL_INC=$config_TARGET_TCL_INC
+  found=yes
+else
+  if test "$with_tcl" != ""; then
+    TARGET_TCL_INC="-I$with_tcl/generic -I$with_tcl/$tclsubdir"
+    found=yes
+  else
+    TARGET_TCL_INC=""
+    found=no
+  fi
+fi
+if test "$found" = "yes"; then
+  echo "$ac_t""$TARGET_TCL_INC" 1>&6
+else
+  echo "$ac_t""not specified: still searching..." 1>&6
+  echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:1230: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    # This must be in double quotes, not single quotes, because CPP may get
+  # substituted into the Makefile and "${CC-cc}" will confuse make.
+  CPP="${CC-cc} -E"
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp.
+  cat > conftest.$ac_ext <<EOF
+#line 1245 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1251: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -E -traditional-cpp"
+  cat > conftest.$ac_ext <<EOF
+#line 1262 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1268: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -nologo -E"
+  cat > conftest.$ac_ext <<EOF
+#line 1279 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1285: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+  ac_cv_prog_CPP="$CPP"
+fi
+  CPP="$ac_cv_prog_CPP"
+else
+  ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+ac_safe=`echo "tcl.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for tcl.h""... $ac_c" 1>&6
+echo "configure:1311: checking for tcl.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1316 "configure"
+#include "confdefs.h"
+#include <tcl.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1321: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  found=yes
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+if test "$found" = "no"; then
+  for dir in /usr/local /usr/X11* /usr/pkg /usr/contrib /usr; do
+    
+ac_safe=`echo "$dir/include/tcl.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $dir/include/tcl.h""... $ac_c" 1>&6
+echo "configure:1348: checking for $dir/include/tcl.h" >&5
+if eval "test \"`echo '$''{'ac_cv_file_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+    { echo "configure: error: Cannot check for file existence when cross compiling" 1>&2; exit 1; }
+else
+  if test -r $dir/include/tcl.h; then
+    eval "ac_cv_file_$ac_safe=yes"
+  else
+    eval "ac_cv_file_$ac_safe=no"
+  fi
+fi
+fi
+if eval "test \"`echo '$ac_cv_file_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  found=yes
+else
+  echo "$ac_t""no" 1>&6
+
+fi
+
+    if test "$found" = "yes"; then
+      TARGET_TCL_INC="-I$dir/include"
+      break
+    fi
+  done
+fi
+
+
+##########
+# Figure out what C libraries are required to compile programs
+# that use GDBM.
+#
+if test "$config_TARGET_GDBM_LIBS" != ""; then
+  TARGET_GDBM_LIBS="$config_TARGET_GDBM_LIBS"
+else
+  CC=$TARGET_CC
+  LIBS=""
+  
+echo $ac_n "checking for library containing gdbm_open""... $ac_c" 1>&6
+echo "configure:1389: checking for library containing gdbm_open" >&5
+if eval "test \"`echo '$''{'ac_cv_search_gdbm_open'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_func_search_save_LIBS="$LIBS"
+ac_cv_search_gdbm_open="no"
+cat > conftest.$ac_ext <<EOF
+#line 1396 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char gdbm_open();
+
+int main() {
+gdbm_open()
+; return 0; }
+EOF
+if { (eval echo configure:1407: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  ac_cv_search_gdbm_open="none required"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+test "$ac_cv_search_gdbm_open" = "no" && for i in gdbm; do
+LIBS="-l$i  $ac_func_search_save_LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1418 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char gdbm_open();
+
+int main() {
+gdbm_open()
+; return 0; }
+EOF
+if { (eval echo configure:1429: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  ac_cv_search_gdbm_open="-l$i"
+break
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+done
+LIBS="$ac_func_search_save_LIBS"
+fi
+
+echo "$ac_t""$ac_cv_search_gdbm_open" 1>&6
+if test "$ac_cv_search_gdbm_open" != "no"; then
+  test "$ac_cv_search_gdbm_open" = "none required" || LIBS="$ac_cv_search_gdbm_open $LIBS"
+  
+else :
+  
+fi
+  TARGET_GDBM_LIBS="$LIBS"
+fi
+
+
+##########
+# Figure out where to get the GDBM header files.
+#
+echo $ac_n "checking GDBM header files""... $ac_c" 1>&6
+echo "configure:1457: checking GDBM header files" >&5
+found=no
+if test "$config_TARGET_GDBM_INC" != ""; then
+  TARGET_GDBM_INC=$config_TARGET_GDBM_INC
+  found=yes
+fi
+if test "$found" = "yes"; then
+  echo "$ac_t""$TARGET_TCL_INC" 1>&6
+else
+  echo "$ac_t""not specified: still searching..." 1>&6
+  ac_safe=`echo "gdbm.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for gdbm.h""... $ac_c" 1>&6
+echo "configure:1469: checking for gdbm.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1474 "configure"
+#include "confdefs.h"
+#include <gdbm.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1479: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  found=yes
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+if test "$found" = "no"; then
+  for dir in /usr/local /usr/pkg /usr/contrib; do
+    
+ac_safe=`echo "$dir/include/gdbm.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $dir/include/gdbm.h""... $ac_c" 1>&6
+echo "configure:1506: checking for $dir/include/gdbm.h" >&5
+if eval "test \"`echo '$''{'ac_cv_file_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+    { echo "configure: error: Cannot check for file existence when cross compiling" 1>&2; exit 1; }
+else
+  if test -r $dir/include/gdbm.h; then
+    eval "ac_cv_file_$ac_safe=yes"
+  else
+    eval "ac_cv_file_$ac_safe=no"
+  fi
+fi
+fi
+if eval "test \"`echo '$ac_cv_file_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  found=yes
+else
+  echo "$ac_t""no" 1>&6
+
+fi
+
+    if test "$found" = "yes"; then
+      TARGET_GDBM_INC="-I$dir/include"
+      break
+    fi
+  done
+fi
+
+
+##########
+# Figure out what C libraries are required to compile programs
+# that use "readline()" library.
+#
+if test "$config_TARGET_READLINE_LIBS" != ""; then
+  TARGET_READLINE_LIBS="$config_TARGET_READLINE_LIBS"
+else
+  CC=$TARGET_CC
+  LIBS=""
+  
+echo $ac_n "checking for library containing readline""... $ac_c" 1>&6
+echo "configure:1547: checking for library containing readline" >&5
+if eval "test \"`echo '$''{'ac_cv_search_readline'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_func_search_save_LIBS="$LIBS"
+ac_cv_search_readline="no"
+cat > conftest.$ac_ext <<EOF
+#line 1554 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char readline();
+
+int main() {
+readline()
+; return 0; }
+EOF
+if { (eval echo configure:1565: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  ac_cv_search_readline="none required"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+test "$ac_cv_search_readline" = "no" && for i in readline; do
+LIBS="-l$i  $ac_func_search_save_LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1576 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char readline();
+
+int main() {
+readline()
+; return 0; }
+EOF
+if { (eval echo configure:1587: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  ac_cv_search_readline="-l$i"
+break
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+done
+LIBS="$ac_func_search_save_LIBS"
+fi
+
+echo "$ac_t""$ac_cv_search_readline" 1>&6
+if test "$ac_cv_search_readline" != "no"; then
+  test "$ac_cv_search_readline" = "none required" || LIBS="$ac_cv_search_readline $LIBS"
+  
+else :
+  
+fi
+  TARGET_READLINE_LIBS="$LIBS"
+fi
+
+
+##########
+# Figure out where to get the READLINE header files.
+#
+echo $ac_n "checking readline header files""... $ac_c" 1>&6
+echo "configure:1615: checking readline header files" >&5
+found=no
+if test "$config_TARGET_READLINE_INC" != ""; then
+  TARGET_READLINE_INC=$config_TARGET_READLINE_INC
+  found=yes
+fi
+if test "$found" = "yes"; then
+  echo "$ac_t""$TARGET_READLINE_INC" 1>&6
+else
+  echo "$ac_t""not specified: still searching..." 1>&6
+  ac_safe=`echo "readline.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for readline.h""... $ac_c" 1>&6
+echo "configure:1627: checking for readline.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1632 "configure"
+#include "confdefs.h"
+#include <readline.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1637: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  found=yes
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+if test "$found" = "no"; then
+  for dir in /usr /usr/local /usr/local/readline /usr/contrib; do
+    
+ac_safe=`echo "$dir/include/readline.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $dir/include/readline.h""... $ac_c" 1>&6
+echo "configure:1664: checking for $dir/include/readline.h" >&5
+if eval "test \"`echo '$''{'ac_cv_file_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+    { echo "configure: error: Cannot check for file existence when cross compiling" 1>&2; exit 1; }
+else
+  if test -r $dir/include/readline.h; then
+    eval "ac_cv_file_$ac_safe=yes"
+  else
+    eval "ac_cv_file_$ac_safe=no"
+  fi
+fi
+fi
+if eval "test \"`echo '$ac_cv_file_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  found=yes
+else
+  echo "$ac_t""no" 1>&6
+
+fi
+
+    if test "$found" = "yes"; then
+      TARGET_READLINE_INC="-I$dir/include"
+      break
+    fi
+    
+ac_safe=`echo "$dir/include/readline/readline.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $dir/include/readline/readline.h""... $ac_c" 1>&6
+echo "configure:1693: checking for $dir/include/readline/readline.h" >&5
+if eval "test \"`echo '$''{'ac_cv_file_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+    { echo "configure: error: Cannot check for file existence when cross compiling" 1>&2; exit 1; }
+else
+  if test -r $dir/include/readline/readline.h; then
+    eval "ac_cv_file_$ac_safe=yes"
+  else
+    eval "ac_cv_file_$ac_safe=no"
+  fi
+fi
+fi
+if eval "test \"`echo '$ac_cv_file_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  found=yes
+else
+  echo "$ac_t""no" 1>&6
+
+fi
+
+    if test "$found" = "yes"; then
+      TARGET_READLINE_INC="-I$dir/include/readline"
+      break
+    fi
+  done
+fi
+if test "$found" = "yes"; then
+  TARGET_HAVE_READLINE=1
+else
+  TARGET_HAVE_READLINE=0
+fi
+
+
+
+#########
+# Generate the output files.
+#
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs.  It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already.  You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+  case `(ac_space=' '; set | grep ac_space) 2>&1` in
+  *ac_space=\ *)
+    # `set' does not quote correctly, so add quotes (double-quote substitution
+    # turns \\\\ into \\, and sed turns \\ into \).
+    sed -n \
+      -e "s/'/'\\\\''/g" \
+      -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+    ;;
+  *)
+    # `set' quotes correctly as required by POSIX, so do not add quotes.
+    sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+    ;;
+  esac >> confcache
+if cmp -s $cache_file confcache; then
+  :
+else
+  if test -w $cache_file; then
+    echo "updating cache $cache_file"
+    cat confcache > $cache_file
+  else
+    echo "not updating unwritable cache $cache_file"
+  fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[        ]*VPATH[        ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+cat > conftest.defs <<\EOF
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g
+s%[    `~#$^&*(){}\\|;'"<>?]%\\&%g
+s%\[%\\&%g
+s%\]%\\&%g
+s%\$%$$%g
+EOF
+DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '`
+rm -f conftest.defs
+
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+  case "\$ac_option" in
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+    exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+  -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+    echo "$CONFIG_STATUS generated by autoconf version 2.13"
+    exit 0 ;;
+  -help | --help | --hel | --he | --h)
+    echo "\$ac_cs_usage"; exit 0 ;;
+  *) echo "\$ac_cs_usage"; exit 1 ;;
+  esac
+done
+
+ac_given_srcdir=$srcdir
+
+trap 'rm -fr `echo "Makefile" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@program_prefix@%$program_prefix%g
+s%@CC@%$CC%g
+s%@BUILD_CC@%$BUILD_CC%g
+s%@BUILD_CFLAGS@%$BUILD_CFLAGS%g
+s%@BUILD_LIBS@%$BUILD_LIBS%g
+s%@RANLIB@%$RANLIB%g
+s%@TARGET_CC@%$TARGET_CC%g
+s%@TARGET_CFLAGS@%$TARGET_CFLAGS%g
+s%@TARGET_LINK@%$TARGET_LINK%g
+s%@TARGET_LFLAGS@%$TARGET_LFLAGS%g
+s%@TARGET_RANLIB@%$TARGET_RANLIB%g
+s%@TARGET_AR@%$TARGET_AR%g
+s%@BUILD_EXEEXT@%$BUILD_EXEEXT%g
+s%@OS_UNIX@%$OS_UNIX%g
+s%@OS_WIN@%$OS_WIN%g
+s%@TARGET_EXEEXT@%$TARGET_EXEEXT%g
+s%@TARGET_LIBS@%$TARGET_LIBS%g
+s%@TARGET_TCL_LIBS@%$TARGET_TCL_LIBS%g
+s%@CPP@%$CPP%g
+s%@TARGET_TCL_INC@%$TARGET_TCL_INC%g
+s%@TARGET_GDBM_LIBS@%$TARGET_GDBM_LIBS%g
+s%@TARGET_GDBM_INC@%$TARGET_GDBM_INC%g
+s%@TARGET_READLINE_LIBS@%$TARGET_READLINE_LIBS%g
+s%@TARGET_READLINE_INC@%$TARGET_READLINE_INC%g
+s%@TARGET_HAVE_READLINE@%$TARGET_HAVE_READLINE%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+  if test $ac_beg -gt 1; then
+    sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+  else
+    sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+  fi
+  if test ! -s conftest.s$ac_file; then
+    ac_more_lines=false
+    rm -f conftest.s$ac_file
+  else
+    if test -z "$ac_sed_cmds"; then
+      ac_sed_cmds="sed -f conftest.s$ac_file"
+    else
+      ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+    fi
+    ac_file=`expr $ac_file + 1`
+    ac_beg=$ac_end
+    ac_end=`expr $ac_end + $ac_max_sed_cmds`
+  fi
+done
+if test -z "$ac_sed_cmds"; then
+  ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+  # Remove last slash and all that follows it.  Not all systems have dirname.
+  ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+  if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+    # The file is in a subdirectory.
+    test ! -d "$ac_dir" && mkdir "$ac_dir"
+    ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+    # A "../" for each directory in $ac_dir_suffix.
+    ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+  else
+    ac_dir_suffix= ac_dots=
+  fi
+
+  case "$ac_given_srcdir" in
+  .)  srcdir=.
+      if test -z "$ac_dots"; then top_srcdir=.
+      else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+  /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+  *) # Relative path.
+    srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+    top_srcdir="$ac_dots$ac_given_srcdir" ;;
+  esac
+
+
+  echo creating "$ac_file"
+  rm -f "$ac_file"
+  configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+  case "$ac_file" in
+  *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+  *) ac_comsub= ;;
+  esac
+
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
diff --git a/configure.in b/configure.in
new file mode 100644 (file)
index 0000000..a6f9a31
--- /dev/null
@@ -0,0 +1,513 @@
+#
+# This file describes a "configure" script that is used to build
+# makefiles for a particular platform.  Process this file using 
+# Autoconf version 1.13 in order to generate that script.  All 
+# lines of this file up to the AC_INIT macro are ignored.
+#
+# The build process allows for using a cross-compiler.  But the default
+# action is to target the same platform that we are running on.  The
+# configure script needs to discover the following properties of the 
+# build and target systems:
+#
+#    srcdir
+#
+#        The is the name of the directory that contains the
+#        "configure" shell script.  All source files are
+#        located relative to this directory.
+#
+#    bindir
+#
+#        The name of the directory where executables should be
+#        written by the "install" target of the makefile.
+#
+#    program_prefix
+#
+#        Add this prefix to the names of all executables that run
+#        on the target machine.  Default: ""
+#
+#    ENABLE_SHARED
+#
+#        True if shared libraries should be generated.
+#
+#    BUILD_CC
+#
+#        The name of a command that is used to convert C
+#        source files into executables that run on the build
+#        platform.
+#
+#    BUILD_CFLAGS
+#
+#        Switches that the build compiler needs in order to construct
+#        command-line programs.
+#
+#    BUILD_LIBS
+#
+#        Libraries that the build compiler needs in order to construct
+#        command-line programs.
+#
+#    BUILD_EXEEXT
+#
+#        The filename extension for executables on the build
+#        platform.  "" for Unix and ".exe" for Windows.
+#
+#    TARGET_CC
+#
+#        The name of a command that runs on the build platform
+#        and converts C source files into *.o files for the
+#        target platform.  In other words, the cross-compiler.
+#
+#    TARGET_CFLAGS
+#
+#        Switches that the target compiler needs to turn C source files
+#        into *.o files.  Do not include TARGET_TCL_INC in this list.
+#        Makefiles might add additional switches such as "-I.".
+#
+#    TARGET_TCL_LIBS
+#
+#        This is the library directives passed to the target linker
+#        that cause the executable to link against Tcl.  This might
+#        be a switch like "-ltcl8.0" or pathnames of library file
+#        like "../../src/libtcl8.0.a".
+#
+#    TARGET_TCL_INC
+#
+#        This variables define the directory that contain header
+#        files for Tcl.  If the compiler is able to find <tcl.h>
+#        on its own, then this can be blank.
+#
+#    TARGET_GDBM_LIBS
+#
+#        This is the library directives passed to the target linker
+#        that cause the executable to link against GDBM.  This might
+#        be a switch like "-lgdbm" or pathnames of library file
+#        like "../../src/libgdbm.a".
+#
+#    TARGET_GDBM_INC
+#
+#        This variables define the directory that contain header
+#        files for GDBM.  If the compiler is able to find <gdbm.h>
+#        on its own, then this can be blank.
+#
+#    TARGET_READLINE_LIBS
+#
+#        This is the library directives passed to the target linker
+#        that cause the executable to link against GDBM.  This might
+#        be a switch like "-lreadline" or pathnames of library file
+#        like "../../src/libreadline.a".
+#
+#    TARGET_READLINE_INC
+#
+#        This variables define the directory that contain header
+#        files for the readline library.  If the compiler is able 
+#        to find <readline.h> on its own, then this can be blank.
+#
+#    TARGET_LINK
+#
+#        The name of the linker that combines *.o files generated
+#        by TARGET_CC into executables for the target platform.
+#
+#    TARGET_LIBS
+#
+#        Additional libraries or other switch that the target linker needs
+#        to build an executable on the target.  Do not include
+#        on this list any libraries in TARGET_TCL_LIBS, TARGET_GDBM_LIBS,
+#        TARGET_READLINE_LIBS, etc.
+#
+#    TARGET_EXEEXT
+#
+#        The filename extension for executables on the
+#        target platform.  "" for Unix and ".exe" for windows.
+#
+# The generated configure script will make an attempt to guess
+# at all of the above parameters.  You can override any of
+# the guesses by setting the environment variable named
+# "config_AAAA" where "AAAA" is the name of the parameter
+# described above.  (Exception: srcdir cannot be set this way.)
+# If you have a file that sets one or more of these environment
+# variables, you can invoke configure as follows:
+#
+#           configure --with-hints=FILE
+#
+# where FILE is the name of the file that sets the environment
+# variables.  FILE should be an absolute pathname.
+#
+# If you have a Tcl/Tk/BLT source distribution available, then the
+# files in that distribution will be used instead of any other
+# Tcl/Tk/BLT files the script might discover if you tell the configure
+# script about the source tree.  Use commandline options:
+#
+#         --with-tcl=PATH  --with-tk=PATH  --with-blt=PATH
+#
+# Or set environment variables config_WITH_TCL, config_WITH_TK, or
+# config_WITH_BLT.
+#
+# This configure.in file is easy to reuse on other projects.  Just
+# change the argument to AC_INIT().  And disable any features that
+# you don't need (for example BLT) by erasing or commenting out
+# the corresponding code.
+#
+AC_INIT(src/sqlite.h)
+
+dnl Put the RCS revision string after AC_INIT so that it will also
+dnl show in in configure.
+# The following RCS revision string applies to configure.in
+# $Revision: 1.1 $
+
+#########
+# Make sure we are not building in a subdirectory of the source tree.
+#
+changequote(<<<,>>>)
+temp=`echo $srcdir | grep '[^./]'`
+changequote([,])
+if test "$temp" = ""; then
+  AC_MSG_ERROR([
+**************************************************************************
+** This program may not be compiled in the same directory that contains **
+** the configure script or any subdirectory of that directory.   Rerun  **
+** the configure script from a directory that is separate from the      **
+** source tree.                                                         **
+**************************************************************************])
+fi
+
+#########
+# Set up an appropriate program prefix
+#
+if test "$program_prefix" = "NONE"; then
+  program_prefix=""
+fi
+AC_SUBST(program_prefix)
+
+#########
+# Check to see if the --with-hints=FILE option is used.  If there is none,
+# then check for a files named "$host.hints" and ../$hosts.hints where
+# $host is the hostname of the build system.  If still no hints are
+# found, try looking in $system.hints and ../$system.hints where
+# $system is the result of uname -s.
+#
+AC_ARG_WITH(hints,
+  [  --with-hints=FILE       Read configuration options from FILE],
+  hints=$withval)
+if test "$hints" = ""; then
+  host=`hostname | sed 's/\..*//'`
+  if test -r $host.hints; then
+    hints=$host.hints
+  else
+     if test -r ../$host.hints; then
+       hints=../$host.hints
+     fi
+  fi
+fi
+if test "$hints" = ""; then
+  sys=`uname -s`
+  if test -r $sys.hints; then
+    hints=$sys.hints
+  else
+     if test -r ../$sys.hints; then
+       hints=../$sys.hints
+     fi
+  fi
+fi
+if test "$hints" != ""; then
+  AC_MSG_RESULT(reading hints from $hints)
+  . $hints
+fi
+
+#########
+# Locate a compiler for the build machine.  This compiler should
+# generate command-line programs that run on the build machine.
+#
+default_build_cflags="-g"
+if test "$config_BUILD_CC" = ""; then
+  AC_PROG_CC
+  if test "$cross_compiling" = "yes"; then
+    AC_MSG_ERROR([unable to find a compiler for building build tools])
+  fi
+  BUILD_CC=$CC
+  default_build_cflags=$CFLAGS
+else
+  BUILD_CC=$config_BUILD_CC
+  AC_MSG_CHECKING([host compiler])
+  CC=$BUILD_CC
+  AC_MSG_RESULT($BUILD_CC)
+fi
+AC_MSG_CHECKING([switches for the host compiler])
+if test "$config_BUILD_CFLAGS" != ""; then
+  CFLAGS=$config_BUILD_CFLAGS
+  BUILD_CFLAGS=$config_BUILD_CFLAGS
+else
+  BUILD_CFLAGS=$default_build_cflags
+fi
+AC_MSG_RESULT($BUILD_CFLAGS)
+if test "$config_BUILD_LIBS" != ""; then
+  BUILD_LIBS=$config_BUILD_LIBS
+fi
+AC_SUBST(BUILD_CC)
+AC_SUBST(BUILD_CFLAGS)
+AC_SUBST(BUILD_LIBS)
+
+##########
+# Locate a compiler that converts C code into *.o files that run on
+# the target machine.
+#
+AC_MSG_CHECKING([target compiler])
+if test "$config_TARGET_CC" != ""; then
+  TARGET_CC=$config_TARGET_CC
+else
+  TARGET_CC=$BUILD_CC
+fi
+AC_MSG_RESULT($TARGET_CC)
+AC_MSG_CHECKING([switches on the target compiler])
+if test "$config_TARGET_CFLAGS" != ""; then
+  TARGET_CFLAGS=$config_TARGET_CFLAGS
+else
+  TARGET_CFLAGS=$BUILD_CFLAGS
+fi
+AC_MSG_RESULT($TARGET_CFLAGS)
+AC_MSG_CHECKING([target linker])
+if test "$config_TARGET_LINK" = ""; then
+  TARGET_LINK=$TARGET_CC
+else
+  TARGET_LINK=$config_TARGET_LINK
+fi
+AC_MSG_RESULT($TARGET_LINK)
+AC_MSG_CHECKING([switches on the target compiler])
+if test "$config_TARGET_TFLAGS" != ""; then
+  TARGET_TFLAGS=$config_TARGET_TFLAGS
+else
+  TARGET_TFLAGS=$BUILD_CFLAGS
+fi
+if test "$config_TARGET_RANLIB" != ""; then
+  TARGET_RANLIB=$config_TARGET_RANLIB
+else
+  AC_PROG_RANLIB
+  TARGET_RANLIB=$RANLIB
+fi
+if test "$config_TARGET_AR" != ""; then
+  TARGET_RANLIB=$config_TARGET_AR
+else
+  TARGET_AR='ar cr'
+fi
+AC_MSG_RESULT($TARGET_TFLAGS)
+AC_SUBST(TARGET_CC)
+AC_SUBST(TARGET_CFLAGS)
+AC_SUBST(TARGET_LINK)
+AC_SUBST(TARGET_LFLAGS)
+AC_SUBST(TARGET_RANLIB)
+AC_SUBST(TARGET_AR)
+
+# Set the $cross variable if we are cross-compiling.  Make
+# it 0 if we are not.
+#
+AC_MSG_CHECKING([if host and target compilers are the same])
+if test "$BUILD_CC" = "$TARGET_CC"; then
+  cross=0
+  AC_MSG_RESULT(yes)
+else
+  cross=1
+  AC_MSG_RESULT(no)
+fi
+
+###########
+# Lots of things are different if we are compiling for Windows using
+# the CYGWIN environment.  So check for that special case and handle
+# things accordingly.
+#
+AC_MSG_CHECKING([if executables have the .exe suffix])
+if test "$config_BUILD_EXEEXT" = ".exe"; then
+  CYGWIN=yes
+  AC_MSG_RESULT(yes)
+else
+  AC_MSG_RESULT(unknown)
+fi
+if test "$CYGWIN" != "yes"; then
+  AC_CYGWIN
+fi
+if test "$CYGWIN" = "yes"; then
+  BUILD_EXEEXT=.exe
+else
+  BUILD_EXEEXT=""
+fi
+if test "$cross" = "0"; then
+  TARGET_EXEEXT=$BUILD_EXEEXT
+else
+  TARGET_EXEEXT=$config_TARGET_EXEEXT
+fi
+if test "$TARGET_EXEEXT" = ".exe"; then
+  OS_UNIX=0
+  OS_WIN=1
+  tclsubdir=win
+else
+  OS_UNIX=1
+  OS_WIN=0
+  tclsubdir=unix
+fi
+TARGET_CFLAGS="$TARGET_CFLAGS -DOS_UNIX=$OS_UNIX -DOS_WIN=$OS_WIN"
+
+AC_SUBST(BUILD_EXEEXT)
+AC_SUBST(OS_UNIX)
+AC_SUBST(OS_WIN)
+AC_SUBST(TARGET_EXEEXT)
+
+##########
+# Extract generic linker options from the environment.
+#
+if test "$config_TARGET_LIBS" != ""; then
+  TARGET_LIBS=$config_TARGET_LIBS
+else
+  TARGET_LIBS=""
+fi
+AC_SUBST(TARGET_LIBS)
+
+##########
+# Figure out what C libraries are required to compile Tcl programs.
+#
+if test "$config_TARGET_TCL_LIBS" != ""; then
+  TARGET_TCL_LIBS="$config_TARGET_TCL_LIBS"
+else
+  if test "$with_tcl" != ""; then
+    extra=`echo $with_tcl/$tclsubdir/libtcl8*.a`
+  fi
+  CC=$TARGET_CC
+  AC_CHECK_FUNC(sin, LIBS="", LIBS="-lm")
+  AC_CHECK_LIB(dl, dlopen)
+  otherlibs=$LIBS
+  if test "$extra" != ""; then
+    LIBS=$extra
+  else 
+    LIBS=""
+    AC_SEARCH_LIBS(Tcl_Init, dnl
+        tcl8.4 tcl8.3 tcl8.2 tcl8.1 tcl8.0 tcl80 tcl,,,$otherlibs)
+  fi
+  TARGET_TCL_LIBS="$LIBS $otherlibs"
+fi
+AC_SUBST(TARGET_TCL_LIBS)
+
+##########
+# Figure out where to get the TCL header files.
+#
+AC_MSG_CHECKING([TCL header files])
+found=no
+if test "$config_TARGET_TCL_INC" != ""; then
+  TARGET_TCL_INC=$config_TARGET_TCL_INC
+  found=yes
+else
+  if test "$with_tcl" != ""; then
+    TARGET_TCL_INC="-I$with_tcl/generic -I$with_tcl/$tclsubdir"
+    found=yes
+  else
+    TARGET_TCL_INC=""
+    found=no
+  fi
+fi
+if test "$found" = "yes"; then
+  AC_MSG_RESULT($TARGET_TCL_INC)
+else
+  AC_MSG_RESULT(not specified: still searching...)
+  AC_CHECK_HEADER(tcl.h, [found=yes])
+fi
+if test "$found" = "no"; then
+  for dir in /usr/local /usr/X11* /usr/pkg /usr/contrib /usr; do
+    AC_CHECK_FILE($dir/include/tcl.h, found=yes)
+    if test "$found" = "yes"; then
+      TARGET_TCL_INC="-I$dir/include"
+      break
+    fi
+  done
+fi
+AC_SUBST(TARGET_TCL_INC)
+
+##########
+# Figure out what C libraries are required to compile programs
+# that use GDBM.
+#
+if test "$config_TARGET_GDBM_LIBS" != ""; then
+  TARGET_GDBM_LIBS="$config_TARGET_GDBM_LIBS"
+else
+  CC=$TARGET_CC
+  LIBS=""
+  AC_SEARCH_LIBS(gdbm_open, gdbm,,,)
+  TARGET_GDBM_LIBS="$LIBS"
+fi
+AC_SUBST(TARGET_GDBM_LIBS)
+
+##########
+# Figure out where to get the GDBM header files.
+#
+AC_MSG_CHECKING([GDBM header files])
+found=no
+if test "$config_TARGET_GDBM_INC" != ""; then
+  TARGET_GDBM_INC=$config_TARGET_GDBM_INC
+  found=yes
+fi
+if test "$found" = "yes"; then
+  AC_MSG_RESULT($TARGET_TCL_INC)
+else
+  AC_MSG_RESULT(not specified: still searching...)
+  AC_CHECK_HEADER(gdbm.h, [found=yes])
+fi
+if test "$found" = "no"; then
+  for dir in /usr/local /usr/pkg /usr/contrib; do
+    AC_CHECK_FILE($dir/include/gdbm.h, found=yes)
+    if test "$found" = "yes"; then
+      TARGET_GDBM_INC="-I$dir/include"
+      break
+    fi
+  done
+fi
+AC_SUBST(TARGET_GDBM_INC)
+
+##########
+# Figure out what C libraries are required to compile programs
+# that use "readline()" library.
+#
+if test "$config_TARGET_READLINE_LIBS" != ""; then
+  TARGET_READLINE_LIBS="$config_TARGET_READLINE_LIBS"
+else
+  CC=$TARGET_CC
+  LIBS=""
+  AC_SEARCH_LIBS(readline, readline,,,)
+  TARGET_READLINE_LIBS="$LIBS"
+fi
+AC_SUBST(TARGET_READLINE_LIBS)
+
+##########
+# Figure out where to get the READLINE header files.
+#
+AC_MSG_CHECKING([readline header files])
+found=no
+if test "$config_TARGET_READLINE_INC" != ""; then
+  TARGET_READLINE_INC=$config_TARGET_READLINE_INC
+  found=yes
+fi
+if test "$found" = "yes"; then
+  AC_MSG_RESULT($TARGET_READLINE_INC)
+else
+  AC_MSG_RESULT(not specified: still searching...)
+  AC_CHECK_HEADER(readline.h, [found=yes])
+fi
+if test "$found" = "no"; then
+  for dir in /usr /usr/local /usr/local/readline /usr/contrib; do
+    AC_CHECK_FILE($dir/include/readline.h, found=yes)
+    if test "$found" = "yes"; then
+      TARGET_READLINE_INC="-I$dir/include"
+      break
+    fi
+    AC_CHECK_FILE($dir/include/readline/readline.h, found=yes)
+    if test "$found" = "yes"; then
+      TARGET_READLINE_INC="-I$dir/include/readline"
+      break
+    fi
+  done
+fi
+if test "$found" = "yes"; then
+  TARGET_HAVE_READLINE=1
+else
+  TARGET_HAVE_READLINE=0
+fi
+AC_SUBST(TARGET_READLINE_INC)
+AC_SUBST(TARGET_HAVE_READLINE)
+
+#########
+# Generate the output files.
+#
+AC_OUTPUT(Makefile)
diff --git a/doc/lemon.html b/doc/lemon.html
new file mode 100644 (file)
index 0000000..9b4648f
--- /dev/null
@@ -0,0 +1,861 @@
+<html>
+<head>
+<title>The Lemon Parser Generator</title>
+</head>
+<body bgcolor=white>
+<h1 align=center>The Lemon Parser Generator</h1>
+
+<p>Lemon is an LALR(1) parser generator for C or C++.  
+It does the same job as ``bison'' and ``yacc''.
+But lemon is not another bison or yacc clone.  It
+uses a different grammar syntax which is designed to
+reduce the number of coding errors.  Lemon also uses a more
+sophisticated parsing engine that is faster than yacc and
+bison and which is both reentrant and thread-safe.
+Furthermore, Lemon implements features that can be used
+to eliminate resource leaks, making is suitable for use
+in long-running programs such as graphical user interfaces
+or embedded controllers.</p>
+
+<p>This document is an introduction to the Lemon
+parser generator.</p>
+
+<h2>Theory of Operation</h2>
+
+<p>The main goal of Lemon is to translate a context free grammar (CFG)
+for a particular language into C code that implements a parser for
+that language.
+The program has two inputs:
+<ul>
+<li>The grammar specification.
+<li>A parser template file.
+</ul>
+Typically, only the grammar specification is supplied by the programmer.
+Lemon comes with a default parser template which works fine for most
+applications.  But the user is free to substitute a different parser
+template if desired.</p>
+
+<p>Depending on command-line options, Lemon will generate between
+one and three files of outputs.
+<ul>
+<li>C code to implement the parser.
+<li>A header file defining an integer ID for each terminal symbol.
+<li>An information file that describes the states of the generated parser
+    automaton.
+</ul>
+By default, all three of these output files are generated.
+The header file is suppressed if the ``-m'' command-line option is
+used and the report file is omitted when ``-q'' is selected.</p>
+
+<p>The grammar specification file uses a ``.y'' suffix, by convention.
+In the examples used in this document, we'll assume the name of the
+grammar file is ``gram.y''.  A typical use of Lemon would be the
+following command:
+<pre>
+   lemon gram.y
+</pre>
+This command will generate three output files named ``gram.c'',
+``gram.h'' and ``gram.out''.
+The first is C code to implement the parser.  The second
+is the header file that defines numerical values for all
+terminal symbols, and the last is the report that explains
+the states used by the parser automaton.</p>
+
+<h3>Command Line Options</h3>
+
+<p>The behavior of Lemon can be modified using command-line options.
+You can obtain a list of the available command-line options together
+with a brief explanation of what each does by typing
+<pre>
+   lemon -?
+</pre>
+As of this writing, the following command-line options are supported:
+<ul>
+<li><tt>-b</tt>
+<li><tt>-c</tt>
+<li><tt>-g</tt>
+<li><tt>-m</tt>
+<li><tt>-q</tt>
+<li><tt>-s</tt>
+<li><tt>-x</tt>
+</ul>
+The ``-b'' option reduces the amount of text in the report file by
+printing only the basis of each parser state, rather than the full
+configuration.
+The ``-c'' option suppresses action table compression.  Using -c
+will make the parser a little larger and slower but it will detect
+syntax errors sooner.
+The ``-g'' option causes no output files to be generated at all.
+Instead, the input grammar file is printed on standard output but
+with all comments, actions and other extraneous text deleted.  This
+is a useful way to get a quick summary of a grammar.
+The ``-m'' option causes the output C source file to be compatible
+with the ``makeheaders'' program.
+Makeheaders is a program that automatically generates header files
+from C source code.  When the ``-m'' option is used, the header
+file is not output since the makeheaders program will take care
+of generated all header files automatically.
+The ``-q'' option suppresses the report file.
+Using ``-s'' causes a brief summary of parser statistics to be
+printed.  Like this:
+<pre>
+   Parser statistics: 74 terminals, 70 nonterminals, 179 rules
+                      340 states, 2026 parser table entries, 0 conflicts
+</pre>
+Finally, the ``-x'' option causes Lemon to print its version number
+and copyright information
+and then stop without attempting to read the grammar or generate a parser.</p>
+
+<h3>The Parser Interface</h3>
+
+<p>Lemon doesn't generate a complete, working program.  It only generates
+a few subroutines that implement a parser.  This section describes
+the interface to those subroutines.  It is up to the programmer to
+call these subroutines in an appropriate way in order to produce a
+complete system.</p>
+
+<p>Before a program begins using a Lemon-generated parser, the program
+must first create the parser.
+A new parser is created as follows:
+<pre>
+   void *pParser = ParseAlloc( malloc );
+</pre>
+The ParseAlloc() routine allocates and initializes a new parser and
+returns a pointer to it.
+The actual data structure used to represent a parser is opaque --
+its internal structure is not visible or usable by the calling routine.
+For this reason, the ParseAlloc() routine returns a pointer to void
+rather than a pointer to some particular structure.
+The sole argument to the ParseAlloc() routine is a pointer to the
+subroutine used to allocate memory.  Typically this means ``malloc()''.</p>
+
+<p>After a program is finished using a parser, it can reclaim all
+memory allocated by that parser by calling
+<pre>
+   ParseFree(pParser, free);
+</pre>
+The first argument is the same pointer returned by ParseAlloc().  The
+second argument is a pointer to the function used to release bulk
+memory back to the system.</p>
+
+<p>After a parser has been allocated using ParseAlloc(), the programmer
+must supply the parser with a sequence of tokens (terminal symbols) to
+be parsed.  This is accomplished by calling the following function
+once for each token:
+<pre>
+   Parse(pParser, hTokenID, sTokenData, pArg);
+</pre>
+The first argument to the Parse() routine is the pointer returned by
+ParseAlloc().
+The second argument is a small positive integer that tells the parse the
+type of the next token in the data stream.
+There is one token type for each terminal symbol in the grammar.
+The gram.h file generated by Lemon contains #define statements that
+map symbolic terminal symbol names into appropriate integer values.
+(A value of 0 for the second argument is a special flag to the
+parser to indicate that the end of input has been reached.)
+The third argument is the value of the given token.  By default,
+the type of the third argument is integer, but the grammar will
+usually redefine this type to be some kind of structure.
+Typically the second argument will be a broad category of tokens
+such as ``identifier'' or ``number'' and the third argument will
+be the name of the identifier or the value of the number.</p>
+
+<p>The Parse() function may have either three or four arguments,
+depending on the grammar.  If the grammar specification file request
+it, the Parse() function will have a fourth parameter that can be
+of any type chosen by the programmer.  The parser doesn't do anything
+with this argument except to pass it through to action routines.
+This is a convenient mechanism for passing state information down
+to the action routines without having to use global variables.</p>
+
+<p>A typical use of a Lemon parser might look something like the
+following:
+<pre>
+   01 ParseTree *ParseFile(const char *zFilename){
+   02    Tokenizer *pTokenizer;
+   03    void *pParser;
+   04    Token sToken;
+   05    int hTokenId;
+   06    ParserState sState;
+   07
+   08    pTokenizer = TokenizerCreate(zFilename);
+   09    pParser = ParseAlloc( malloc );
+   10    InitParserState(&sState);
+   11    while( GetNextToken(pTokenizer, &hTokenId, &sToken) ){
+   12       Parse(pParser, hTokenId, sToken, &sState);
+   13    }
+   14    Parse(pParser, 0, sToken, &sState);
+   15    ParseFree(pParser, free );
+   16    TokenizerFree(pTokenizer);
+   17    return sState.treeRoot;
+   18 }
+</pre>
+This example shows a user-written routine that parses a file of
+text and returns a pointer to the parse tree.
+(We've omitted all error-handling from this example to keep it
+simple.)
+We assume the existence of some kind of tokenizer which is created
+using TokenizerCreate() on line 8 and deleted by TokenizerFree()
+on line 16.  The GetNextToken() function on line 11 retrieves the
+next token from the input file and puts its type in the 
+integer variable hTokenId.  The sToken variable is assumed to be
+some kind of structure that contains details about each token,
+such as its complete text, what line it occurs on, etc. </p>
+
+<p>This example also assumes the existence of structure of type
+ParserState that holds state information about a particular parse.
+An instance of such a structure is created on line 6 and initialized
+on line 10.  A pointer to this structure is passed into the Parse()
+routine as the optional 4th argument.
+The action routine specified by the grammar for the parser can use
+the ParserState structure to hold whatever information is useful and
+appropriate.  In the example, we note that the treeRoot field of
+the ParserState structure is left pointing to the root of the parse
+tree.</p>
+
+<p>The core of this example as it relates to Lemon is as follows:
+<pre>
+   ParseFile(){
+      pParser = ParseAlloc( malloc );
+      while( GetNextToken(pTokenizer,&hTokenId, &sToken) ){
+         Parse(pParser, hTokenId, sToken);
+      }
+      Parse(pParser, 0, sToken);
+      ParseFree(pParser, free );
+   }
+</pre>
+Basically, what a program has to do to use a Lemon-generated parser
+is first create the parser, then send it lots of tokens obtained by
+tokenizing an input source.  When the end of input is reached, the
+Parse() routine should be called one last time with a token type
+of 0.  This step is necessary to inform the parser that the end of
+input has been reached.  Finally, we reclaim memory used by the
+parser by calling ParseFree().</p>
+
+<p>There is one other interface routine that should be mentioned
+before we move on.
+The ParseTrace() function can be used to generate debugging output
+from the parser.  A prototype for this routine is as follows:
+<pre>
+   ParseTrace(FILE *stream, char *zPrefix);
+</pre>
+After this routine is called, a short (one-line) message is written
+to the designated output stream every time the parser changes states
+or calls an action routine.  Each such message is prefaced using
+the text given by zPrefix.  This debugging output can be turned off
+by calling ParseTrace() again with a first argument of NULL (0).</p>
+
+<h3>Differences With YACC and BISON</h3>
+
+<p>Programmers who have previously used the yacc or bison parser
+generator will notice several important differences between yacc and/or
+bison and Lemon.
+<ul>
+<li>In yacc and bison, the parser calls the tokenizer.  In Lemon,
+    the tokenizer calls the parser.
+<li>Lemon uses no global variables.  Yacc and bison use global variables
+    to pass information between the tokenizer and parser.
+<li>Lemon allows multiple parsers to be running simultaneously.  Yacc
+    and bison do not.
+</ul>
+These differences may cause some initial confusion for programmers
+with prior yacc and bison experience.
+But after years of experience using Lemon, I firmly
+believe that the Lemon way of doing things is better.</p>
+
+<h2>Input File Syntax</h2>
+
+<p>The main purpose of the grammar specification file for Lemon is
+to define the grammar for the parser.  But the input file also
+specifies additional information Lemon requires to do its job.
+Most of the work in using Lemon is in writing an appropriate
+grammar file.</p>
+
+<p>The grammar file for lemon is, for the most part, free format.
+It does not have sections or divisions like yacc or bison.  Any
+declaration can occur at any point in the file.
+Lemon ignores whitespace (except where it is needed to separate
+tokens) and it honors the same commenting conventions as C and C++.</p>
+
+<h3>Terminals and Nonterminals</h3>
+
+<p>A terminal symbol (token) is any string of alphanumeric
+and underscore characters
+that begins with an upper case letter.
+A terminal can contain lower class letters after the first character,
+but the usual convention is to make terminals all upper case.
+A nonterminal, on the other hand, is any string of alphanumeric
+and underscore characters than begins with a lower case letter.
+Again, the usual convention is to make nonterminals use all lower
+case letters.</p>
+
+<p>In Lemon, terminal and nonterminal symbols do not need to 
+be declared or identified in a separate section of the grammar file.
+Lemon is able to generate a list of all terminals and nonterminals
+by examining the grammar rules, and it can always distinguish a
+terminal from a nonterminal by checking the case of the first
+character of the name.</p>
+
+<p>Yacc and bison allow terminal symbols to have either alphanumeric
+names or to be individual characters included in single quotes, like
+this: ')' or '$'.  Lemon does not allow this alternative form for
+terminal symbols.  With Lemon, all symbols, terminals and nonterminals,
+must have alphanumeric names.</p>
+
+<h3>Grammar Rules</h3>
+
+<p>The main component of a Lemon grammar file is a sequence of grammar
+rules.
+Each grammar rule consists of a nonterminal symbol followed by
+the special symbol ``::='' and then a list of terminals and/or nonterminals.
+The rule is terminated by a period.
+The list of terminals and nonterminals on the right-hand side of the
+rule can be empty.
+Rules can occur in any order, except that the left-hand side of the
+first rule is assumed to be the start symbol for the grammar (unless
+specified otherwise using the <tt>%start</tt> directive described below.)
+A typical sequence of grammar rules might look something like this:
+<pre>
+  expr ::= expr PLUS expr.
+  expr ::= expr TIMES expr.
+  expr ::= LPAREN expr RPAREN.
+  expr ::= VALUE.
+</pre>
+</p>
+
+<p>There is one non-terminal in this example, ``expr'', and five
+terminal symbols or tokens: ``PLUS'', ``TIMES'', ``LPAREN'',
+``RPAREN'' and ``VALUE''.</p>
+
+<p>Like yacc and bison, Lemon allows the grammar to specify a block
+of C code that will be executed whenever a grammar rule is reduced
+by the parser.
+In Lemon, this action is specified by putting the C code (contained
+within curly braces <tt>{...}</tt>) immediately after the
+period that closes the rule.
+For example:
+<pre>
+  expr ::= expr PLUS expr.   { printf("Doing an addition...\n"); }
+</pre>
+</p>
+
+<p>In order to be useful, grammar actions must normally be linked to
+their associated grammar rules.
+In yacc and bison, this is accomplished by embedding a ``$$'' in the
+action to stand for the value of the left-hand side of the rule and
+symbols ``$1'', ``$2'', and so forth to stand for the value of
+the terminal or nonterminal at position 1, 2 and so forth on the
+right-hand side of the rule.
+This idea is very powerful, but it is also very error-prone.  The
+single most common source of errors in a yacc or bison grammar is
+to miscount the number of symbols on the right-hand side of a grammar
+rule and say ``$7'' when you really mean ``$8''.</p>
+
+<p>Lemon avoids the need to count grammar symbols by assigning symbolic
+names to each symbol in a grammar rule and then using those symbolic
+names in the action.
+In yacc or bison, one would write this:
+<pre>
+  expr -> expr PLUS expr  { $$ = $1 + $3; };
+</pre>
+But in Lemon, the same rule becomes the following:
+<pre>
+  expr(A) ::= expr(B) PLUS expr(C).  { A = B+C; }
+</pre>
+In the Lemon rule, any symbol in parentheses after a grammar rule
+symbol becomes a place holder for that symbol in the grammar rule.
+This place holder can then be used in the associated C action to
+stand for the value of that symbol.<p>
+
+<p>The Lemon notation for linking a grammar rule with its reduce
+action is superior to yacc/bison on several counts.
+First, as mentioned above, the Lemon method avoids the need to
+count grammar symbols.
+Secondly, if a terminal or nonterminal in a Lemon grammar rule
+includes a linking symbol in parentheses but that linking symbol
+is not actually used in the reduce action, then an error message
+is generated.
+For example, the rule
+<pre>
+  expr(A) ::= expr(B) PLUS expr(C).  { A = B; }
+</pre>
+will generate an error because the linking symbol ``C'' is used
+in the grammar rule but not in the reduce action.</p>
+
+<p>The Lemon notation for linking grammar rules to reduce actions
+also facilitates the use of destructors for reclaiming memory
+allocated by the values of terminals and nonterminals on the
+right-hand side of a rule.</p>
+
+<h3>Precedence Rules</h3>
+
+<p>Lemon resolves parsing ambiguities in exactly the same way as
+yacc and bison.  A shift-reduce conflict is resolved in favor
+of the shift, and a reduce-reduce conflict is resolved by reducing
+whichever rule comes first in the grammar file.</p>
+
+<p>Just like in
+yacc and bison, Lemon allows a measure of control 
+over the resolution of paring conflicts using precedence rules.
+A precedence value can be assigned to any terminal symbol
+using the %left, %right or %nonassoc directives.  Terminal symbols
+mentioned in earlier directives have a lower precedence that
+terminal symbols mentioned in later directives.  For example:</p>
+
+<p><pre>
+   %left AND.
+   %left OR.
+   %nonassoc EQ NE GT GE LT LE.
+   %left PLUS MINUS.
+   %left TIMES DIVIDE MOD.
+   %right EXP NOT.
+</pre></p>
+
+<p>In the preceding sequence of directives, the AND operator is
+defined to have the lowest precedence.  The OR operator is one
+precedence level higher.  And so forth.  Hence, the grammar would
+attempt to group the ambiguous expression
+<pre>
+     a AND b OR c
+</pre>
+like this
+<pre>
+     a AND (b OR c).
+</pre>
+The associativity (left, right or nonassoc) is used to determine
+the grouping when the precedence is the same.  AND is left-associative
+in our example, so
+<pre>
+     a AND b AND c
+</pre>
+is parsed like this
+<pre>
+     (a AND b) AND c.
+</pre>
+The EXP operator is right-associative, though, so
+<pre>
+     a EXP b EXP c
+</pre>
+is parsed like this
+<pre>
+     a EXP (b EXP c).
+</pre>
+The nonassoc precedence is used for non-associative operators.
+So
+<pre>
+     a EQ b EQ c
+</pre>
+is an error.</p>
+
+<p>The precedence of non-terminals is transferred to rules as follows:
+The precedence of a grammar rule is equal to the precedence of the
+left-most terminal symbol in the rule for which a precedence is
+defined.  This is normally what you want, but in those cases where
+you want to precedence of a grammar rule to be something different,
+you can specify an alternative precedence symbol by putting the
+symbol in square braces after the period at the end of the rule and
+before any C-code.  For example:</p>
+
+<p><pre>
+   expr = MINUS expr.  [NOT]
+</pre></p>
+
+<p>This rule has a precedence equal to that of the NOT symbol, not the
+MINUS symbol as would have been the case by default.</p>
+
+<p>With the knowledge of how precedence is assigned to terminal
+symbols and individual
+grammar rules, we can now explain precisely how parsing conflicts
+are resolved in Lemon.  Shift-reduce conflicts are resolved
+as follows:
+<ul>
+<li> If either the token to be shifted or the rule to be reduced
+     lacks precedence information, then resolve in favor of the
+     shift, but report a parsing conflict.
+<li> If the precedence of the token to be shifted is greater than
+     the precedence of the rule to reduce, then resolve in favor
+     of the shift.  No parsing conflict is reported.
+<li> If the precedence of the token it be shifted is less than the
+     precedence of the rule to reduce, then resolve in favor of the
+     reduce action.  No parsing conflict is reported.
+<li> If the precedences are the same and the shift token is
+     right-associative, then resolve in favor of the shift.
+     No parsing conflict is reported.
+<li> If the precedences are the same the the shift token is
+     left-associative, then resolve in favor of the reduce.
+     No parsing conflict is reported.
+<li> Otherwise, resolve the conflict by doing the shift and
+     report the parsing conflict.
+</ul>
+Reduce-reduce conflicts are resolved this way:
+<ul>
+<li> If either reduce rule 
+     lacks precedence information, then resolve in favor of the
+     rule that appears first in the grammar and report a parsing
+     conflict.
+<li> If both rules have precedence and the precedence is different
+     then resolve the dispute in favor of the rule with the highest
+     precedence and do not report a conflict.
+<li> Otherwise, resolve the conflict by reducing by the rule that
+     appears first in the grammar and report a parsing conflict.
+</ul>
+
+<h3>Special Directives</h3>
+
+<p>The input grammar to Lemon consists of grammar rules and special
+directives.  We've described all the grammar rules, so now we'll
+talk about the special directives.</p>
+
+<p>Directives in lemon can occur in any order.  You can put them before
+the grammar rules, or after the grammar rules, or in the mist of the
+grammar rules.  It doesn't matter.  The relative order of
+directives used to assign precedence to terminals is important, but
+other than that, the order of directives in Lemon is arbitrary.</p>
+
+<p>Lemon supports the following special directives:
+<ul>
+<li><tt>%destructor</tt>
+<li><tt>%extra_argument</tt>
+<li><tt>%include</tt>
+<li><tt>%left</tt>
+<li><tt>%name</tt>
+<li><tt>%nonassoc</tt>
+<li><tt>%parse_accept</tt>
+<li><tt>%parse_failure </tt>
+<li><tt>%right</tt>
+<li><tt>%stack_overflow</tt>
+<li><tt>%stack_size</tt>
+<li><tt>%start_symbol</tt>
+<li><tt>%syntax_error</tt>
+<li><tt>%token_destructor</tt>
+<li><tt>%token_prefix</tt>
+<li><tt>%token_type</tt>
+<li><tt>%type</tt>
+</ul>
+Each of these directives will be described separately in the
+following sections:</p>
+
+<h4>The <tt>%destructor</tt> directive</h4>
+
+<p>The %destructor directive is used to specify a destructor for
+a non-terminal symbol.
+(See also the %token_destructor directive which is used to
+specify a destructor for terminal symbols.)</p>
+
+<p>A non-terminal's destructor is called to dispose of the
+non-terminal's value whenever the non-terminal is popped from
+the stack.  This includes all of the following circumstances:
+<ul>
+<li> When a rule reduces and the value of a non-terminal on
+     the right-hand side is not linked to C code.
+<li> When the stack is popped during error processing.
+<li> When the ParseFree() function runs.
+</ul>
+The destructor can do whatever it wants with the value of
+the non-terminal, but its design is to deallocate memory
+or other resources held by that non-terminal.</p>
+
+<p>Consider an example:
+<pre>
+   %type nt {void*}
+   %destructor nt { free($$); }
+   nt(A) ::= ID NUM.   { A = malloc( 100 ); }
+</pre>
+This example is a bit contrived but it serves to illustrate how
+destructors work.  The example shows a non-terminal named
+``nt'' that holds values of type ``void*''.  When the rule for
+an ``nt'' reduces, it sets the value of the non-terminal to
+space obtained from malloc().  Later, when the nt non-terminal
+is popped from the stack, the destructor will fire and call
+free() on this malloced space, thus avoiding a memory leak.
+(Note that the symbol ``$$'' in the destructor code is replaced
+by the value of the non-terminal.)</p>
+
+<p>It is important to note that the value of a non-terminal is passed
+to the destructor whenever the non-terminal is removed from the
+stack, unless the non-terminal is used in a C-code action.  If
+the non-terminal is used by C-code, then it is assumed that the
+C-code will take care of destroying it if it should really
+be destroyed.  More commonly, the value is used to build some
+larger structure and we don't want to destroy it, which is why
+the destructor is not called in this circumstance.</p>
+
+<p>By appropriate use of destructors, it is possible to
+build a parser using Lemon that can be used within a long-running
+program, such as a GUI, that will not leak memory or other resources.
+To do the same using yacc or bison is much more difficult.</p>
+
+<h4>The <tt>%extra_argument</tt> directive</h4>
+
+The %extra_argument directive instructs Lemon to add a 4th parameter
+to the parameter list of the Parse() function it generates.  Lemon
+doesn't do anything itself with this extra argument, but it does
+make the argument available to C-code action routines, destructors,
+and so forth.  For example, if the grammar file contains:</p>
+
+<p><pre>
+    %extra_argument { MyStruct *pAbc }
+</pre></p>
+
+<p>Then the Parse() function generated will have an 4th parameter
+of type ``MyStruct*'' and all action routines will have access to
+a variable named ``pAbc'' that is the value of the 4th parameter
+in the most recent call to Parse().</p>
+
+<h4>The <tt>%include</tt> directive</h4>
+
+<p>The %include directive specifies C code that is included at the
+top of the generated parser.  You can include any text you want --
+the Lemon parser generator copies to blindly.  If you have multiple
+%include directives in your grammar file, their values are concatenated
+before being put at the beginning of the generated parser.</p>
+
+<p>The %include directive is very handy for getting some extra #include
+preprocessor statements at the beginning of the generated parser.
+For example:</p>
+
+<p><pre>
+   %include {#include &lt;unistd.h&gt;}
+</pre></p>
+
+<p>This might be needed, for example, if some of the C actions in the
+grammar call functions that are prototyed in unistd.h.</p>
+
+<h4>The <tt>%left</tt> directive</h4>
+
+The %left directive is used (along with the %right and
+%nonassoc directives) to declare precedences of terminal
+symbols.  Every terminal symbol whose name appears after
+a %left directive but before the next period (``.'') is
+given the same left-associative precedence value.  Subsequent
+%left directives have higher precedence.  For example:</p>
+
+<p><pre>
+   %left AND.
+   %left OR.
+   %nonassoc EQ NE GT GE LT LE.
+   %left PLUS MINUS.
+   %left TIMES DIVIDE MOD.
+   %right EXP NOT.
+</pre></p>
+
+<p>Note the period that terminates each %left, %right or %nonassoc
+directive.</p>
+
+<p>LALR(1) grammars can get into a situation where they require
+a large amount of stack space if you make heavy use or right-associative
+operators.  For this reason, it is recommended that you use %left
+rather than %right whenever possible.</p>
+
+<h4>The <tt>%name</tt> directive</h4>
+
+<p>By default, the functions generated by Lemon all begin with the
+five-character string ``Parse''.  You can change this string to something
+different using the %name directive.  For instance:</p>
+
+<p><pre>
+   %name Abcde
+</pre></p>
+
+<p>Putting this directive in the grammar file will cause Lemon to generate
+functions named
+<ul>
+<li> AbcdeAlloc(),
+<li> AbcdeFree(),
+<li> AbcdeTrace(), and
+<li> Abcde().
+</ul>
+The %name directive allows you to generator two or more different
+parsers and link them all into the same executable.
+</p>
+
+<h4>The <tt>%nonassoc</tt> directive</h4>
+
+<p>This directive is used to assign non-associative precedence to
+one or more terminal symbols.  See the section on precedence rules
+or on the %left directive for additional information.</p>
+
+<h4>The <tt>%parse_accept</tt> directive</h4>
+
+<p>The %parse_accept directive specifies a block of C code that is
+executed whenever the parser accepts its input string.  To ``accept''
+an input string means that the parser was able to process all tokens
+without error.</p>
+
+<p>For example:</p>
+
+<p><pre>
+   %parse_accept {
+      printf("parsing complete!\n");
+   }
+</pre></p>
+
+
+<h4>The <tt>%parse_failure</tt> directive</h4>
+
+<p>The %parse_failure directive specifies a block of C code that
+is executed whenever the parser fails complete.  This code is not
+executed until the parser has tried and failed to resolve an input
+error using is usual error recovery strategy.  The routine is
+only invoked when parsing is unable to continue.</p>
+
+<p><pre>
+   %parse_failure {
+     fprintf(stderr,"Giving up.  Parser is hopelessly lost...\n");
+   }
+</pre></p>
+
+<h4>The <tt>%right</tt> directive</h4>
+
+<p>This directive is used to assign right-associative precedence to
+one or more terminal symbols.  See the section on precedence rules
+or on the %left directive for additional information.</p>
+
+<h4>The <tt>%stack_overflow</tt> directive</h4>
+
+<p>The %stack_overflow directive specifies a block of C code that
+is executed if the parser's internal stack ever overflows.  Typically
+this just prints an error message.  After a stack overflow, the parser
+will be unable to continue and must be reset.</p>
+
+<p><pre>
+   %stack_overflow {
+     fprintf(stderr,"Giving up.  Parser stack overflow\n");
+   }
+</pre></p>
+
+<p>You can help prevent parser stack overflows by avoiding the use
+of right recursion and right-precedence operators in your grammar.
+Use left recursion and and left-precedence operators instead, to
+encourage rules to reduce sooner and keep the stack size down.
+For example, do rules like this:
+<pre>
+   list ::= list element.      // left-recursion.  Good!
+   list ::= .
+</pre>
+Not like this:
+<pre>
+   list ::= element list.      // right-recursion.  Bad!
+   list ::= .
+</pre>
+
+<h4>The <tt>%stack_size</tt> directive</h4>
+
+<p>If stack overflow is a problem and you can't resolve the trouble
+by using left-recursion, then you might want to increase the size
+of the parser's stack using this directive.  Put an positive integer
+after the %stack_size directive and Lemon will generate a parse
+with a stack of the requested size.  The default value is 100.</p>
+
+<p><pre>
+   %stack_size 2000
+</pre></p>
+
+<h4>The <tt>%start_symbol</tt> directive</h4>
+
+<p>By default, the start-symbol for the grammar that Lemon generates
+is the first non-terminal that appears in the grammar file.  But you
+can choose a different start-symbol using the %start_symbol directive.</p>
+
+<p><pre>
+   %start_symbol  prog
+</pre></p>
+
+<h4>The <tt>%token_destructor</tt> directive</h4>
+
+<p>The %destructor directive assigns a destructor to a non-terminal
+symbol.  (See the description of the %destructor directive above.)
+This directive does the same thing for all terminal symbols.</p>
+
+<p>Unlike non-terminal symbols which may each have a different data type
+for their values, terminals all use the same data type (defined by
+the %token_type directive) and so they use a common destructor.  Other
+than that, the token destructor works just like the non-terminal
+destructors.</p>
+
+<h4>The <tt>%token_prefix</tt> directive</h4>
+
+<p>Lemon generates #defines that assign small integer constants
+to each terminal symbol in the grammar.  If desired, Lemon will
+add a prefix specified by this directive
+to each of the #defines it generates.
+So if the default output of Lemon looked like this:
+<pre>
+    #define AND              1
+    #define MINUS            2
+    #define OR               3
+    #define PLUS             4
+</pre>
+You can insert a statement into the grammar like this:
+<pre>
+    %token_prefix    TOKEN_
+</pre>
+to cause Lemon to produce these symbols instead:
+<pre>
+    #define TOKEN_AND        1
+    #define TOKEN_MINUS      2
+    #define TOKEN_OR         3
+    #define TOKEN_PLUS       4
+</pre>
+
+<h4>The <tt>%token_type</tt> and <tt>%type</tt> directives</h4>
+
+<p>These directives are used to specify the data types for values
+on the parser's stack associated with terminal and non-terminal
+symbols.  The values of all terminal symbols must be of the same
+type.  This turns out to be the same data type as the 3rd parameter
+to the Parse() function generated by Lemon.  Typically, you will
+make the value of a terminal symbol by a pointer to some kind of
+token structure.  Like this:</p>
+
+<p><pre>
+   %token_type    {Token*}
+</pre></p>
+
+<p>If the data type of terminals is not specified, the default value
+is ``int''.</p>
+
+<p>Non-terminal symbols can each have their own data types.  Typically
+the data type  of a non-terminal is a pointer to the root of a parse-tree
+structure that contains all information about that non-terminal.
+For example:</p>
+
+<p><pre>
+   %type   expr  {Expr*}
+</pre></p>
+
+<p>Each entry on the parser's stack is actually a union containing
+instances of all data types for every non-terminal and terminal symbol.
+Lemon will automatically use the correct element of this union depending
+on what the corresponding non-terminal or terminal symbol is.  But
+the grammar designer should keep in mind that the size of the union
+will be the size of its largest element.  So if you have a single
+non-terminal whose data type requires 1K of storage, then your 100
+entry parser stack will require 100K of heap space.  If you are willing
+and able to pay that price, fine.  You just need to know.</p>
+
+<h3>Error Processing</h3>
+
+<p>After extensive experimentation over several years, it has been
+discovered that the error recovery strategy used by yacc is about
+as good as it gets.  And so that is what Lemon uses.</p>
+
+<p>When a Lemon-generated parser encounters a syntax error, it
+first invokes the code specified by the %syntax_error directive, if
+any.  It then enters its error recovery strategy.  The error recovery
+strategy is to begin popping the parsers stack until it enters a
+state where it is permitted to shift a special non-terminal symbol
+named ``error''.  It then shifts this non-terminal and continues
+parsing.  But the %syntax_error routine will not be called again
+until at least three new tokens have been successfully shifted.</p>
+
+<p>If the parser pops its stack until the stack is empty, and it still
+is unable to shift the error symbol, then the %parse_failed routine
+is invoked and the parser resets itself to its start state, ready
+to begin parsing a new file.  This is what will happen at the very
+first syntax error, of course, if there are no instances of the 
+``error'' non-terminal in your grammar.</p>
+
+</body>
+</html>
index f96d70fa5a337330d168664bf9f66ef889c3e300..a2d479053a83618df6e04200accf2f67a47e2bbf 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,8 +1,29 @@
-C initial\sempty\scheck-in
-D 2000-05-29T14:16:00
-P
-R d41d8cd98f00b204e9800998ecf8427e
-T *branch * trunk
-T *sym-trunk *
+C initial\scheck-in\sof\sthe\snew\sversion\s(CVS\s1)
+D 2000-05-29T14:26:00
+F Makefile.in 4bd5c67a3a2816e930df4b22df8c1631ee87ff0c
+F configure 8faba4d0194321e5f61a64e842c65eab0f68e6d8 x
+F configure.in 4fc2947d631037bd340b112d6193847d7ac827ae
+F doc/lemon.html e233a3e97a779c7a87e1bc4528c664a58e49dd47
+F src/build.c 64016990ebbbcbc848165551732a1f9f397bd150
+F src/dbbe.c ab05293e89525041eaab8b4aca10516db3648792
+F src/dbbe.h bedeb3a0985bb584458e7849fb59927e99e751e6
+F src/main.c 25cce7bce0eb3ba10bada7c05f4b38dc6dbbc86f
+F src/shell.c de770d16aae1ea219e7a9ab5147a4437c23b4a6c
+F src/sqlite.h 2397c17a8f4ca90c09acab0100dc7e2f8f441b69
+F src/sqliteInt.h 0365970442441b5e9b74e1e828afdeac7b0662be
+F src/tclsqlite.c 6eca1c1b8713048245d295ed18dca71c91d4931f
+F src/tokenize.c ab578d90ec6ab117b7ade6e6cfbcb5b0f9cad500
+F src/util.c 370c2339bb9ff82645804a4c62506149392fd032
+F src/vdbe.c 80132b6bb9a744d1990a1c16666d54baaff2dbc3
+F src/vdbe.h e721ad308f2e6ca805cebc4dd0a196ce4419d030
+F src/where.c 67ffea57920e16b33c580e9a9b9855b3ec9dea7b
+F tool/gdbmdump.c 529e67c78d920606ba196326ea55b57b75fcc82b
+F tool/lemon.c cff35578b3c4d1491021b6418016639ebe21b1a5
+F tool/lempar.c a1eec94d6eacc12332368660ec65f3b248853833
+F tool/opNames.awk 2bd9071a138e4e2be13dc98fe066398a61219e1e
+F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c
+F tool/renumberOps.awk 6d067177ad5f8d711b79577b462da9b3634bd0a9
+P 704b122e5308587b60b47a5c2fff40c593d4bf8f
+R 33c985d67f2f41286bc65b8529a1ae84
 U drh
-Z 8c6f780fffd15dac29a44b424067ccfc
+Z a9e2b0f2d67c72179e4ea5172821c6d6
index 919e65c522fd9930baf491e66a6ef9549249a88d..1fff0226d4de6571158b8e4ee1b896236b1eca5a 100644 (file)
@@ -1 +1 @@
-704b122e5308587b60b47a5c2fff40c593d4bf8f
\ No newline at end of file
+6f3655f79f9b6fc9fb7baaa10a7e0f2b6a512dfa
\ No newline at end of file
diff --git a/src/build.c b/src/build.c
new file mode 100644 (file)
index 0000000..ba4eb17
--- /dev/null
@@ -0,0 +1,1435 @@
+/*
+** Copyright (c) 1999, 2000 D. Richard Hipp
+**
+** 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 library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*************************************************************************
+** This file contains C code routines that are called by the parser
+** when syntax rules are reduced.
+**
+** $Id: build.c,v 1.1 2000/05/29 14:26:01 drh Exp $
+*/
+#include "sqliteInt.h"
+
+/*
+** This routine is called after a single SQL statement has been
+** parsed and we want to execute the code to implement 
+** the statement.  Prior action routines should have already
+** constructed VDBE code to do the work of the SQL statement.
+** This routine just has to execute the VDBE code.
+**
+** Note that if an error occurred, it might be the case that
+** no VDBE code was generated.
+*/
+void sqliteExec(Parse *pParse){
+  if( pParse->pVdbe ){
+    if( pParse->explain ){
+      sqliteVdbeList(pParse->pVdbe, pParse->xCallback, pParse->pArg, 
+                     &pParse->zErrMsg);
+    }else{
+      FILE *trace = (pParse->db->flags & SQLITE_VdbeTrace)!=0 ? stderr : 0;
+      sqliteVdbeTrace(pParse->pVdbe, trace);
+      sqliteVdbeExec(pParse->pVdbe, pParse->xCallback, pParse->pArg, 
+                     &pParse->zErrMsg);
+    }
+    sqliteVdbeDelete(pParse->pVdbe);
+    pParse->pVdbe = 0;
+  }
+}
+
+/*
+** Construct a new expression node and return a pointer to it.
+*/
+Expr *sqliteExpr(int op, Expr *pLeft, Expr *pRight, Token *pToken){
+  Expr *pNew;
+  pNew = sqliteMalloc( sizeof(Expr) );
+  if( pNew==0 ) return 0;
+  pNew->op = op;
+  pNew->pLeft = pLeft;
+  pNew->pRight = pRight;
+  if( pToken ){
+    pNew->token = *pToken;
+  }else{
+    pNew->token.z = "";
+    pNew->token.n = 0;
+  }
+  return pNew;
+}
+
+/*
+** Construct a new expression node for a function with multiple
+** arguments.
+*/
+Expr *sqliteExprFunction(ExprList *pList, Token *pToken){
+  Expr *pNew;
+  pNew = sqliteMalloc( sizeof(Expr) );
+  if( pNew==0 ) return 0;
+  pNew->op = TK_FUNCTION;
+  pNew->pList = pList;
+  if( pToken ){
+    pNew->token = *pToken;
+  }else{
+    pNew->token.z = "";
+    pNew->token.n = 0;
+  }
+  return pNew;
+}
+
+/*
+** Recursively delete an expression tree.
+*/
+void sqliteExprDelete(Expr *p){
+  if( p==0 ) return;
+  if( p->pLeft ) sqliteExprDelete(p->pLeft);
+  if( p->pRight ) sqliteExprDelete(p->pRight);
+  sqliteFree(p);
+}
+
+/*
+** Locate the in-memory structure that describes the
+** format of a particular database table given the name
+** of that table.  Return NULL if not found.
+*/
+Table *sqliteFindTable(sqlite *db, char *zName){
+  Table *pTable;
+  int h;
+
+  h = sqliteHashNoCase(zName, 0) % N_HASH;
+  for(pTable=db->apTblHash[h]; pTable; pTable=pTable->pHash){
+    if( sqliteStrICmp(pTable->zName, zName)==0 ) return pTable;
+  }
+  return 0;
+}
+
+/*
+** Locate the in-memory structure that describes the
+** format of a particular index table given the name
+** of that table.  Return NULL if not found.
+*/
+Index *sqliteFindIndex(sqlite *db, char *zName){
+  Index *p;
+  int h;
+
+  h = sqliteHashNoCase(zName, 0) % N_HASH;
+  for(p=db->apIdxHash[h]; p; p=p->pHash){
+    if( sqliteStrICmp(p->zName, zName)==0 ) return p;
+  }
+  return 0;
+}
+
+/*
+** Remove the given index from the index hash table, and free
+** its memory structures.
+**
+** The index is removed from the database hash table, but it is
+** not unlinked from the table that is being indexed.  Unlinking
+** from the table must be done by the calling function.
+*/
+static void sqliteDeleteIndex(sqlite *db, Index *pIndex){
+  int h;
+  if( pIndex->zName ){
+    h = sqliteHashNoCase(pIndex->zName, 0) % N_HASH;
+    if( db->apIdxHash[h]==pIndex ){
+      db->apIdxHash[h] = pIndex->pHash;
+    }else{
+      Index *p;
+      for(p=db->apIdxHash[h]; p && p->pHash!=pIndex; p=p->pHash){}
+      if( p && p->pHash==pIndex ){
+        p->pHash = pIndex->pHash;
+      }
+    }
+  }
+  sqliteFree(pIndex);
+}
+
+/*
+** Remove the memory data structures associated with the given
+** table.  No changes are made to disk by this routine.
+**
+** This routine just deletes the data structure.  It does not unlink
+** the table data structure from the hash table.  But does it destroy
+** memory structures of the indices associated with the table.
+*/
+void sqliteDeleteTable(sqlite *db, Table *pTable){
+  int i;
+  Index *pIndex, *pNext;
+  if( pTable==0 ) return;
+  for(i=0; i<pTable->nCol; i++){
+    if( pTable->azCol[i] ) sqliteFree(pTable->azCol[i]);
+  }
+  for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){
+    pNext = pIndex->pNext;
+    sqliteDeleteIndex(db, pIndex);
+  }
+  sqliteFree(pTable->azCol);
+  sqliteFree(pTable);
+}
+
+/*
+** Construct the name of a user table from a token.
+**
+** Space to hold the name is obtained from sqliteMalloc() and must
+** be freed by the calling function.
+*/
+static char *sqliteTableNameFromToken(Token *pName){
+  char *zName = 0;
+  sqliteSetNString(&zName, pName->z, pName->n, 0);
+  return zName;
+}
+
+/*
+** Begin constructing a new table representation in memory.  This is
+** the first of several action routines that get called in response
+** to a CREATE TABLE statement.
+*/
+void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName){
+  Table *pTable;
+  char *zName;
+
+  pParse->sFirstToken = *pStart;
+  zName = sqliteTableNameFromToken(pName);
+  pTable = sqliteFindTable(pParse->db, zName);
+  if( pTable!=0 ){
+    sqliteSetNString(&pParse->zErrMsg, "table \"", 0, pName->z, pName->n,
+        "\" already exists", 0, 0);
+    sqliteFree(zName);
+    pParse->nErr++;
+    return;
+  }
+  if( sqliteFindIndex(pParse->db, zName) ){
+    sqliteSetString(&pParse->zErrMsg, "there is already an index named \"", 
+       zName, "\"", 0);
+    sqliteFree(zName);
+    pParse->nErr++;
+    return;
+  }
+  pTable = sqliteMalloc( sizeof(Table) );
+  if( pTable==0 ){
+    sqliteSetString(&pParse->zErrMsg, "out of memory", 0);
+    pParse->nErr++;
+    return;
+  }
+  pTable->zName = zName;
+  pTable->pHash = 0;
+  pTable->nCol = 0;
+  pTable->azCol = 0;
+  pTable->pIndex = 0;
+  if( pParse->pNewTable ) sqliteDeleteTable(pParse->db, pParse->pNewTable);
+  pParse->pNewTable = pTable;
+}
+
+/*
+** Add a new column to the table currently being constructed.
+*/
+void sqliteAddColumn(Parse *pParse, Token *pName){
+  Table *p;
+  char **pz;
+  if( (p = pParse->pNewTable)==0 ) return;
+  if( (p->nCol & 0x7)==0 ){
+    p->azCol = sqliteRealloc( p->azCol, p->nCol+8);
+  }
+  if( p->azCol==0 ){
+    p->nCol = 0;
+    return;
+  }
+  pz = &p->azCol[p->nCol++];
+  *pz = 0;
+  sqliteSetNString(pz, pName->z, pName->n, 0);
+}
+
+/*
+** This routine is called to report the final ")" that terminates
+** a CREATE TABLE statement.
+**
+** The table structure is added to the internal hash tables.  
+**
+** An entry for the table is made in the master table, unless 
+** initFlag==1.  When initFlag==1, it means we are reading the
+** master table because we just connected to the database, so 
+** the entry for this table already exists in the master table.
+** We do not want to create it again.
+*/
+void sqliteEndTable(Parse *pParse, Token *pEnd){
+  Table *p;
+  int h;
+
+  if( pParse->nErr ) return;
+
+  /* Add the table to the in-memory representation of the database
+  */
+  if( (p = pParse->pNewTable)!=0 && pParse->explain==0 ){
+    h = sqliteHashNoCase(p->zName, 0) % N_HASH;
+    p->pHash = pParse->db->apTblHash[h];
+    pParse->db->apTblHash[h] = p;
+    pParse->pNewTable = 0;
+  }
+
+  /* If not initializing, then create the table on disk.
+  */
+  if( !pParse->initFlag ){
+    static VdbeOp addTable[] = {
+      { OP_Open,        0, 0, MASTER_NAME },
+      { OP_New,         0, 0, 0},
+      { OP_String,      0, 0, "table"     },
+      { OP_String,      0, 0, 0},            /* 2 */
+      { OP_String,      0, 0, 0},            /* 3 */
+      { OP_String,      0, 0, 0},            /* 4 */
+      { OP_MakeRecord,  4, 0, 0},
+      { OP_Put,         0, 0, 0},
+      { OP_Close,       0, 0, 0},
+    };
+    int n, base;
+    Vdbe *v = pParse->pVdbe;
+
+    if( v==0 ){
+      v = pParse->pVdbe = sqliteVdbeCreate(pParse->db->pBe);
+    }
+    if( v==0 ) return;
+    n = (int)pEnd->z - (int)pParse->sFirstToken.z + 1;
+    base = sqliteVdbeAddOpList(v, ArraySize(addTable), addTable);
+    sqliteVdbeChangeP3(v, base+2, p->zName, 0);
+    sqliteVdbeChangeP3(v, base+3, p->zName, 0);
+    sqliteVdbeChangeP3(v, base+4, pParse->sFirstToken.z, n);
+  }
+}
+
+/*
+** Given a token, look up a table with that name.  If not found, leave
+** an error for the parser to find and return NULL.
+*/
+static Table *sqliteTableFromToken(Parse *pParse, Token *pTok){
+  char *zName = sqliteTableNameFromToken(pTok);
+  Table *pTab = sqliteFindTable(pParse->db, zName);
+  sqliteFree(zName);
+  if( pTab==0 ){
+    sqliteSetNString(&pParse->zErrMsg, "no such table: \"", 0, 
+        pTok->z, pTok->n, "\"", 1, 0);
+    pParse->nErr++;
+  }
+  return pTab;
+}
+
+/*
+** This routine is called to do the work of a DROP TABLE statement.
+*/
+void sqliteDropTable(Parse *pParse, Token *pName){
+  Table *pTable;
+  int h;
+  Vdbe *v;
+  int base;
+
+  pTable = sqliteTableFromToken(pParse, pName);
+  if( pTable==0 ) return;
+  if( pTable->readOnly ){
+    sqliteSetString(&pParse->zErrMsg, "table \"", pTable->zName, 
+       "\" may not be dropped", 0);
+    pParse->nErr++;
+    return;
+  }
+
+  /* Generate code to remove the table and its reference in sys_master */
+  v = pParse->pVdbe;
+  if( v==0 ){
+    v = pParse->pVdbe = sqliteVdbeCreate(pParse->db->pBe);
+  }
+  if( v ){
+    static VdbeOp dropTable[] = {
+      { OP_Open,       0, 0,        MASTER_NAME },
+      { OP_ListOpen,   0, 0,        0},
+      { OP_String,     0, 0,        0}, /* 2 */
+      { OP_Next,       0, ADDR(10), 0}, /* 3 */
+      { OP_Dup,        0, 0,        0},
+      { OP_Field,      0, 2,        0},
+      { OP_Ne,         0, ADDR(3),  0},
+      { OP_Key,        0, 0,        0},
+      { OP_ListWrite,  0, 0,        0},
+      { OP_Goto,       0, ADDR(3),  0},
+      { OP_ListRewind, 0, 0,        0}, /* 10 */
+      { OP_ListRead,   0, ADDR(14), 0}, /* 11 */
+      { OP_Delete,     0, 0,        0},
+      { OP_Goto,       0, ADDR(11), 0},
+      { OP_Destroy,    0, 0,        0}, /* 14 */
+      { OP_Close,      0, 0,        0},
+    };
+    Index *pIdx;
+    base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable);
+    sqliteVdbeChangeP3(v, base+2, pTable->zName, 0);
+    sqliteVdbeChangeP3(v, base+14, pTable->zName, 0);
+    for(pIdx=pTable->pIndex; pIdx; pIdx=pIdx->pNext){
+      sqliteVdbeAddOp(v, OP_Destroy, 0, 0, pIdx->zName, 0);
+    }
+  }
+
+  /* Remove the table structure and free its memory.
+  **
+  ** Exception: if the SQL statement began with the EXPLAIN keyword,
+  ** then no changes are made.
+  */
+  if( !pParse->explain ){
+    h = sqliteHashNoCase(pTable->zName, 0) % N_HASH;
+    if( pParse->db->apTblHash[h]==pTable ){
+      pParse->db->apTblHash[h] = pTable->pHash;
+    }else{
+      Table *p;
+      for(p=pParse->db->apTblHash[h]; p && p->pHash!=pTable; p=p->pHash){}
+      if( p && p->pHash==pTable ){
+        p->pHash = pTable->pHash;
+      }
+    }
+    sqliteDeleteTable(pParse->db, pTable);
+  }
+}
+
+/*
+** Create a new index for an SQL table.  pIndex is the name of the index 
+** and pTable is the name of the table that is to be indexed.  Both will 
+** be NULL for a primary key.  In that case, use pParse->pNewTable as the 
+** table to be indexed.
+**
+** pList is a list of fields to be indexed.  pList will be NULL if the
+** most recently added field of the table is labeled as the primary key.
+*/
+void sqliteCreateIndex(
+  Parse *pParse,   /* All information about this parse */
+  Token *pName,    /* Name of the index.  May be NULL */
+  Token *pTable,   /* Name of the table to index.  Use pParse->pNewTable if 0 */
+  IdList *pList,   /* A list of fields to be indexed */
+  Token *pStart,   /* The CREATE token that begins a CREATE TABLE statement */
+  Token *pEnd      /* The ")" that closes the CREATE INDEX statement */
+){
+  Table *pTab;     /* Table to be indexed */
+  Index *pIndex;   /* The index to be created */
+  char *zName = 0;
+  int i, j, h;
+  Token nullId;    /* Fake token for an empty ID list */
+
+  /*
+  ** Find the table that is to be indexed.  Return early if not found.
+  */
+  if( pTable!=0 ){
+    pTab =  sqliteTableFromToken(pParse, pTable);
+  }else{
+    pTab =  pParse->pNewTable;
+  }
+  if( pTab==0 || pParse->nErr ) goto exit_create_index;
+  if( pTab->readOnly ){
+    sqliteSetString(&pParse->zErrMsg, "table \"", pTab->zName, 
+      "\" may not have new indices added", 0);
+    pParse->nErr++;
+    goto exit_create_index;
+  }
+
+  /*
+  ** Find the name of the index.  Make sure there is not already another
+  ** index or table with the same name.
+  */
+  if( pName ){
+    zName = sqliteTableNameFromToken(pName);
+  }else{
+    zName = 0;
+    sqliteSetString(&zName, pTab->zName, "__primary_key", 0);
+  }
+  if( sqliteFindIndex(pParse->db, zName) ){
+    sqliteSetString(&pParse->zErrMsg, "index \"", zName, 
+       "\" already exists", 0);
+    pParse->nErr++;
+    goto exit_create_index;
+  }
+  if( sqliteFindTable(pParse->db, zName) ){
+    sqliteSetString(&pParse->zErrMsg, "there is already a table named \"",
+       zName, "\"", 0);
+    pParse->nErr++;
+    goto exit_create_index;
+  }
+
+  /* If pList==0, it means this routine was called to make a primary
+  ** key out of the last field added to the table under construction.
+  ** So create a fake list to simulate this.
+  */
+  if( pList==0 ){
+    nullId.z = pTab->azCol[pTab->nCol-1];
+    nullId.n = strlen(nullId.z);
+    pList = sqliteIdListAppend(0, &nullId);
+    if( pList==0 ) goto exit_create_index;
+  }
+
+  /* 
+  ** Allocate the index structure. 
+  */
+  pIndex = sqliteMalloc( sizeof(Index) + strlen(zName) + 
+                        sizeof(int)*pList->nId );
+  if( pIndex==0 ){
+    sqliteSetString(&pParse->zErrMsg, "out of memory", 0);
+    pParse->nErr++;
+    goto exit_create_index;
+  }
+  pIndex->aiField = (int*)&pIndex[1];
+  pIndex->zName = (char*)&pIndex->aiField[pList->nId];
+  strcpy(pIndex->zName, zName);
+  pIndex->pTable = pTab;
+  pIndex->nField = pList->nId;
+
+  /* Scan the names of the fields of the table to be indexed and
+  ** load the field indices into the Index structure.  Report an error
+  ** if any field is not found.
+  */
+  for(i=0; i<pList->nId; i++){
+    for(j=0; j<pTab->nCol; j++){
+      if( sqliteStrICmp(pList->a[i].zName, pTab->azCol[j])==0 ) break;
+    }
+    if( j>=pTab->nCol ){
+      sqliteSetString(&pParse->zErrMsg, "table being indexed has no field "
+        "named \"", pList->a[i].zName, "\"", 0);
+      pParse->nErr++;
+      sqliteFree(pIndex);
+      goto exit_create_index;
+    }
+    pIndex->aiField[i] = j;
+  }
+
+  /* Link the new Index structure to its table and to the other
+  ** in-memory database structures.
+  */
+  if( pParse->explain==0 ){
+    h = sqliteHashNoCase(pIndex->zName, 0) % N_HASH;
+    pIndex->pHash = pParse->db->apIdxHash[h];
+    pParse->db->apIdxHash[h] = pIndex;
+    pIndex->pNext = pTab->pIndex;
+    pTab->pIndex = pIndex;
+  }
+
+  /* If the initFlag is 0 then create the index on disk.  This
+  ** involves writing the index into the master table and filling in the
+  ** index with the current table contents.
+  **
+  ** The initFlag is 0 when the user first enters a CREATE INDEX 
+  ** command.  The initFlag is 1 when a database is opened and 
+  ** CREATE INDEX statements are read out of the master table.  In
+  ** the latter case the index already exists on disk, which is why
+  ** we don't want to recreate it.
+  */
+  if( pParse->initFlag==0 ){
+    static VdbeOp addTable[] = {
+      { OP_Open,        0, 0, MASTER_NAME},
+      { OP_New,         0, 0, 0},
+      { OP_String,      0, 0, "index"},
+      { OP_String,      0, 0, 0},  /* 2 */
+      { OP_String,      0, 0, 0},  /* 3 */
+      { OP_String,      0, 0, 0},  /* 4 */
+      { OP_MakeRecord,  4, 0, 0},
+      { OP_Put,         0, 0, 0},
+      { OP_Close,       0, 0, 0},
+    };
+    int n;
+    Vdbe *v = pParse->pVdbe;
+    int lbl1, lbl2;
+    int i;
+
+    if( v==0 ){
+      v = pParse->pVdbe = sqliteVdbeCreate(pParse->db->pBe);
+    }
+    if( v==0 ) goto exit_create_index;
+    if( pStart && pEnd ){
+      int base;
+      n = (int)pEnd->z - (int)pStart->z + 1;
+      base = sqliteVdbeAddOpList(v, ArraySize(addTable), addTable);
+      sqliteVdbeChangeP3(v, base+2, pIndex->zName, 0);
+      sqliteVdbeChangeP3(v, base+3, pTab->zName, 0);
+      sqliteVdbeChangeP3(v, base+4, pStart->z, n);
+    }
+    sqliteVdbeAddOp(v, OP_Open, 0, 0, pTab->zName, 0);
+    sqliteVdbeAddOp(v, OP_Open, 1, 0, pIndex->zName, 0);
+    lbl1 = sqliteVdbeMakeLabel(v);
+    lbl2 = sqliteVdbeMakeLabel(v);
+    sqliteVdbeAddOp(v, OP_Next, 0, lbl2, 0, lbl1);
+    sqliteVdbeAddOp(v, OP_Key, 0, 0, 0, 0);
+    for(i=0; i<pIndex->nField; i++){
+      sqliteVdbeAddOp(v, OP_Field, 0, pIndex->aiField[i], 0, 0);
+    }
+    sqliteVdbeAddOp(v, OP_MakeKey, pIndex->nField, 0, 0, 0);
+    sqliteVdbeAddOp(v, OP_PutIdx, 1, 0, 0, 0);
+    sqliteVdbeAddOp(v, OP_Goto, 0, lbl1, 0, 0);
+    sqliteVdbeAddOp(v, OP_Noop, 0, 0, 0, lbl2);
+    sqliteVdbeAddOp(v, OP_Close, 0, 0, 0, 0);
+    sqliteVdbeAddOp(v, OP_Close, 1, 0, 0, 0);
+  }
+
+  /* Reclaim memory on an EXPLAIN call.
+  */
+  if( pParse->explain ){
+    sqliteFree(pIndex);
+  }
+
+  /* Clean up before exiting */
+exit_create_index:
+  sqliteIdListDelete(pList);
+  sqliteFree(zName);
+  return;
+}
+
+/*
+** This routine will drop an existing named index.
+*/
+void sqliteDropIndex(Parse *pParse, Token *pName){
+  Index *pIndex;
+  char *zName;
+  Vdbe *v;
+
+  zName = sqliteTableNameFromToken(pName);
+  pIndex = sqliteFindIndex(pParse->db, zName);
+  sqliteFree(zName);
+  if( pIndex==0 ){
+    sqliteSetNString(&pParse->zErrMsg, "no such index: \"", 0, 
+        pName->z, pName->n, "\"", 1, 0);
+    pParse->nErr++;
+    return;
+  }
+
+  /* Generate code to remove the index and from the master table */
+  v = pParse->pVdbe = sqliteVdbeCreate(pParse->db->pBe);
+  if( v ){
+    static VdbeOp dropIndex[] = {
+      { OP_Open,       0, 0,       MASTER_NAME},
+      { OP_ListOpen,   0, 0,       0},
+      { OP_String,     0, 0,       0}, /* 2 */
+      { OP_Next,       0, ADDR(9), 0}, /* 3 */
+      { OP_Dup,        0, 0,       0},
+      { OP_Field,      0, 1,       0},
+      { OP_Ne,         0, ADDR(3), 0},
+      { OP_Key,        0, 0,       0},
+      { OP_Delete,     0, 0,       0},
+      { OP_Destroy,    0, 0,       0}, /* 9 */
+      { OP_Close,      0, 0,       0},
+    };
+    int base;
+
+    base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex);
+    sqliteVdbeChangeP3(v, base+2, pIndex->zName, 0);
+    sqliteVdbeChangeP3(v, base+9, pIndex->zName, 0);
+  }
+
+  /* Remove the index structure and free its memory.  Except if the
+  ** EXPLAIN keyword is present, no changes are made.
+  */
+  if( !pParse->explain ){
+    if( pIndex->pTable->pIndex==pIndex ){
+      pIndex->pTable->pIndex = pIndex->pNext;
+    }else{
+      Index *p;
+      for(p=pIndex->pTable->pIndex; p && p->pNext!=pIndex; p=p->pNext){}
+      if( p && p->pNext==pIndex ){
+        p->pNext = pIndex->pNext;
+      }
+    }
+    sqliteDeleteIndex(pParse->db, pIndex);
+  }
+}
+
+/*
+** Add a new element to the end of an expression list.  If pList is
+** initially NULL, then create a new expression list.
+*/
+ExprList *sqliteExprListAppend(ExprList *pList, Expr *pExpr, Token *pName){
+  int i;
+  if( pList==0 ){
+    pList = sqliteMalloc( sizeof(ExprList) );
+  }
+  if( pList==0 ) return 0;
+  if( (pList->nExpr & 7)==0 ){
+    int n = pList->nExpr + 8;
+    pList->a = sqliteRealloc(pList->a, n*sizeof(pList->a[0]));
+    if( pList->a==0 ){
+      pList->nExpr = 0;
+      return pList;
+    }
+  }
+  i = pList->nExpr++;
+  pList->a[i].pExpr = pExpr;
+  pList->a[i].zName = 0;
+  if( pName ){
+    sqliteSetNString(&pList->a[i].zName, pName->z, pName->n, 0);
+  }
+  return pList;
+}
+
+/*
+** Delete an entire expression list.
+*/
+void sqliteExprListDelete(ExprList *pList){
+  int i;
+  if( pList==0 ) return;
+  for(i=0; i<pList->nExpr; i++){
+    sqliteExprDelete(pList->a[i].pExpr);
+    sqliteFree(pList->a[i].zName);
+  }
+  sqliteFree(pList->a);
+  sqliteFree(pList);
+}
+
+/*
+** Append a new element to the given IdList.  Create a new IdList if
+** need be.
+*/
+IdList *sqliteIdListAppend(IdList *pList, Token *pToken){
+  if( pList==0 ){
+    pList = sqliteMalloc( sizeof(IdList) );
+    if( pList==0 ) return 0;
+  }
+  if( (pList->nId & 7)==0 ){
+    pList->a = sqliteRealloc(pList->a, (pList->nId+8)*sizeof(pList->a[0]) );
+    if( pList->a==0 ){
+      pList->nId = 0;
+      return pList;
+    }
+  }
+  memset(&pList->a[pList->nId], 0, sizeof(pList->a[0]));
+  if( pToken ){
+    sqliteSetNString(&pList->a[pList->nId].zName, pToken->z, pToken->n, 0);
+  }
+  pList->nId++;
+  return pList;
+}
+
+/*
+** Add an alias to the last identifier on the given identifier list.
+*/
+void sqliteIdListAddAlias(IdList *pList, Token *pToken){
+  if( pList && pList->nId>0 ){
+    int i = pList->nId - 1;
+    sqliteSetNString(&pList->a[i].zAlias, pToken->z, pToken->n, 0);
+  }
+}
+
+/*
+** Delete an entire IdList
+*/
+void sqliteIdListDelete(IdList *pList){
+  int i;
+  if( pList==0 ) return;
+  for(i=0; i<pList->nId; i++){
+    sqliteFree(pList->a[i].zName);
+    sqliteFree(pList->a[i].zAlias);
+  }
+  sqliteFree(pList->a);
+  sqliteFree(pList);
+}
+
+/*
+** This routine is call to handle SQL of the following form:
+**
+**    insert into TABLE (IDLIST) values(EXPRLIST)
+**
+** The parameters are the table name and the expression list.
+*/
+void sqliteInsert(
+  Parse *pParse,        /* Parser context */
+  Token *pTableName,    /* Name of table into which we are inserting */
+  ExprList *pList,      /* List of values to be inserted */
+  IdList *pField        /* Field name corresponding to pList.  Might be NULL */
+){
+  Table *pTab;
+  char *zTab;
+  int i, j;
+  Vdbe *v;
+
+  zTab = sqliteTableNameFromToken(pTableName);
+  pTab = sqliteFindTable(pParse->db, zTab);
+  sqliteFree(zTab);
+  if( pTab==0 ){
+    sqliteSetNString(&pParse->zErrMsg, "no such table: \"", 0, 
+        pTableName->z, pTableName->n, "\"", 1, 0);
+    pParse->nErr++;
+    goto insert_cleanup;
+  }
+  if( pTab->readOnly ){
+    sqliteSetString(&pParse->zErrMsg, "table \"", pTab->zName,
+        "\" may not be modified", 0);
+    pParse->nErr++;
+    goto insert_cleanup;
+  }
+  if( pField==0 && pList->nExpr!=pTab->nCol ){
+    char zNum1[30];
+    char zNum2[30];
+    sprintf(zNum1,"%d", pList->nExpr);
+    sprintf(zNum2,"%d", pTab->nCol);
+    sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName,
+       " has ", zNum2, " columns but only ",
+       zNum1, " values were supplied", 0);
+    pParse->nErr++;
+    goto insert_cleanup;
+  }
+  if( pField!=0 && pList->nExpr!=pField->nId ){
+    char zNum1[30];
+    char zNum2[30];
+    sprintf(zNum1,"%d", pList->nExpr);
+    sprintf(zNum2,"%d", pTab->nCol);
+    sqliteSetString(&pParse->zErrMsg, zNum1, " values for ",
+       zNum2, " columns", 0);
+    pParse->nErr++;
+    goto insert_cleanup;
+  }
+  if( pField ){
+    for(i=0; i<pField->nId; i++){
+      pField->a[i].idx = -1;
+    }
+    for(i=0; i<pField->nId; i++){
+      for(j=0; j<pTab->nCol; j++){
+        if( sqliteStrICmp(pField->a[i].zName, pTab->azCol[j])==0 ){
+          pField->a[i].idx = j;
+          break;
+        }
+      }
+      if( j>=pTab->nCol ){
+        sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName,
+           " has no column named ", pField->a[i].zName, 0);
+        pParse->nErr++;
+        goto insert_cleanup;
+      }
+    }
+  }
+  v = pParse->pVdbe = sqliteVdbeCreate(pParse->db->pBe);
+  if( v ){
+    Index *pIdx;
+    sqliteVdbeAddOp(v, OP_Open, 0, 0, pTab->zName, 0);
+    sqliteVdbeAddOp(v, OP_New, 0, 0, 0, 0);
+    if( pTab->pIndex ){
+      sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
+    }
+    for(i=0; i<pTab->nCol; i++){
+      if( pField==0 ){
+        j = i;
+      }else{
+        for(j=0; j<pField->nId; j++){
+          if( pField->a[j].idx==i ) break;
+        }
+      }
+      if( pField && j>=pField->nId ){
+        sqliteVdbeAddOp(v, OP_String, 0, 0, "", 0);
+      }else{
+        sqliteExprCode(pParse, pList->a[j].pExpr);
+      }
+    }
+    sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0, 0, 0);
+    sqliteVdbeAddOp(v, OP_Put, 0, 0, 0, 0);
+    sqliteVdbeAddOp(v, OP_Close, 0, 0, 0, 0);
+    for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+      if( pIdx->pNext ){
+        sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
+      }
+      sqliteVdbeAddOp(v, OP_Open, 0, 0, pIdx->zName, 0);
+      for(i=0; i<pIdx->nField; i++){
+        int idx = pIdx->aiField[i];
+        if( pField==0 ){
+          j = idx;
+        }else{
+          for(j=0; j<pField->nId; j++){
+            if( pField->a[j].idx==idx ) break;
+          }
+        }
+        if( pField && j>=pField->nId ){
+          sqliteVdbeAddOp(v, OP_String, 0, 0, "", 0);
+        }else{
+          sqliteExprCode(pParse, pList->a[j].pExpr);
+        }
+      }
+      sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0);
+      sqliteVdbeAddOp(v, OP_PutIdx, 0, 0, 0, 0);
+      sqliteVdbeAddOp(v, OP_Close, 0, 0, 0, 0);
+    }
+  }
+
+insert_cleanup:
+  sqliteExprListDelete(pList);
+  sqliteIdListDelete(pField);
+}
+
+/*
+** This routine walks an expression tree and resolves references to
+** table fields.  Nodes of the form ID.ID or ID resolve into an
+** index to the table in the table list and a field offset.  The opcode
+** for such nodes is changed to TK_FIELD.  The iTable value is changed
+** to the index of the referenced table in pTabList, and the iField value
+** is changed to the index of the field of the referenced table.
+**
+** Unknown fields or tables provoke an error.  The function returns
+** the number of errors seen and leaves an error message on pParse->zErrMsg.
+*/
+int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
+  if( pExpr==0 ) return 0;
+  switch( pExpr->op ){
+    /* A lone identifier */
+    case TK_ID: {
+      int cnt = 0;   /* Number of matches */
+      int i;         /* Loop counter */
+      char *z = pExpr->token.z;
+      int n = pExpr->token.n;
+      for(i=0; i<pTabList->nId; i++){
+        int j;
+        Table *pTab = pTabList->a[i].pTab;
+        if( pTab==0 ) continue;
+        for(j=0; j<pTab->nCol; j++){
+          if( sqliteStrNICmp(pTab->azCol[j], z, n)==0 ){
+            cnt++;
+            pExpr->iTable = i;
+            pExpr->iField = j;
+          }
+        }
+      }
+      if( cnt==0 ){
+        sqliteSetNString(&pParse->zErrMsg, "unknown field name: \"", -1,  
+          pExpr->token.z, pExpr->token.n, "\"", -1, 0);
+        pParse->nErr++;
+        return 1;
+      }else if( cnt>1 ){
+        sqliteSetNString(&pParse->zErrMsg, "ambiguous field name: \"", -1,  
+          pExpr->token.z, pExpr->token.n, "\"", -1, 0);
+        pParse->nErr++;
+        return 1;
+      }
+      pExpr->op = TK_FIELD;
+      break; 
+    }
+  
+    /* A table name and field name:  ID.ID */
+    case TK_DOT: {
+      int cnt = 0;   /* Number of matches */
+      int i;         /* Loop counter */
+      Expr *pLeft, *pRight;    /* Left and right subbranches of the expr */
+      int n;                   /* Length of an identifier */
+      char *z;                 /* Text of an identifier */
+
+      pLeft = pExpr->pLeft;
+      pRight = pExpr->pRight;
+      assert( pLeft && pLeft->op==TK_ID );
+      assert( pRight && pRight->op==TK_ID );
+      n = pRight->token.n;
+      z = pRight->token.z;      
+      for(i=0; i<pTabList->nId; i++){
+        int j;
+        char *zTab;
+        Table *pTab = pTabList->a[i].pTab;
+        if( pTab==0 ) continue;
+        if( pTabList->a[i].zAlias ){
+          zTab = pTabList->a[i].zAlias;
+        }else{
+          zTab = pTab->zName;
+        }
+        if( sqliteStrNICmp(zTab, pLeft->token.z, pLeft->token.n)!=0 ) continue;
+        for(j=0; j<pTab->nCol; j++){
+          if( sqliteStrNICmp(pTab->azCol[j], z, n)==0 ){
+            cnt++;
+            pExpr->iTable = i;
+            pExpr->iField = j;
+          }
+        }
+      }
+      if( cnt==0 ){
+        sqliteSetNString(&pParse->zErrMsg, "unknown field name: \"", -1,  
+          pLeft->token.z, pLeft->token.n, ".", 1, z, n, "\"", 1, 0);
+        pParse->nErr++;
+        return 1;
+      }else if( cnt>1 ){
+        sqliteSetNString(&pParse->zErrMsg, "ambiguous field name: \"", -1,  
+          pExpr->token.z, pExpr->token.n, ".", 1, z, n, "\"", 1, 0);
+        pParse->nErr++;
+        return 1;
+      }
+      sqliteExprDelete(pLeft);
+      pExpr->pLeft = 0;
+      sqliteExprDelete(pRight);
+      pExpr->pRight = 0;
+      pExpr->op = TK_FIELD;
+      break;
+    }
+
+    /* For all else, just recursively walk the tree */
+    default: {
+      if( pExpr->pLeft 
+            && sqliteExprResolveIds(pParse, pTabList, pExpr->pLeft) ){
+        return 1;
+      }
+      if( pExpr->pRight 
+            && sqliteExprResolveIds(pParse, pTabList, pExpr->pRight) ){
+        return 1;
+      }
+      if( pExpr->pList ){
+        int i;
+        ExprList *pList = pExpr->pList;
+        for(i=0; i<pList->nExpr; i++){
+          if( sqliteExprResolveIds(pParse, pTabList, pList->a[i].pExpr) ){
+            return 1;
+          }
+        }
+      }
+    }
+  }
+  return 0;
+}
+
+/*
+** Process a SELECT statement.
+*/
+void sqliteSelect(
+  Parse *pParse,         /* The parser context */
+  ExprList *pEList,      /* List of fields to extract.  NULL means "*" */
+  IdList *pTabList,      /* List of tables to select from */
+  Expr *pWhere,          /* The WHERE clause.  May be NULL */
+  ExprList *pOrderBy     /* The ORDER BY clause.  May be NULL */
+){
+  int i, j;
+  WhereInfo *pWInfo;
+  Vdbe *v;
+
+  if( pParse->nErr>0 ) goto select_cleanup;
+
+  /* Look up every table in the table list.
+  */
+  for(i=0; i<pTabList->nId; i++){
+    pTabList->a[i].pTab = sqliteFindTable(pParse->db, pTabList->a[i].zName);
+    if( pTabList->a[i].pTab==0 ){
+      sqliteSetString(&pParse->zErrMsg, "unknown table \"", 
+         pTabList->a[i].zName, "\"", 0);
+      pParse->nErr++;
+      goto select_cleanup;
+    }
+  }
+
+  /* If the list of fields to retrieve is "*" then replace it with
+  ** a list of all fields from all tables.
+  */
+  if( pEList==0 ){
+    for(i=0; i<pTabList->nId; i++){
+      Table *pTab = pTabList->a[i].pTab;
+      for(j=0; j<pTab->nCol; j++){
+        Expr *pExpr = sqliteExpr(TK_FIELD, 0, 0, 0);
+        pExpr->iTable = i;
+        pExpr->iField = j;
+        pEList = sqliteExprListAppend(pEList, pExpr, 0);
+      }
+    }
+  }
+
+  /* Resolve the field names in all the expressions.
+  */
+  for(i=0; i<pEList->nExpr; i++){
+    if( sqliteExprResolveIds(pParse, pTabList, pEList->a[i].pExpr) ){
+      goto select_cleanup;
+    }
+  }
+  if( pWhere && sqliteExprResolveIds(pParse, pTabList, pWhere) ){
+    goto select_cleanup;
+  }
+  if( pOrderBy ){
+    for(i=0; i<pOrderBy->nExpr; i++){
+      if( sqliteExprResolveIds(pParse, pTabList, pOrderBy->a[i].pExpr) ){
+        goto select_cleanup;
+      }
+    }
+  }
+
+  /* Begin generating code.
+  */
+  v = pParse->pVdbe;
+  if( v==0 ){
+    v = pParse->pVdbe = sqliteVdbeCreate(pParse->db->pBe);
+  }
+  if( v==0 ) goto select_cleanup;
+  if( pOrderBy ){
+    sqliteVdbeAddOp(v, OP_SortOpen, 0, 0, 0, 0);
+  }
+
+
+  /* Identify column names
+  */
+  sqliteVdbeAddOp(v, OP_ColumnCount, pEList->nExpr, 0, 0, 0);
+  for(i=0; i<pEList->nExpr; i++){
+    Expr *p;
+    if( pEList->a[i].zName ){
+      char *zName = pEList->a[i].zName;
+      int addr = sqliteVdbeAddOp(v, OP_ColumnName, i, 0, zName, 0);
+      if( zName[0]=='\'' || zName[0]=='"' ){
+        sqliteVdbeDequoteP3(v, addr);
+      }
+      continue;
+    }
+    p = pEList->a[i].pExpr;
+    if( p->op!=TK_FIELD ){
+      char zName[30];
+      sprintf(zName, "field%d", i+1);
+      sqliteVdbeAddOp(v, OP_ColumnName, i, 0, zName, 0);
+    }else{
+      if( pTabList->nId>1 ){
+        char *zName = 0;
+        Table *pTab = pTabList->a[p->iTable].pTab;
+        sqliteSetString(&zName, pTab->zName, ".", 
+               pTab->azCol[p->iField], 0);
+        sqliteVdbeAddOp(v, OP_ColumnName, i, 0, zName, 0);
+        sqliteFree(zName);
+      }else{
+        Table *pTab = pTabList->a[0].pTab;
+        sqliteVdbeAddOp(v, OP_ColumnName, i, 0, pTab->azCol[p->iField], 0);
+      }
+    }
+  }
+
+  /* Begin the database scan
+  */  
+  pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 0);
+  if( pWInfo==0 ) goto select_cleanup;
+
+  /* Pull the requested fields.
+  */
+  for(i=0; i<pEList->nExpr; i++){
+    sqliteExprCode(pParse, pEList->a[i].pExpr);
+  }
+  
+  /* If there is no ORDER BY clause, then we can invoke the callback
+  ** right away.  If there is an ORDER BY, then we need to put the
+  ** data into an appropriate sorter record.
+  */
+  if( pOrderBy==0 ){
+    sqliteVdbeAddOp(v, OP_Callback, pEList->nExpr, 0, 0, 0);
+  }else{
+    char *zSortOrder;
+    sqliteVdbeAddOp(v, OP_SortMakeRec, pEList->nExpr, 0, 0, 0);
+    zSortOrder = sqliteMalloc( pOrderBy->nExpr + 1 );
+    if( zSortOrder==0 ) goto select_cleanup;
+    for(i=0; i<pOrderBy->nExpr; i++){
+      zSortOrder[i] = pOrderBy->a[i].idx ? '-' : '+';
+      sqliteExprCode(pParse, pOrderBy->a[i].pExpr);
+    }
+    zSortOrder[pOrderBy->nExpr] = 0;
+    sqliteVdbeAddOp(v, OP_SortMakeKey, pOrderBy->nExpr, 0, zSortOrder, 0);
+    sqliteVdbeAddOp(v, OP_SortPut, 0, 0, 0, 0);
+  }
+
+  /* End the database scan loop.
+  */
+  sqliteWhereEnd(pWInfo);
+
+  /* If there is an ORDER BY clause, then we need to sort the results
+  ** and send them to the callback one by one.
+  */
+  if( pOrderBy ){
+    int end = sqliteVdbeMakeLabel(v);
+    int addr;
+    sqliteVdbeAddOp(v, OP_Sort, 0, 0, 0, 0);
+    addr = sqliteVdbeAddOp(v, OP_SortNext, 0, end, 0, 0);
+    sqliteVdbeAddOp(v, OP_SortCallback, pEList->nExpr, 0, 0, 0);
+    sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0);
+    sqliteVdbeAddOp(v, OP_Noop, 0, 0, 0, end);
+  }
+
+  /* Always execute the following code before exiting, in order to
+  ** release resources.
+  */
+select_cleanup:
+  sqliteExprListDelete(pEList);
+  sqliteIdListDelete(pTabList);
+  sqliteExprDelete(pWhere);
+  sqliteExprListDelete(pOrderBy);
+  return;
+}
+
+/*
+** Process a DELETE FROM statement.
+*/
+void sqliteDeleteFrom(
+  Parse *pParse,         /* The parser context */
+  Token *pTableName,     /* The table from which we should delete things */
+  Expr *pWhere           /* The WHERE clause.  May be null */
+){
+  Vdbe *v;               /* The virtual database engine */
+  Table *pTab;           /* The table from which records will be deleted */
+  IdList *pTabList;      /* An ID list holding pTab and nothing else */
+  int end, addr;         /* A couple addresses of generated code */
+  int i;                 /* Loop counter */
+  WhereInfo *pWInfo;     /* Information about the WHERE clause */
+  Index *pIdx;           /* For looping over indices of the table */
+
+  /* Locate the table which we want to update.  This table has to be
+  ** put in an IdList structure because some of the subroutines will
+  ** will be calling are designed to work with multiple tables and expect
+  ** an IdList* parameter instead of just a Table* parameger.
+  */
+  pTabList = sqliteIdListAppend(0, pTableName);
+  for(i=0; i<pTabList->nId; i++){
+    pTabList->a[i].pTab = sqliteFindTable(pParse->db, pTabList->a[i].zName);
+    if( pTabList->a[i].pTab==0 ){
+      sqliteSetString(&pParse->zErrMsg, "unknown table \"", 
+         pTabList->a[i].zName, "\"", 0);
+      pParse->nErr++;
+      goto delete_from_cleanup;
+    }
+    if( pTabList->a[i].pTab->readOnly ){
+      sqliteSetString(&pParse->zErrMsg, "table \"", pTabList->a[i].zName,
+        "\" may not be modified", 0);
+      pParse->nErr++;
+      goto delete_from_cleanup;
+    }
+  }
+  pTab = pTabList->a[0].pTab;
+
+  /* Resolve the field names in all the expressions.
+  */
+  if( pWhere && sqliteExprResolveIds(pParse, pTabList, pWhere) ){
+    goto delete_from_cleanup;
+  }
+
+  /* Begin generating code.
+  */
+  v = pParse->pVdbe;
+  if( v==0 ){
+    v = pParse->pVdbe = sqliteVdbeCreate(pParse->db->pBe);
+  }
+  if( v==0 ) goto delete_from_cleanup;
+
+  /* Begin the database scan
+  */
+  sqliteVdbeAddOp(v, OP_ListOpen, 0, 0, 0, 0);
+  pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 1);
+  if( pWInfo==0 ) goto delete_from_cleanup;
+
+  /* Remember the index of every item to be deleted.
+  */
+  sqliteVdbeAddOp(v, OP_ListWrite, 0, 0, 0, 0);
+
+  /* End the database scan loop.
+  */
+  sqliteWhereEnd(pWInfo);
+
+  /* Delete every item identified in the list.
+  */
+  sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
+  for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
+    sqliteVdbeAddOp(v, OP_Open, i, 0, pIdx->zName, 0);
+  }
+  end = sqliteVdbeMakeLabel(v);
+  addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0);
+  if( pTab->pIndex ){
+    sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
+    sqliteVdbeAddOp(v, OP_Fetch, 0, 0, 0, 0);
+    for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
+      int j;
+      sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
+      for(j=0; j<pIdx->nField; j++){
+        sqliteVdbeAddOp(v, OP_Field, 0, pIdx->aiField[j], 0, 0);
+      }
+      sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0);
+      sqliteVdbeAddOp(v, OP_DeleteIdx, i, 0, 0, 0);
+    }
+  }
+  sqliteVdbeAddOp(v, OP_Delete, 0, 0, 0, 0);
+  sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0);
+  sqliteVdbeAddOp(v, OP_ListClose, 0, 0, 0, end);
+
+delete_from_cleanup:
+  sqliteIdListDelete(pTabList);
+  sqliteExprDelete(pWhere);
+  return;
+}
+
+/*
+** Process an UPDATE statement.
+*/
+void sqliteUpdate(
+  Parse *pParse,         /* The parser context */
+  Token *pTableName,     /* The table in which we should change things */
+  ExprList *pChanges,    /* Things to be changed */
+  Expr *pWhere           /* The WHERE clause.  May be null */
+){
+  int i, j;              /* Loop counters */
+  Table *pTab;           /* The table to be updated */
+  IdList *pTabList = 0;  /* List containing only pTab */
+  int end, addr;         /* A couple of addresses in the generated code */
+  WhereInfo *pWInfo;     /* Information about the WHERE clause */
+  Vdbe *v;               /* The virtual database engine */
+  Index *pIdx;           /* For looping over indices */
+  int nIdx;              /* Number of indices that need updating */
+  Index **apIdx = 0;     /* An array of indices that need updating too */
+  int *aXRef = 0;        /* aXRef[i] is the index in pChanges->a[] of the
+                         ** an expression for the i-th field of the table.
+                         ** aXRef[i]==-1 if the i-th field is not changed. */
+
+  /* Locate the table which we want to update.  This table has to be
+  ** put in an IdList structure because some of the subroutines will
+  ** will be calling are designed to work with multiple tables and expect
+  ** an IdList* parameter instead of just a Table* parameger.
+  */
+  pTabList = sqliteIdListAppend(0, pTableName);
+  for(i=0; i<pTabList->nId; i++){
+    pTabList->a[i].pTab = sqliteFindTable(pParse->db, pTabList->a[i].zName);
+    if( pTabList->a[i].pTab==0 ){
+      sqliteSetString(&pParse->zErrMsg, "unknown table \"", 
+         pTabList->a[i].zName, "\"", 0);
+      pParse->nErr++;
+      goto update_cleanup;
+    }
+    if( pTabList->a[i].pTab->readOnly ){
+      sqliteSetString(&pParse->zErrMsg, "table \"", pTabList->a[i].zName,
+        "\" may not be modified", 0);
+      pParse->nErr++;
+      goto update_cleanup;
+    }
+  }
+  pTab = pTabList->a[0].pTab;
+  aXRef = sqliteMalloc( sizeof(int) * pTab->nCol );
+  if( aXRef==0 ) goto update_cleanup;
+  for(i=0; i<pTab->nCol; i++) aXRef[i] = -1;
+
+  /* Resolve the field names in all the expressions in both the
+  ** WHERE clause and in the new values.  Also find the field index
+  ** for each field to be updated in the pChanges array.
+  */
+  if( pWhere && sqliteExprResolveIds(pParse, pTabList, pWhere) ){
+    goto update_cleanup;
+  }
+  for(i=0; i<pChanges->nExpr; i++){
+    if( sqliteExprResolveIds(pParse, pTabList, pChanges->a[i].pExpr) ){
+      goto update_cleanup;
+    }
+    for(j=0; j<pTab->nCol; j++){
+      if( strcmp(pTab->azCol[j], pChanges->a[i].zName)==0 ){
+        pChanges->a[i].idx = j;
+        aXRef[j] = i;
+        break;
+      }
+    }
+    if( j>=pTab->nCol ){
+      sqliteSetString(&pParse->zErrMsg, "no such field: \"", 
+         pChanges->a[i].zName, "\"", 0);
+      pParse->nErr++;
+      goto update_cleanup;
+    }
+  }
+
+  /* Allocate memory for the array apIdx[] and fill it pointers to every
+  ** index that needs to be updated.  Indices only need updating if their
+  ** key includes one of the fields named in pChanges.
+  */
+  for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+    for(i=0; i<pIdx->nField; i++){
+      if( aXRef[pIdx->aiField[i]]>=0 ) break;
+    }
+    if( i<pIdx->nField ) nIdx++;
+  }
+  apIdx = sqliteMalloc( sizeof(Index*) * nIdx );
+  if( apIdx==0 ) goto update_cleanup;
+  for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+    for(i=0; i<pIdx->nField; i++){
+      if( aXRef[pIdx->aiField[i]]>=0 ) break;
+    }
+    if( i<pIdx->nField ) apIdx[nIdx++] = pIdx;
+  }
+
+  /* Begin generating code.
+  */
+  v = pParse->pVdbe;
+  if( v==0 ){
+    v = pParse->pVdbe = sqliteVdbeCreate(pParse->db->pBe);
+  }
+  if( v==0 ) goto update_cleanup;
+
+  /* Begin the database scan
+  */
+  sqliteVdbeAddOp(v, OP_ListOpen, 0, 0, 0, 0);
+  pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 1);
+  if( pWInfo==0 ) goto update_cleanup;
+
+  /* Remember the index of every item to be updated.
+  */
+  sqliteVdbeAddOp(v, OP_ListWrite, 0, 0, 0, 0);
+
+  /* End the database scan loop.
+  */
+  sqliteWhereEnd(pWInfo);
+
+  /* Rewind the list of records that need to be updated and
+  ** open every index that needs updating.
+  */
+  sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
+  for(i=0; i<nIdx; i++){
+    sqliteVdbeAddOp(v, OP_Open, i+1, 0, apIdx[i]->zName, 0);
+  }
+
+  /* Loop over every record that needs updating.  We have to load
+  ** the old data for each record to be updated because some fields
+  ** might not change and we will need to copy the old value, therefore.
+  ** Also, the old data is needed to delete the old index entires.
+  */
+  end = sqliteVdbeMakeLabel(v);
+  addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0);
+  sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
+  sqliteVdbeAddOp(v, OP_Fetch, 0, 0, 0, 0);
+
+  /* Delete the old indices for the current record.
+  */
+  for(i=0; i<nIdx; i++){
+    sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
+    pIdx = apIdx[i];
+    for(j=0; j<pIdx->nField; j++){
+      sqliteVdbeAddOp(v, OP_Field, 0, pIdx->aiField[j], 0, 0);
+    }
+    sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0);
+    sqliteVdbeAddOp(v, OP_DeleteIdx, i+1, 0, 0, 0);
+  }
+
+  /* Compute a completely new data for this record.  
+  */
+  for(i=0; i<pTab->nCol; i++){
+    j = aXRef[i];
+    if( j<0 ){
+      sqliteVdbeAddOp(v, OP_Field, 0, i, 0, 0);
+    }else{
+      sqliteExprCode(pParse, pChanges->a[j].pExpr);
+    }
+  }
+
+  /* Insert new index entries that correspond to the new data
+  */
+  for(i=0; i<nIdx; i++){
+    sqliteVdbeAddOp(v, OP_Dup, pTab->nCol, 0, 0, 0); /* The KEY */
+    pIdx = apIdx[i];
+    for(j=0; j<pIdx->nField; j++){
+      sqliteVdbeAddOp(v, OP_Dup, j+pTab->nCol-pIdx->aiField[j], 0, 0, 0);
+    }
+    sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0);
+    sqliteVdbeAddOp(v, OP_PutIdx, i+1, 0, 0, 0);
+  }
+
+  /* Write the new data back into the database.
+  */
+  sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0, 0, 0);
+  sqliteVdbeAddOp(v, OP_Put, 0, 0, 0, 0);
+
+  /* Repeat the above with the next record to be updated, until
+  ** all record selected by the WHERE clause have been updated.
+  */
+  sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0);
+  sqliteVdbeAddOp(v, OP_ListClose, 0, 0, 0, end);
+
+update_cleanup:
+  sqliteFree(apIdx);
+  sqliteFree(aXRef);
+  sqliteIdListDelete(pTabList);
+  sqliteExprListDelete(pChanges);
+  sqliteExprDelete(pWhere);
+  return;
+}
diff --git a/src/dbbe.c b/src/dbbe.c
new file mode 100644 (file)
index 0000000..808d342
--- /dev/null
@@ -0,0 +1,510 @@
+/*
+** Copyright (c) 1999, 2000 D. Richard Hipp
+**
+** 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 library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*************************************************************************
+** This file contains code to implement the database baseend (DBBE)
+** for sqlite.  The database backend is the interface between
+** sqlite and the code that does the actually reading and writing
+** of information to the disk.
+**
+** This file uses GDBM as the database backend.  It should be
+** relatively simple to convert to a different database such
+** as NDBM, SDBM, or BerkeleyDB.
+**
+** $Id: dbbe.c,v 1.1 2000/05/29 14:26:01 drh Exp $
+*/
+#include "sqliteInt.h"
+#include <gdbm.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <time.h>
+
+/*
+** Each open database file is an instance of this structure.
+*/
+typedef struct BeFile BeFile;
+struct BeFile {
+  char *zName;            /* Name of the file */
+  GDBM_FILE dbf;          /* The file itself */
+  int nRef;               /* Number of references */
+  BeFile *pNext, *pPrev;  /* Next and previous on list of open files */
+};
+
+/*
+** The complete database is an instance of the following structure.
+*/
+struct Dbbe {
+  char *zDir;        /* The directory containing the database */
+  int write;         /* True for write permission */
+  BeFile *pOpen;     /* List of open files */
+  int nTemp;         /* Number of temporary files created */
+  FILE **apTemp;     /* Space to hold temporary file pointers */
+};
+
+/*
+** Each file within the database is an instance of this
+** structure.
+*/
+struct DbbeTable {
+  Dbbe *pBe;         /* The database of which this record is a part */
+  BeFile *pFile;     /* The database file for this table */
+  datum key;         /* Most recently used key */
+  datum data;        /* Most recent data */
+  int needRewind;    /* Next key should be the first */
+  int readPending;   /* The fetch hasn't actually been done yet */
+};
+
+/*
+** This routine opens a new database.  For the current driver scheme,
+** the database name is the name of the directory
+** containing all the files of the database.
+*/
+Dbbe *sqliteDbbeOpen(
+  const char *zName,     /* The name of the database */
+  int write,             /* True if we will be writing to the database */
+  int create,            /* True to create database if it doesn't exist */
+  char **pzErrMsg        /* Write error messages (if any) here */
+){
+  Dbbe *pNew;
+  struct stat statbuf;
+
+  if( stat(zName, &statbuf)!=0 ){
+    sqliteSetString(pzErrMsg, "can't find file \"", zName, "\"", 0);
+    return 0;
+  }
+  if( !S_ISDIR(statbuf.st_mode) ){
+    sqliteSetString(pzErrMsg, "not a directory: \"", zName, "\"", 0);
+    return 0;
+  }
+  pNew = sqliteMalloc(sizeof(Dbbe) + strlen(zName) + 1);
+  if( pNew==0 ){
+    sqliteSetString(pzErrMsg, "out of memory", 0);
+    return 0;
+  }
+  pNew->zDir = (char*)&pNew[1];
+  strcpy(pNew->zDir, zName);
+  pNew->write = write;
+  pNew->pOpen = 0;
+  return pNew;
+}
+
+/*
+** Completely shutdown the given database.  Close all files.  Free all memory.
+*/
+void sqliteDbbeClose(Dbbe *pBe){
+  BeFile *pFile, *pNext;
+  for(pFile=pBe->pOpen; pFile; pFile=pNext){
+    pNext = pFile->pNext;
+    gdbm_close(pFile->dbf);
+    memset(pFile, 0, sizeof(*pFile));   
+    sqliteFree(pFile);
+  }
+  memset(pBe, 0, sizeof(*pBe));
+  sqliteFree(pBe);
+}
+
+/*
+** Translate the name of a table into the name of a file that holds
+** that table.  Space to hold the filename is obtained from
+** sqliteMalloc() and must be freed by the calling function.
+*/
+static char *sqliteFileOfTable(Dbbe *pBe, const char *zTable){
+  char *zFile = 0;
+  int i;
+  sqliteSetString(&zFile, pBe->zDir, "/", zTable, ".tbl", 0);
+  if( zFile==0 ) return 0;
+  for(i=strlen(pBe->zDir)+1; zFile[i]; i++){
+    int c = zFile[i];
+    if( isupper(c) ){
+      zFile[i] = tolower(c);
+    }else if( !isalnum(c) && c!='-' && c!='_' && c!='.' ){
+      zFile[i] = '+';
+    }
+  }
+  return zFile;
+}
+
+/*
+** Open a new table cursor
+*/
+DbbeTable *sqliteDbbeOpenTable(
+  Dbbe *pBe,              /* The database the table belongs to */
+  const char *zTable,     /* The name of the table */
+  int writeable           /* True to open for writing */
+){
+  char *zFile;            /* Name of the table file */
+  DbbeTable *pTable;      /* The new table cursor */
+  BeFile *pFile;          /* The underlying data file for this table */
+
+  pTable = sqliteMalloc( sizeof(*pTable) );
+  if( pTable==0 ) return 0;
+  zFile = sqliteFileOfTable(pBe, zTable);
+  for(pFile=pBe->pOpen; pFile; pFile=pFile->pNext){
+    if( strcmp(pFile->zName,zFile)==0 ) break;
+  }
+  if( pFile==0 ){
+    pFile = sqliteMalloc( sizeof(*pFile) );
+    if( pFile==0 ){
+      sqliteFree(zFile);
+      return 0;
+    }
+    pFile->zName = zFile;
+    pFile->nRef = 1;
+    pFile->pPrev = 0;
+    if( pBe->pOpen ){
+      pBe->pOpen->pPrev = pFile;
+    }
+    pFile->pNext = pBe->pOpen;
+    pBe->pOpen = pFile;
+    pFile->dbf = gdbm_open(pFile->zName, 0, GDBM_WRCREAT, 0640, 0);
+  }else{
+    sqliteFree(zFile);
+    pFile->nRef++;
+  }
+  pTable->pBe = pBe;
+  pTable->pFile = pFile;
+  pTable->readPending = 0;
+  pTable->needRewind = 1;
+  return pTable;
+}
+
+/*
+** Drop a table from the database.
+*/
+void sqliteDbbeDropTable(Dbbe *pBe, const char *zTable){
+  char *zFile;            /* Name of the table file */
+
+  zFile = sqliteFileOfTable(pBe, zTable);
+  unlink(zFile);
+  sqliteFree(zFile);
+}
+
+/*
+** Close a table previously opened by sqliteDbbeOpenTable().
+*/
+void sqliteDbbeCloseTable(DbbeTable *pTable){
+  BeFile *pFile;
+  Dbbe *pBe;
+  if( pTable==0 ) return;
+  pFile = pTable->pFile;
+  pBe = pTable->pBe;
+  pFile->nRef--;
+  if( pFile->nRef<=0 ){
+    if( pFile->dbf!=NULL ){
+      gdbm_close(pFile->dbf);
+    }
+    if( pFile->pPrev ){
+      pFile->pPrev->pNext = pFile->pNext;
+    }else{
+      pBe->pOpen = pFile->pNext;
+    }
+    if( pFile->pNext ){
+      pFile->pNext->pPrev = pFile->pPrev;
+    }
+    sqliteFree(pFile->zName);
+    memset(pFile, 0, sizeof(*pFile));
+    sqliteFree(pFile);
+  }
+  if( pTable->key.dptr ) free(pTable->key.dptr);
+  if( pTable->data.dptr ) free(pTable->data.dptr);
+  memset(pTable, 0, sizeof(*pTable));
+  sqliteFree(pTable);
+}
+
+/*
+** Clear the given datum
+*/
+static void datumClear(datum *p){
+  if( p->dptr ) free(p->dptr);
+  p->dptr = 0;
+  p->dsize = 0;
+}
+
+/*
+** Fetch a single record from an open table.  Return 1 on success
+** and 0 on failure.
+*/
+int sqliteDbbeFetch(DbbeTable *pTable, int nKey, char *pKey){
+  datum key;
+  key.dsize = nKey;
+  key.dptr = pKey;
+  datumClear(&pTable->key);
+  datumClear(&pTable->data);
+  if( pTable->pFile && pTable->pFile->dbf ){
+    pTable->data = gdbm_fetch(pTable->pFile->dbf, key);
+  }
+  return pTable->data.dptr!=0;
+}
+
+/*
+** Copy bytes from the current key or data into a buffer supplied by
+** the calling function.  Return the number of bytes copied.
+*/
+int sqliteDbbeCopyKey(DbbeTable *pTable, int offset, int size, char *zBuf){
+  int n;
+  if( offset>=pTable->key.dsize ) return 0;
+  if( offset+size>pTable->key.dsize ){
+    n = pTable->key.dsize - offset;
+  }else{
+    n = size;
+  }
+  memcpy(zBuf, &pTable->key.dptr[offset], n);
+  return n;
+}
+int sqliteDbbeCopyData(DbbeTable *pTable, int offset, int size, char *zBuf){
+  int n;
+  if( pTable->readPending && pTable->pFile && pTable->pFile->dbf ){
+    pTable->data = gdbm_fetch(pTable->pFile->dbf, pTable->key);
+    pTable->readPending = 0;
+  }
+  if( offset>=pTable->data.dsize ) return 0;
+  if( offset+size>pTable->data.dsize ){
+    n = pTable->data.dsize - offset;
+  }else{
+    n = size;
+  }
+  memcpy(zBuf, &pTable->data.dptr[offset], n);
+  return n;
+}
+
+/*
+** Return a pointer to bytes from the key or data.  The data returned
+** is ephemeral.
+*/
+char *sqliteDbbeReadKey(DbbeTable *pTable, int offset){
+  if( offset<0 || offset>=pTable->key.dsize ) return "";
+  return &pTable->key.dptr[offset];
+}
+char *sqliteDbbeReadData(DbbeTable *pTable, int offset){
+  if( pTable->readPending && pTable->pFile && pTable->pFile->dbf ){
+    pTable->data = gdbm_fetch(pTable->pFile->dbf, pTable->key);
+    pTable->readPending = 0;
+  }
+  if( offset<0 || offset>=pTable->data.dsize ) return "";
+  return &pTable->data.dptr[offset];
+}
+
+/*
+** Return the total number of bytes in either data or key.
+*/
+int sqliteDbbeKeyLength(DbbeTable *pTable){
+  return pTable->key.dsize;
+}
+int sqliteDbbeDataLength(DbbeTable *pTable){
+  if( pTable->readPending && pTable->pFile && pTable->pFile->dbf ){
+    pTable->data = gdbm_fetch(pTable->pFile->dbf, pTable->key);
+    pTable->readPending = 0;
+  }
+  return pTable->data.dsize;
+}
+
+/*
+** Make is so that the next call to sqliteNextKey() finds the first
+** key of the table.
+*/
+int sqliteDbbeRewind(DbbeTable *pTable){
+  pTable->needRewind = 1;
+  return 0;
+}
+
+/*
+** Read the next key from the table.  Return 1 on success.  Return
+** 0 if there are no more keys.
+*/
+int sqliteDbbeNextKey(DbbeTable *pTable){
+  datum nextkey;
+  int rc;
+  if( pTable==0 || pTable->pFile==0 || pTable->pFile->dbf==0 ){
+    pTable->readPending = 0;
+    return 0;
+  }
+  if( pTable->needRewind ){
+    nextkey = gdbm_firstkey(pTable->pFile->dbf);
+    pTable->needRewind = 0;
+  }else{
+    nextkey = gdbm_nextkey(pTable->pFile->dbf, pTable->key);
+  }
+  datumClear(&pTable->key);
+  datumClear(&pTable->data);
+  pTable->key = nextkey;
+  if( pTable->key.dptr ){
+    pTable->readPending = 1;
+    rc = 1;
+  }else{
+    pTable->needRewind = 1;
+    pTable->readPending = 0;
+    rc = 0;
+  }
+  return rc;
+}
+
+/*
+** The following are state variables for the RC4 algorithm.  We
+** use RC4 as a random number generator.  Each call to RC4 gives
+** a random 8-bit number.
+*/
+static struct {
+  int i, j;
+  int s[256];
+} rc4;
+
+/*
+** Initialize the RC4 algorithm.
+*/
+static void rc4init(char *key, int keylen){
+  int i;
+  char k[256];
+  rc4.j = 0;
+  rc4.i = 0;
+  for(i=0; i<256; i++){
+    rc4.s[i] = i;
+    k[i] = key[i%keylen];
+  }
+  for(i=0; i<256; i++){
+    int t;
+    rc4.j = (rc4.j + rc4.s[i] + k[i]) & 0xff;
+    t = rc4.s[rc4.j];
+    rc4.s[rc4.j] = rc4.s[i];
+    rc4.s[i] = t;
+  }
+}
+
+/*
+** Get a single 8-bit random value from the RC4 algorithm.
+*/
+static int rc4byte(void){
+  int t;
+  rc4.i = (rc4.i + 1) & 0xff;
+  rc4.j = (rc4.j + rc4.s[rc4.i]) & 0xff;
+  t = rc4.s[rc4.i];
+  rc4.s[rc4.i] = rc4.s[rc4.j];
+  rc4.s[rc4.j] = t;
+  t = rc4.s[rc4.i] + rc4.s[rc4.j];
+  return t & 0xff;
+}
+
+/*
+** Get a new integer key.
+*/
+int sqliteDbbeNew(DbbeTable *pTable){
+  static int isInit = 0;
+  int iKey;
+  datum key;
+  int go = 1;
+  int i;
+
+  if( !isInit ){
+    struct stat statbuf;
+    stat(pTable->pFile->zName, &statbuf);
+    time(&statbuf.st_ctime);
+    rc4init((char*)&statbuf, sizeof(statbuf));
+    isInit = 1;
+  }
+  if( pTable->pFile==0 || pTable->pFile->dbf==0 ) return 1;
+  while( go ){
+    iKey = 0;
+    for(i=0; i<4; i++){
+      iKey = (iKey<<8) + rc4byte();
+    }
+    key.dptr = (char*)&iKey;
+    key.dsize = 4;
+    go = gdbm_exists(pTable->pFile->dbf, key);
+  }
+  return iKey;
+}   
+
+/*
+** Write an entry into the table.  Overwrite any prior entry with the
+** same key.
+*/
+int sqliteDbbePut(DbbeTable *pTable, int nKey,char *pKey,int nData,char *pData){
+  datum data, key;
+  if( pTable->pFile==0 || pTable->pFile->dbf==0 ) return 0;
+  data.dsize = nData;
+  data.dptr = pData;
+  key.dsize = nKey;
+  key.dptr = pKey;
+  gdbm_store(pTable->pFile->dbf, key, data, GDBM_REPLACE);
+  datumClear(&pTable->key);
+  datumClear(&pTable->data);
+  return 1;
+}
+
+/*
+** Remove an entry from a table, if the entry exists.
+*/
+int sqliteDbbeDelete(DbbeTable *pTable, int nKey, char *pKey){
+  datum key;
+  datumClear(&pTable->key);
+  datumClear(&pTable->data);
+  if( pTable->pFile==0 || pTable->pFile->dbf==0 ) return 0;
+  key.dsize = nKey;
+  key.dptr = pKey;
+  gdbm_delete(pTable->pFile->dbf, key);
+  return 1;
+}
+
+/*
+** Open a temporary file.
+*/
+FILE *sqliteDbbeOpenTempFile(Dbbe *pBe){
+  char *zFile;
+  char zBuf[30];
+  int i;
+
+  for(i=0; i<pBe->nTemp; i++){
+    if( pBe->apTemp[i]==0 ) break;
+  }
+  if( i>=pBe->nTemp ){
+    pBe->nTemp++;
+    pBe->apTemp = sqliteRealloc(pBe->apTemp, pBe->nTemp*sizeof(FILE*) );
+  }
+  if( pBe->apTemp==0 ) return 0;
+  sprintf(zBuf, "/_temp_%d~", i);
+  zFile = 0;
+  sqliteSetString(&zFile, pBe->zDir, zBuf, 0);
+  pBe->apTemp[i] = fopen(zFile, "w+");
+  sqliteFree(zFile);
+  return pBe->apTemp[i];
+}
+
+/*
+** Close a temporary file opened using sqliteDbbeOpenTempFile()
+*/
+void sqliteDbbeCloseTempFile(Dbbe *pBe, FILE *f){
+  int i;
+  for(i=0; i<pBe->nTemp; i++){
+    if( pBe->apTemp[i]==f ){
+      char *zFile;
+      char zBuf[30];
+      sprintf(zBuf, "/_temp_%d~", i);
+      zFile = 0;
+      sqliteSetString(&zFile, pBe->zDir, zBuf, 0);
+      unlink(zFile);
+      sqliteFree(zFile);
+      pBe->apTemp[i] = 0;
+      break;
+    }
+  }
+  fclose(f);
+}
diff --git a/src/dbbe.h b/src/dbbe.h
new file mode 100644 (file)
index 0000000..26e83a6
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+** Copyright (c) 1999, 2000 D. Richard Hipp
+**
+** 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 library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*************************************************************************
+** This file defines the interface to the database backend (Dbbe).
+**
+** The database backend is designed to be as general as possible
+** so that it can easily be replaced by a different backend.
+** This library was originally designed to support the following
+** backends: GDBM, NDBM, SDBM, Berkeley DB.
+**
+** $Id: dbbe.h,v 1.1 2000/05/29 14:26:01 drh Exp $
+*/
+#ifndef _SQLITE_DBBE_H_
+#define _SQLITE_DBBE_H_
+#include <stdio.h>
+
+/*
+** The database backend supports two opaque structures.  A Dbbe is
+** a context for the entire set of tables forming a complete
+** database.  A DbbeTable is a single table.  
+**
+** The DbbeTable structure holds some state information, such as
+** the key and data from the last retrieval.  For this reason, 
+** the backend must allow the creation of multiple independent
+** DbbeTable structures for each table in the database.
+*/
+typedef struct Dbbe Dbbe;
+typedef struct DbbeTable DbbeTable;
+
+/*
+** The 18 interface routines.
+*/
+
+/* Open a complete database */
+Dbbe *sqliteDbbeOpen(const char *zName, int write, int create, char **pzErr);
+
+/* Close the whole database. */
+void sqliteDbbeClose(Dbbe*);
+
+/* Open a particular table of a previously opened database.
+** Create the table if it doesn't already exist and writeable!=0.
+*/
+DbbeTable *sqliteDbbeOpenTable(Dbbe*, const char *zTableName, int writeable);
+
+/* Delete a table from the database */
+void sqliteDbbeDropTable(Dbbe*, const char *zTableName);
+
+/* Close a table */
+void sqliteDbbeCloseTable(DbbeTable*);
+
+/* Fetch an entry from a table with the given key.  Return 1 if
+** successful and 0 if no such entry exists.
+*/
+int sqliteDbbeFetch(DbbeTable*, int nKey, char *pKey);
+
+/* Retrieve the key or data used for the last fetch.  Only size
+** bytes are read beginning with the offset-th byte.  The return
+** value is the actual number of bytes read.
+*/
+int sqliteDbbeCopyKey(DbbeTable*, int offset, int size, char *zBuf);
+int sqliteDbbeCopyData(DbbeTable*, int offset, int size, char *zBuf);
+
+/* Retrieve the key or data.  The result is ephemeral.
+*/
+char *sqliteDbbeReadKey(DbbeTable*, int offset);
+char *sqliteDbbeReadData(DbbeTable*, int offset);
+
+/* Return the length of the most recently fetched key or data. */
+int sqliteDbbeKeyLength(DbbeTable*);
+int sqliteDbbeDataLength(DbbeTable*);
+
+/* Retrieve the next entry in the table.  The first key is retrieved
+** the first time this routine is called, or after a call to
+** sqliteDbbeRewind().  The return value is 1 if there is another
+** entry, or 0 if there are no more entries. */
+int sqliteDbbeNextKey(DbbeTable*);
+
+/* Make it so that the next call to sqliteDbbeNextKey() returns
+** the first entry of the table. */
+int sqliteDbbeRewind(DbbeTable*);
+
+/* Get a new integer key for this table. */
+int sqliteDbbeNew(DbbeTable*);
+
+/* Write an entry into a table.  If another entry already exists with
+** the same key, the old entry is discarded first.
+*/
+int sqliteDbbePut(DbbeTable*, int nKey, char *pKey, int nData, char *pData);
+
+/* Remove an entry from the table */
+int sqliteDbbeDelete(DbbeTable*, int nKey, char *pKey);
+
+/* Open a file suitable for temporary storage */
+FILE *sqliteDbbeOpenTempFile(Dbbe*);
+
+/* Close a temporary file */
+void sqliteDbbeCloseTempFile(Dbbe *, FILE *);
+
+#endif /* defined(_SQLITE_DBBE_H_) */
diff --git a/src/main.c b/src/main.c
new file mode 100644 (file)
index 0000000..4bbc75c
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+** Copyright (c) 1999, 2000 D. Richard Hipp
+**
+** 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 library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*************************************************************************
+** Main file for the SQLite library.  The routines in this file
+** implement the programmer interface to the library.  Routines in
+** other files are for internal use by SQLite and should not be
+** accessed by users of the library.
+**
+** $Id: main.c,v 1.1 2000/05/29 14:26:01 drh Exp $
+*/
+#include "sqliteInt.h"
+
+/*
+** This is the callback routine for the code that initializes the
+** database.  Each callback contains text of a CREATE TABLE or
+** CREATE INDEX statement that must be parsed to yield the internal
+** structures that describe the tables.
+*/
+static int sqliteOpenCb(void *pDb, int argc, char **argv, char **azColName){
+  sqlite *db = (sqlite*)pDb;
+  Parse sParse;
+  int nErr;
+  char *zErrMsg = 0;
+
+  if( argc!=1 ) return 0;
+  memset(&sParse, 0, sizeof(sParse));
+  sParse.db = db;
+  sParse.initFlag = 1;
+  nErr = sqliteRunParser(&sParse, argv[0], &zErrMsg);
+  return nErr;
+}
+
+/*
+** Open a new SQLite database.  Construct an "sqlite" structure to define
+** the state of this database and return a pointer to that structure.
+*/
+sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
+  sqlite *db;
+  Vdbe *vdbe;
+  Table *pTab;
+  char *azArg[2];
+  static char master_schema[] = 
+     "CREATE TABLE " MASTER_NAME " (\n"
+     "  type text,\n"
+     "  name text,\n"
+     "  tbl_name text,\n"
+     "  sql text\n"
+     ")"
+  ;
+
+  /* The following program is used to initialize the internal
+  ** structure holding the tables and indexes of the database.
+  ** The database contains a special table named "sqlite_master"
+  ** defined as follows:
+  **
+  **    CREATE TABLE sqlite_master (
+  **        type       text,    --  Either "table" or "index"
+  **        name       text,    --  Name of table or index
+  **        tbl_name   text,    --  Associated table 
+  **        sql        text     --  The CREATE statement for this object
+  **    );
+  **
+  ** The sqlite_master table contains a single entry for each table
+  ** and each index.  The "type" field tells whether the entry is
+  ** a table or index.  The "name" field is the name of the object.
+  ** The "tbl_name" is the name of the associated table.  For tables,
+  ** the tbl_name field is always the same as name.  For indices, the
+  ** tbl_name field contains the name of the table that the index
+  ** indexes.  Finally, the sql field contains the complete text of
+  ** the CREATE TABLE or CREATE INDEX statement that originally created
+  ** the table or index.
+  **
+  ** The following program invokes its callback on the SQL for each
+  ** table then goes back and invokes the callback on the
+  ** SQL for each index.  The callback will invoke the
+  ** parser to build the internal representation of the
+  ** database scheme.
+  */
+  static VdbeOp initProg[] = {
+    { OP_Open,     0, 0,  MASTER_NAME},
+    { OP_Next,     0, 8,  0},           /* 1 */
+    { OP_Field,    0, 0,  0},
+    { OP_String,   0, 0,  "table"},
+    { OP_Ne,       0, 1,  0},
+    { OP_Field,    0, 3,  0},
+    { OP_Callback, 1, 0,  0},
+    { OP_Goto,     0, 1,  0},
+    { OP_Rewind,   0, 0,  0},           /* 8 */
+    { OP_Next,     0, 16, 0},           /* 9 */
+    { OP_Field,    0, 0,  0},
+    { OP_String,   0, 0,  "index"},
+    { OP_Ne,       0, 9,  0},
+    { OP_Field,    0, 3,  0},
+    { OP_Callback, 1, 0,  0},
+    { OP_Goto,     0, 9,  0},
+    { OP_Halt,     0, 0,  0},           /* 16 */
+  };
+
+  /* Allocate space to hold the main database structure */
+  db = sqliteMalloc( sizeof(sqlite) );
+  if( pzErrMsg ) *pzErrMsg = 0;
+  if( db==0 ){
+    sqliteSetString(pzErrMsg, "out of memory", 0);
+    return 0;
+  }
+  
+  /* Open the backend database driver */
+  db->pBe = sqliteDbbeOpen(zFilename, (mode&0222)!=0, mode!=0, pzErrMsg);
+  if( db->pBe==0 ){
+    sqliteFree(db);
+    return 0;
+  }
+
+  /* Create a virtual machine to run the initialization program.  Run
+  ** the program.  The delete the virtual machine.
+  */
+  azArg[0] = master_schema;
+  azArg[1] = 0;
+  sqliteOpenCb(db, 1, azArg, 0);
+  pTab = sqliteFindTable(db, MASTER_NAME);
+  if( pTab ){
+    pTab->readOnly = 1;
+  }
+  vdbe = sqliteVdbeCreate(db->pBe);
+  sqliteVdbeAddOpList(vdbe, sizeof(initProg)/sizeof(initProg[0]), initProg);
+  sqliteVdbeExec(vdbe, sqliteOpenCb, db, pzErrMsg);
+  sqliteVdbeDelete(vdbe);
+  return db;
+}
+
+/*
+** Close an existing SQLite database
+*/
+void sqlite_close(sqlite *db){
+  int i;
+  sqliteDbbeClose(db->pBe);
+  for(i=0; i<N_HASH; i++){
+    Table *pNext, *pList = db->apTblHash[i];
+    db->apTblHash[i] = 0;
+    while( pList ){
+      pNext = pList->pHash;
+      pList->pHash = 0;
+      sqliteDeleteTable(db, pList);
+      pList = pNext;
+    }
+  }
+  sqliteFree(db);
+}
+
+/*
+** Return TRUE if the given SQL string ends in a semicolon.
+*/
+int sqlite_complete(const char *zSql){
+  int i;
+  int lastWasSemi = 0;
+
+  i = 0;
+  while( i>=0 && zSql[i]!=0 ){
+    int tokenType;
+    int n;
+
+    n = sqliteGetToken(&zSql[i], &tokenType);
+    switch( tokenType ){
+      case TK_SPACE:
+      case TK_COMMENT:
+        break;
+      case TK_SEMI:
+        lastWasSemi = 1;
+        break;
+      default:
+        lastWasSemi = 0;
+        break;
+    }
+    i += n;
+  }
+  return lastWasSemi;
+}
+
+/*
+** Execute SQL code 
+*/
+int sqlite_exec(
+  sqlite *db,                 /* The database on which the SQL executes */
+  char *zSql,                 /* The SQL to be executed */
+  sqlite_callback xCallback,  /* Invoke this callback routine */
+  void *pArg,                 /* First argument to xCallback() */
+  char **pzErrMsg             /* Write error messages here */
+){
+  Parse sParse;
+  int nErr;
+
+  if( pzErrMsg ) *pzErrMsg = 0;
+  memset(&sParse, 0, sizeof(sParse));
+  sParse.db = db;
+  sParse.xCallback = xCallback;
+  sParse.pArg = pArg;
+  nErr = sqliteRunParser(&sParse, zSql, pzErrMsg);
+  return nErr;
+}
diff --git a/src/shell.c b/src/shell.c
new file mode 100644 (file)
index 0000000..0812747
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+** Copyright (c) 1999, 2000 D. Richard Hipp
+**
+** 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 library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*************************************************************************
+** This file contains code to implement the "sqlite" command line
+** utility for accessing SQLite databases.
+**
+** $Id: shell.c,v 1.1 2000/05/29 14:26:01 drh Exp $
+*/
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "sqlite.h"
+#include <unistd.h>
+#include <ctype.h>
+
+#if !defined(NO_READLINE)
+#include <readline/readline.h>
+#include <readline/history.h>
+#endif
+
+/*
+** 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 {
+  int cnt;           /* Number of records displayed so far */
+  FILE *out;         /* Write results here */
+  int mode;          /* An output mode setting */
+  int showHeader;    /* True to show column names in List or Column mode */
+  char separator[20];/* Separator character for MODE_List */
+  int colWidth[30];  /* Width of each column when in column mode */
+};
+
+/*
+** These are the allowed modes.
+*/
+#define MODE_Line     0  /* One field 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 */
+
+/*
+** Number of elements in an array
+*/
+#define ArraySize(X)  (sizeof(X)/sizeof(X[0]))
+
+/*
+** 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: {
+      if( p->cnt++>0 ) fprintf(p->out,"\n");
+      for(i=0; i<nArg; i++){
+        fprintf(p->out,"%s = %s\n", azCol[i], azArg[i]);
+      }
+      break;
+    }
+    case MODE_Column: {
+      if( p->cnt++==0 && p->showHeader ){
+        for(i=0; i<nArg; i++){
+          int w;
+          if( i<ArraySize(p->colWidth) && p->colWidth[i]>0 ){
+             w = p->colWidth[i]; 
+          }else{
+             w = 10;
+          }
+          fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": "  ");
+        }
+        for(i=0; i<nArg; i++){
+          int w;
+          if( i<ArraySize(p->colWidth) && p->colWidth[i]>0 ){
+             w = p->colWidth[i];
+          }else{
+             w = 10;
+          }
+          fprintf(p->out,"%-*.*s%s",w,w,"-------------------------------------",
+                  i==nArg-1 ? "\n": "  ");
+        }
+      }
+      for(i=0; i<nArg; i++){
+        int w;
+        if( i<ArraySize(p->colWidth) && p->colWidth[i]>0 ){
+           w = p->colWidth[i];
+        }else{
+           w = 10;
+        }
+        fprintf(p->out,"%-*.*s%s",w,w,azArg[i], i==nArg-1 ? "\n": "  ");
+      }
+      break;
+    }
+    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);
+        }
+      }
+      for(i=0; i<nArg; i++){
+        fprintf(p->out,"%s%s",azArg[i], i==nArg-1 ? "\n" : p->separator);
+      }
+      break;
+    }
+  }      
+  return 0;
+}
+
+/*
+** Text of a help message
+*/
+static char zHelp[] = 
+  ".exit                  Exit this program\n"
+  ".explain               Set output mode suitable for EXPLAIN\n"
+  ".header ON|OFF         Turn display of headers on or off\n"
+  ".help                  Show this message\n"
+  ".indices TABLE         Show names of all indices on TABLE\n"
+  ".mode MODE             Set mode to one of \"line\", \"column\", or"
+                                      " \"list\"\n"
+  ".output FILENAME       Send output to FILENAME\n"
+  ".output stdout         Send output to the screen\n"
+  ".schema ?TABLE?        Show the CREATE statements\n"
+  ".separator STRING      Change separator string for \"list\" mode\n"
+  ".tables                List names all tables in the database\n"
+  ".width NUM NUM ...     Set column widths for \"column\" mode\n"
+;
+
+/*
+** If an input line begins with "." then invoke this routine to
+** process that line.
+*/
+static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
+  int i = 1;
+  int nArg = 0;
+  int n, c;
+  char *azArg[50];
+
+  /* Parse the input line into tokens.
+  */
+  while( zLine[i] && nArg<ArraySize(azArg) ){
+    while( isspace(zLine[i]) ){ i++; }
+    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;
+      }
+    }else{
+      azArg[nArg++] = &zLine[i];
+      while( zLine[i] && !isspace(zLine[i]) ){ i++; }
+      if( zLine[i] ) zLine[i++] = 0;
+    }
+  }
+
+  /* Process the input line.
+  */
+  if( nArg==0 ) return;
+  n = strlen(azArg[0]);
+  c = azArg[0][0];
+
+  if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
+    exit(0);
+  }else
+
+  if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
+    p->mode = MODE_Column;
+    p->showHeader = 1;
+    p->colWidth[0] = 4;
+    p->colWidth[1] = 12;
+    p->colWidth[2] = 5;
+    p->colWidth[3] = 5;
+    p->colWidth[4] = 40;
+  }else
+
+  if( c=='h' && strncmp(azArg[0], "header", n)==0 && nArg>1 ){
+    int j;
+    char *z = azArg[1];
+    int val = atoi(azArg[1]);
+    for(j=0; z[j]; j++){
+      if( isupper(z[j]) ) z[j] = tolower(z[j]);
+    }
+    if( strcmp(z,"on")==0 ){
+      val = 1;
+    }else if( strcmp(z,"yes")==0 ){
+      val = 1;
+    } 
+    p->showHeader = val;
+  }else
+
+  if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
+    fprintf(stderr,zHelp);
+  }else
+
+  if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg>1 ){
+    struct callback_data data;
+    char *zErrMsg = 0;
+    char zSql[1000];
+    memcpy(&data, p, sizeof(data));
+    data.showHeader = 0;
+    data.mode = MODE_List;
+    sprintf(zSql, "SELECT name FROM sqlite_master "
+                  "WHERE type='index' AND tbl_name='%.900s'", azArg[1]);
+    sqlite_exec(db, zSql, callback, &data, &zErrMsg);
+    if( zErrMsg ){
+      fprintf(stderr,"Error: %s\n", zErrMsg);
+      free(zErrMsg);
+    }
+  }else
+
+  if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg==2 ){
+    int n2 = strlen(azArg[1]);
+    if( strncmp(azArg[1],"line",n2)==0 ){
+      p->mode = MODE_Line;
+    }else if( strncmp(azArg[1],"column",n2)==0 ){
+      p->mode = MODE_Column;
+    }else if( strncmp(azArg[1],"list",n2)==0 ){
+      p->mode = MODE_List;
+    }
+  }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;
+    }else{
+      p->out = fopen(azArg[1], "w");
+      if( p->out==0 ){
+        fprintf(stderr,"can't write to \"%s\"\n", azArg[1]);
+        p->out = stdout;
+      }
+    }
+  }else
+
+  if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
+    struct callback_data data;
+    char *zErrMsg = 0;
+    char zSql[1000];
+    memcpy(&data, p, sizeof(data));
+    data.showHeader = 0;
+    data.mode = MODE_List;
+    if( nArg>1 ){
+      sprintf(zSql, "SELECT sql FROM sqlite_master WHERE name='%.900s'",
+         azArg[1]);
+    }else{
+      sprintf(zSql, "SELECT sql FROM sqlite_master "
+         "ORDER BY tbl_name, type DESC, name");
+    }
+    sqlite_exec(db, zSql, callback, &data, &zErrMsg);
+    if( zErrMsg ){
+      fprintf(stderr,"Error: %s\n", zErrMsg);
+      free(zErrMsg);
+    }
+  }else
+
+  if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){
+    sprintf(p->separator, "%.*s", (int)ArraySize(p->separator)-1, azArg[1]);
+  }else
+
+  if( c=='t' && strncmp(azArg[0], "tables", n)==0 ){
+    struct callback_data data;
+    char *zErrMsg = 0;
+    static char zSql[] = "SELECT name FROM sqlite_master WHERE type='table'";
+    memcpy(&data, p, sizeof(data));
+    data.showHeader = 0;
+    data.mode = MODE_List;
+    sqlite_exec(db, zSql, callback, &data, &zErrMsg);
+    if( zErrMsg ){
+      fprintf(stderr,"Error: %s\n", zErrMsg);
+      free(zErrMsg);
+    }
+  }else
+
+  if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
+    int j;
+    for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
+      p->colWidth[j-1] = atoi(azArg[j]);
+    }
+  }else
+
+  {
+    fprintf(stderr, "unknown command: \"%s\". Enter \".help\" for help\n",
+      azArg[0]);
+  }
+}
+
+int main(int argc, char **argv){
+  sqlite *db;
+  char *zErrMsg = 0;
+  struct callback_data data;
+
+  if( argc!=2 && argc!=3 ){
+    fprintf(stderr,"Usage: %s FILENAME ?SQL?\n", *argv);
+    exit(1);
+  }
+  db = sqlite_open(argv[1], 0666, &zErrMsg);
+  if( db==0 ){
+    fprintf(stderr,"Unable to open database \"%s\": %s\n", argv[1], zErrMsg);
+    exit(1);
+  }
+  memset(&data, 0, sizeof(data));
+  data.out = stdout;
+  if( argc==3 ){
+    data.mode = MODE_List;
+    strcpy(data.separator,"|");
+    if( sqlite_exec(db, argv[2], callback, &data, &zErrMsg)!=0 && zErrMsg!=0 ){
+      fprintf(stderr,"SQL error: %s\n", zErrMsg);
+      exit(1);
+    }
+  }else{
+    char *zLine;
+    char *zSql = 0;
+    int nSql = 0;
+    int istty = isatty(0);
+    data.mode = MODE_Line;
+    strcpy(data.separator,"|");
+    data.showHeader = 0;
+    if( istty ){
+      printf(
+        "Enter \".help\" for instructions\n"
+      );
+    }
+    while( (zLine = readline(istty ? (zSql==0 ? "sql> " : ".... ") : 0))!=0 ){
+      if( zLine && zLine[0]=='.' ){
+        do_meta_command(zLine, db, &data);
+        free(zLine);
+        continue;
+      }
+      if( zSql==0 ){
+        nSql = strlen(zLine);
+        zSql = malloc( nSql+1 );
+        strcpy(zSql, zLine);
+      }else{
+        int len = strlen(zLine);
+        zSql = realloc( zSql, nSql + len + 2 );
+        if( zSql==0 ){
+          fprintf(stderr,"%s: out of memory!\n", *argv);
+          exit(1);
+        }
+        strcpy(&zSql[nSql++], "\n");
+        strcpy(&zSql[nSql], zLine);
+        nSql += len;
+      }
+      free(zLine);
+      if( sqlite_complete(zSql) ){
+        data.cnt = 0;
+        if( sqlite_exec(db, zSql, callback, &data, &zErrMsg)!=0 
+             && zErrMsg!=0 ){
+          printf("SQL error: %s\n", zErrMsg);
+          free(zErrMsg);
+          zErrMsg = 0;
+        }
+        free(zSql);
+        zSql = 0;
+        nSql = 0;
+      }
+    }
+  }
+  sqlite_close(db);
+  return 0;
+}
diff --git a/src/sqlite.h b/src/sqlite.h
new file mode 100644 (file)
index 0000000..26b4874
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+** Copyright (c) 1999, 2000 D. Richard Hipp
+**
+** 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 library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*************************************************************************
+** This header file defines the interface that the sqlite library
+** presents to client programs.
+**
+** @(#) $Id: sqlite.h,v 1.1 2000/05/29 14:26:01 drh Exp $
+*/
+#ifndef _SQLITE_H_
+#define _SQLITE_H_
+
+/*
+** Each open sqlite database is represented by an instance of the
+** following opaque structure.
+*/
+typedef struct sqlite sqlite;
+
+/*
+** A function to open a new sqlite database.  
+**
+** If the database does not exist and mode indicates write
+** permission, then a new database is created.  If the database
+** does not exist and mode does not indicate write permission,
+** then the open fails, an error message generated (if errmsg!=0)
+** and the function returns 0.
+** 
+** If mode does not indicates user write permission, then the 
+** database is opened read-only.
+**
+** The Truth:  As currently implemented, all databases are opened
+** for writing all the time.  Maybe someday we will provide the
+** ability to open a database readonly.  The mode parameters is
+** provide in anticipation of that enhancement.
+*/
+sqlite *sqlite_open(const char *filename, int mode, char **errmsg);
+
+/*
+** A function to close the database.
+**
+** Call this function with a pointer to a structure that was previously
+** returned from sqlite_open() and the corresponding database will by closed.
+*/
+void sqlite_close(sqlite *);
+
+/*
+** The type for a callback function.
+*/
+typedef int (*sqlite_callback)(void*,int,char**, char**);
+
+/*
+** A function to executes one or more statements of SQL.
+**
+** If one or more of the SQL statements are queries, then
+** the callback function specified by the 3rd parameter is
+** invoked once for each row of the query result.  This callback
+** should normally return 0.  If the callback returns a non-zero
+** value then the query is aborted, all subsequent SQL statements
+** are skipped and the sqlite_exec() function returns the same
+** value that the callback returned.
+**
+** The 4th parameter is an arbitrary pointer that is passed
+** to the callback function as its first parameter.
+**
+** The 2nd parameter to the callback function is the number of
+** columns in the query result.  The 3rd parameter is an array
+** of string holding the values for each column.  The 4th parameter
+** is an array of strings holding the names of each column.
+**
+** The callback function may be NULL, even for queries.  A NULL
+** callback is not an error.  It just means that no callback
+** will be invoked.
+**
+** If an error occurs while parsing or evaluating the SQL (but
+** not while executing the callback) then an appropriate error
+** message is written into memory obtained from malloc() and
+** *errmsg is made to point to that message.  If errmsg==NULL,
+** then no error message is ever written.  The return value is
+** non-zero if an error occurs.
+*/
+int sqlite_exec(
+  sqlite*,                      /* An open database */
+  char *sql,                    /* SQL to be executed */
+  sqlite_callback,              /* Callback function */
+  void *,                       /* 1st argument to callback function */
+  char **errmsg                 /* Error msg written here */
+);
+
+
+/* This function returns true if the given input string comprises
+** one or more complete SQL statements.
+**
+** The algorithm is simple.  If the last token other than spaces
+** and comments is a semicolon, then return true.  otherwise return
+** false.
+*/
+int sqlite_complete(const char *sql);
+
+#endif /* _SQLITE_H_ */
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
new file mode 100644 (file)
index 0000000..b2bf129
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+** Copyright (c) 1999, 2000 D. Richard Hipp
+**
+** 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 library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*************************************************************************
+** Internal interface definitions for SQLite.
+**
+** @(#) $Id: sqliteInt.h,v 1.1 2000/05/29 14:26:01 drh Exp $
+*/
+#include "sqlite.h"
+#include "dbbe.h"
+#include "vdbe.h"
+#include "parse.h"
+#include <gdbm.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+/*
+** The number of entries in the in-memory hash table holding the
+** schema.
+*/
+#define N_HASH        51
+
+/*
+** Name of the master database table.  The master database table
+** is a special table that holds the names and attributes of all
+** user tables and indices.
+*/
+#define MASTER_NAME   "sqlite_master"
+
+/*
+** A convenience macro that returns the number of elements in
+** an array.
+*/
+#define ArraySize(X)    (sizeof(X)/sizeof(X[0]))
+
+/*
+** Forward references to structures
+*/
+typedef struct Table Table;
+typedef struct Index Index;
+typedef struct Instruction Instruction;
+typedef struct Expr Expr;
+typedef struct ExprList ExprList;
+typedef struct Parse Parse;
+typedef struct Token Token;
+typedef struct IdList IdList;
+typedef struct WhereInfo WhereInfo;
+
+/*
+** Each database is an instance of the following structure
+*/
+struct sqlite {
+  Dbbe *pBe;                 /* The backend driver */
+  int flags;                 /* Miscellanous flags */
+  Table *apTblHash[N_HASH];  /* All tables of the database */
+  Index *apIdxHash[N_HASH];  /* All indices of the database */
+};
+
+/*
+** Possible values for the flags field of sqlite
+*/
+#define SQLITE_VdbeTrace    0x00000001
+
+/*
+** Each table is represented in memory by
+** an instance of the following structure
+*/
+struct Table {
+  char *zName;        /* Name of the table */
+  Table *pHash;       /* Next table with same hash on zName */
+  int nCol;           /* Number of columns in this table */
+  int readOnly;       /* True if this table should not be written by the user */
+  char **azCol;       /* Name of each column */
+  Index *pIndex;      /* List of indices on this table. */
+};
+
+/*
+** Each index is represented in memory by and
+** instance of the following structure.
+*/
+struct Index {
+  char *zName;        /* Name of this index */
+  Index *pHash;       /* Next index with the same hash on zName */
+  int nField;         /* Number of fields in the table indexed by this index */
+  int *aiField;       /* Indices of fields used by this index.  1st is 0 */
+  Table *pTable;      /* The table being indexed */
+  Index *pNext;       /* The next index associated with the same table */
+};
+
+/*
+** Each token coming out of the lexer is an instance of
+** this structure.
+*/
+struct Token {
+  char *z;      /* Text of the token */
+  int n;        /* Number of characters in this token */
+};
+
+/*
+** Each node of an expression in the parse tree is an instance
+** of this structure
+*/
+struct Expr {
+  int op;                /* Operation performed by this node */
+  Expr *pLeft, *pRight;  /* Left and right subnodes */
+  ExprList *pList;       /* A list of expressions used as a function argument */
+  Token token;           /* An operand token */
+  int iTable, iField;    /* When op==TK_FIELD, then this node means the
+                         ** iField-th field of the iTable-th table */
+};
+
+/*
+** A list of expressions.  Each expression may optionally have a
+** name.  An expr/name combination can be used in several ways, such
+** as the list of "expr AS ID" fields following a "SELECT" or in the
+** list of "ID = expr" items in an UPDATE.  A list of expressions can
+** also be used as the argument to a function, in which case the azName
+** field is not used.
+*/
+struct ExprList {
+  int nExpr;             /* Number of expressions on the list */
+  struct {
+    Expr *pExpr;           /* The list of expressions */
+    char *zName;           /* Token associated with this expression */
+    int idx;               /* ... */
+  } *a;                  /* One entry for each expression */
+};
+
+/*
+** A list of identifiers.
+*/
+struct IdList {
+  int nId;         /* Number of identifiers on the list */
+  struct {
+    char *zName;      /* Text of the identifier. */
+    char *zAlias;     /* The "B" part of a "A AS B" phrase.  zName is the "A" */
+    Table *pTab;      /* Table corresponding to zName */
+    int idx;          /* Index of a field name in the table */
+  } *a;            /* One entry for each identifier on the list */
+};
+
+/*
+** The WHERE clause processing routine has two halves.  The
+** first part does the start of the WHERE loop and the second
+** half does the tail of the WHERE loop.  An instance of
+** this structure is returned by the first half and passed
+** into the second half to give some continuity.
+*/
+struct WhereInfo {
+  Parse *pParse;
+  IdList *pTabList;
+  int iContinue;
+  int iBreak;
+};
+
+/*
+** An SQL parser context
+*/
+struct Parse {
+  sqlite *db;          /* The main database structure */
+  sqlite_callback xCallback;  /* The callback function */
+  void *pArg;          /* First argument to the callback function */
+  char *zErrMsg;       /* An error message */
+  Token sErrToken;     /* The token at which the error occurred */
+  Token sFirstToken;   /* The first token parsed */
+  Token sLastToken;    /* The last token parsed */
+  Table *pNewTable;    /* A table being constructed by CREATE TABLE */
+  Vdbe *pVdbe;         /* An engine for executing database bytecode */
+  int explain;         /* True if the EXPLAIN flag is found on the query */
+  int initFlag;        /* True if reparsing CREATE TABLEs */
+  int nErr;            /* Number of errors seen */
+};
+
+/*
+** Internal function prototypes
+*/
+int sqliteStrICmp(const char *, const char *);
+int sqliteStrNICmp(const char *, const char *, int);
+int sqliteHashNoCase(const char *, int);
+int sqliteCompare(const char *, const char *);
+int sqliteSortCompare(const char *, const char *);
+void *sqliteMalloc(int);
+void sqliteFree(void*);
+void *sqliteRealloc(void*,int);
+int sqliteGetToken(const char*, int *);
+void sqliteSetString(char **, const char *, ...);
+void sqliteSetNString(char **, ...);
+int sqliteRunParser(Parse*, char*, char **);
+void sqliteExec(Parse*);
+Expr *sqliteExpr(int, Expr*, Expr*, Token*);
+Expr *sqliteExprFunction(ExprList*, Token*);
+void sqliteExprDelete(Expr*);
+ExprList *sqliteExprListAppend(ExprList*,Expr*,Token*);
+void sqliteExprListDelete(ExprList*);
+void sqliteStartTable(Parse*,Token*,Token*);
+void sqliteAddColumn(Parse*,Token*);
+void sqliteEndTable(Parse*,Token*);
+void sqliteDropTable(Parse*, Token*);
+void sqliteDeleteTable(sqlite*, Table*);
+void sqliteInsert(Parse*, Token*, ExprList*, IdList*);
+IdList *sqliteIdListAppend(IdList*, Token*);
+void sqliteIdListAddAlias(IdList*, Token*);
+void sqliteIdListDelete(IdList*);
+void sqliteCreateIndex(Parse*, Token*, Token*, IdList*, Token*, Token*);
+void sqliteDropIndex(Parse*, Token*);
+void sqliteSelect(Parse*, ExprList*, IdList*, Expr*, ExprList*);
+void sqliteDeleteFrom(Parse*, Token*, Expr*);
+void sqliteUpdate(Parse*, Token*, ExprList*, Expr*);
+WhereInfo *sqliteWhereBegin(Parse*, IdList*, Expr*, int);
+void sqliteWhereEnd(WhereInfo*);
+void sqliteExprCode(Parse*, Expr*);
+void sqliteExprIfTrue(Parse*, Expr*, int);
+void sqliteExprIfFalse(Parse*, Expr*, int);
+Table *sqliteFindTable(sqlite*,char*);
diff --git a/src/tclsqlite.c b/src/tclsqlite.c
new file mode 100644 (file)
index 0000000..55e9a85
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+** Copyright (c) 1999, 2000 D. Richard Hipp
+**
+** 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 library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*************************************************************************
+** A TCL Interface to SQLite
+**
+** $Id: tclsqlite.c,v 1.1 2000/05/29 14:26:01 drh Exp $
+*/
+#include "sqlite.h"
+#include <tcl.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+** An instance of this structure passes information thru the sqlite
+** logic from the original TCL command into the callback routine.
+*/
+typedef struct CallbackData CallbackData;
+struct CallbackData {
+  Tcl_Interp *interp;       /* The TCL interpreter */
+  char *zArray;             /* The array into which data is written */
+  char *zCode;              /* The code to execute for each row */
+  int once;                 /* Set only for the first invocation of callback */
+};
+
+/*
+** Called for each row of the result.
+*/
+static int DbEvalCallback(
+  void *clientData,      /* An instance of CallbackData */
+  int nCol,              /* Number of columns in the result */
+  char ** azCol,         /* Data for each column */
+  char ** azN            /* Name for each column */
+){
+  CallbackData *cbData = (CallbackData*)clientData;
+  int i, rc;
+  if( cbData->zArray[0] ){
+    if( cbData->once ){
+      for(i=0; i<nCol; i++){
+        Tcl_SetVar2(cbData->interp, cbData->zArray, "*", azN[i],
+           TCL_LIST_ELEMENT|TCL_APPEND_VALUE);
+      }
+    }
+    for(i=0; i<nCol; i++){
+      Tcl_SetVar2(cbData->interp, cbData->zArray, azN[i], azCol[i], 0);
+    }
+  }else{
+    for(i=0; i<nCol; i++){
+      Tcl_SetVar(cbData->interp, azN[i], azCol[i], 0);
+    }
+  }
+  cbData->once = 0;
+  rc = Tcl_Eval(cbData->interp, cbData->zCode);
+  return rc;
+}
+
+/*
+** Called when the command is deleted.
+*/
+static void DbDeleteCmd(void *db){
+  sqlite_close((sqlite*)db);
+}
+
+/*
+** The "sqlite" command below creates a new Tcl command for each
+** connection it opens to an SQLite database.  This routine is invoked
+** whenever one of those connection-specific commands is executed
+** in Tcl.  For example, if you run Tcl code like this:
+**
+**       sqlite db1  "my_database"
+**       db1 close
+**
+** The first command opens a connection to the "my_database" database
+** and calls that connection "db1".  The second command causes this
+** subroutine to be invoked.
+*/
+static int DbCmd(void *cd, Tcl_Interp *interp, int argc, char **argv){
+  char *z;
+  int n, c;
+  sqlite *db = cd;
+  if( argc<2 ){
+    Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
+        " SUBCOMMAND ...\"", 0);
+    return TCL_ERROR;
+  }
+  z = argv[1];
+  n = strlen(z);
+  c = z[0];
+
+  /*    $db close
+  **
+  ** Shutdown the database
+  */
+  if( c=='c' && n>=2 && strncmp(z,"close",n)==0 ){
+    Tcl_DeleteCommand(interp, argv[0]);
+  }else
+
+  /*    $db complete SQL
+  **
+  ** Return TRUE if SQL is a complete SQL statement.  Return FALSE if
+  ** additional lines of input are needed.  This is similar to the
+  ** built-in "info complete" command of Tcl.
+  */
+  if( c=='c' && n>=2 && strncmp(z,"complete",n)==0 ){
+    char *zRes;
+    if( argc!=3 ){
+      Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
+          " complete SQL\"", 0);
+      return TCL_ERROR;
+    }
+    zRes = sqlite_complete(argv[2]) ? "1" : "0";
+    Tcl_SetResult(interp, zRes, TCL_VOLATILE);
+  }else
+   
+  /*
+  **    $db eval $sql ?array {  ...code... }?
+  **
+  ** The SQL statement in $sql is evaluated.  For each row, the values are
+  ** placed in elements of the array named "array" and ...code.. is executed.
+  ** If "array" and "code" are omitted, then no callback is every invoked.
+  ** If "array" is an empty string, then the values are placed in variables
+  ** that have the same name as the fields extracted by the query.
+  */
+  if( c=='e' && strncmp(z,"eval",n)==0 ){
+    CallbackData cbData;
+    char *zErrMsg;
+    int rc;
+
+    if( argc!=5 && argc!=3 ){
+      Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
+         " eval SQL ?ARRAY-NAME CODE?", 0);
+      return TCL_ERROR;
+    }
+    if( argc==5 ){
+      cbData.interp = interp;
+      cbData.zArray = argv[3];
+      cbData.zCode = argv[4];
+      zErrMsg = 0;
+      rc = sqlite_exec(db, argv[2], DbEvalCallback, &cbData, &zErrMsg);
+    }else{
+      rc = sqlite_exec(db, argv[2], 0, 0, &zErrMsg);
+    }
+    if( zErrMsg ){
+      Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
+      free(zErrMsg);
+    }
+    return rc;
+  }
+
+  /* The default
+  */
+  else{
+    Tcl_AppendResult(interp,"unknown subcommand \"", z, 
+        "\" - should be one of: close complete eval", 0);
+    return TCL_ERROR;
+  }
+  return TCL_OK;
+}
+
+/*
+**   sqlite DBNAME FILENAME ?MODE?
+**
+** This is the main Tcl command.  When the "sqlite" Tcl command is
+** invoked, this routine runs to process that command.
+**
+** The first argument, DBNAME, is an arbitrary name for a new
+** database connection.  This command creates a new command named
+** DBNAME that is used to control that connection.  The database
+** connection is deleted when the DBNAME command is deleted.
+**
+** The second argument is the name of the directory that contains
+** the sqlite database that is to be accessed.
+*/
+static int DbMain(void *cd, Tcl_Interp *interp, int argc, char **argv){
+  int mode;
+  sqlite *p;
+  char *zErrMsg;
+  if( argc!=3 && argc!=4 ){
+    Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
+       " HANDLE FILENAME ?MODE?\"", 0);
+    return TCL_ERROR;
+  }
+  if( argc==3 ){
+    mode = 0;
+  }else if( Tcl_GetInt(interp, argv[3], &mode)!=TCL_OK ){
+    return TCL_ERROR;
+  }
+  zErrMsg = 0;
+  p = sqlite_open(argv[2], mode, &zErrMsg);
+  if( p==0 ){
+    Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
+    free(zErrMsg);
+    return TCL_ERROR;
+  }
+  Tcl_CreateCommand(interp, argv[1], DbCmd, p, DbDeleteCmd);
+  return TCL_OK;
+}
+
+/*
+** Initialize this module.
+**
+** This Tcl module contains only a single new Tcl command named "sqlite".
+** (Hence there is no namespace.  There is no point in using a namespace
+** if the extension only supplies one new name!)  The "sqlite" command is
+** used to open a new SQLite database.  See the DbMain() routine above
+** for additional information.
+*/
+int Sqlite_Init(Tcl_Interp *interp){
+  Tcl_CreateCommand(interp, "sqlite", DbMain, 0, 0);
+  return TCL_OK;
+}
+int Sqlite_SafeInit(Tcl_Interp *interp){
+  return TCL_OK;
+}
+
+/*
+** If compiled using mktclapp, this routine runs to initialize
+** everything.
+*/
+int Et_AppInit(Tcl_Interp *interp){
+  return Sqlite_Init(interp);
+}
diff --git a/src/tokenize.c b/src/tokenize.c
new file mode 100644 (file)
index 0000000..f762b67
--- /dev/null
@@ -0,0 +1,375 @@
+/*
+** Copyright (c) 1999, 2000 D. Richard Hipp
+**
+** 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 library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*************************************************************************
+** An tokenizer for SQL
+**
+** This file contains C code that splits an SQL input string up into
+** individual tokens and sends those tokens one-by-one over to the
+** parser for analysis.
+**
+** $Id: tokenize.c,v 1.1 2000/05/29 14:26:02 drh Exp $
+*/
+#include "sqliteInt.h"
+#include <ctype.h>
+
+/*
+** All the keywords of the SQL language are stored as in a hash
+** table composed of instances of the following structure.
+*/
+typedef struct Keyword Keyword;
+struct Keyword {
+  char *zName;             /* The keyword name */
+  int len;                 /* Number of characters in the keyword */
+  int tokenType;           /* The token value for this keyword */
+  Keyword *pNext;          /* Next keyword with the same hash */
+};
+
+/*
+** These are the keywords
+*/
+static Keyword aKeywordTable[] = {
+  { "AND",               0, TK_AND,              0 },
+  { "AS",                0, TK_AS,               0 },
+  { "ASC",               0, TK_ASC,              0 },
+  { "BY",                0, TK_BY,               0 },
+  { "CHECK",             0, TK_CHECK,            0 },
+  { "CONSTRAINT",        0, TK_CONSTRAINT,       0 },
+  { "CREATE",            0, TK_CREATE,           0 },
+  { "DEFAULT",           0, TK_DEFAULT,          0 },
+  { "DELETE",            0, TK_DELETE,           0 },
+  { "DESC",              0, TK_DESC,             0 },
+  { "DROP",              0, TK_DROP,             0 },
+  { "EXPLAIN",           0, TK_EXPLAIN,          0 },
+  { "FROM",              0, TK_FROM,             0 },
+  { "INDEX",             0, TK_INDEX,            0 },
+  { "INSERT",            0, TK_INSERT,           0 },
+  { "INTO",              0, TK_INTO,             0 },
+  { "IS",                0, TK_IS,               0 },
+  { "ISNULL",            0, TK_ISNULL,           0 },
+  { "KEY",               0, TK_KEY,              0 },
+  { "NOT",               0, TK_NOT,              0 },
+  { "NOTNULL",           0, TK_NOTNULL,          0 },
+  { "NULL",              0, TK_NULL,             0 },
+  { "ON",                0, TK_ON,               0 },
+  { "OR",                0, TK_OR,               0 },
+  { "ORDER",             0, TK_ORDER,            0 },
+  { "PRIMARY",           0, TK_PRIMARY,          0 },
+  { "SELECT",            0, TK_SELECT,           0 },
+  { "SET",               0, TK_SET,              0 },
+  { "TABLE",             0, TK_TABLE,            0 },
+  { "UNIQUE",            0, TK_UNIQUE,           0 },
+  { "UPDATE",            0, TK_UPDATE,           0 },
+  { "VALUES",            0, TK_VALUES,           0 },
+  { "WHERE",             0, TK_WHERE,            0 },
+};
+
+/*
+** This is the hash table
+*/
+#define KEY_HASH_SIZE 37
+static Keyword *apHashTable[KEY_HASH_SIZE];
+
+
+/*
+** This function looks up an identifier to determine if it is a
+** keyword.  If it is a keyword, the token code of that keyword is 
+** returned.  If the input is not a keyword, TK_ID is returned.
+*/
+static int sqliteKeywordCode(const char *z, int n){
+  int h;
+  Keyword *p;
+  if( aKeywordTable[0].len==0 ){
+    /* Initialize the keyword hash table */
+    int i;
+    int n;
+    n = sizeof(aKeywordTable)/sizeof(aKeywordTable[0]);
+    for(i=0; i<n; i++){
+      aKeywordTable[i].len = strlen(aKeywordTable[i].zName);
+      h = sqliteHashNoCase(aKeywordTable[i].zName, aKeywordTable[i].len);
+      h %= KEY_HASH_SIZE;
+      aKeywordTable[i].pNext = apHashTable[h];
+      apHashTable[h] = &aKeywordTable[i];
+    }
+  }
+  h = sqliteHashNoCase(z, n) % KEY_HASH_SIZE;
+  for(p=apHashTable[h]; p; p=p->pNext){
+    if( p->len==n && sqliteStrNICmp(p->zName, z, n)==0 ){
+      return p->tokenType;
+    }
+  }
+  return TK_ID;
+}
+
+/*
+** Return the length of the token that begins at z[0].  Return
+** -1 if the token is (or might be) incomplete.  Store the token
+** type in *tokenType before returning.
+*/
+int sqliteGetToken(const char *z, int *tokenType){
+  int i;
+  switch( *z ){
+    case ' ': case '\t': case '\n': case '\f': {
+      for(i=1; z[i] && isspace(z[i]); i++){}
+      *tokenType = TK_SPACE;
+      return i;
+    }
+    case '-': {
+      if( z[1]==0 ) return -1;
+      if( z[1]=='-' ){
+        for(i=2; z[i] && z[i]!='\n'; i++){}
+        *tokenType = TK_COMMENT;
+        return i;
+      }
+      *tokenType = TK_MINUS;
+      return 1;
+    }
+    case '(': {
+      *tokenType = TK_LP;
+      return 1;
+    }
+    case ')': {
+      *tokenType = TK_RP;
+      return 1;
+    }
+    case ';': {
+      *tokenType = TK_SEMI;
+      return 1;
+    }
+    case '+': {
+      *tokenType = TK_PLUS;
+      return 1;
+    }
+    case '*': {
+      *tokenType = TK_STAR;
+      return 1;
+    }
+    case '/': {
+      *tokenType = TK_SLASH;
+      return 1;
+    }
+    case '=': {
+      *tokenType = TK_EQ;
+      return 1 + (z[1]=='=');
+    }
+    case '<': {
+      if( z[1]=='=' ){
+        *tokenType = TK_LE;
+        return 2;
+      }else if( z[1]=='>' ){
+        *tokenType = TK_NE;
+        return 2;
+      }else{
+        *tokenType = TK_LT;
+        return 1;
+      }
+    }
+    case '>': {
+      if( z[1]=='=' ){
+        *tokenType = TK_GE;
+        return 2;
+      }else{
+        *tokenType = TK_GT;
+        return 1;
+      }
+    }
+    case '!': {
+      if( z[1]!='=' ){
+        *tokenType = TK_ILLEGAL;
+        return 1;
+      }else{
+        *tokenType = TK_NE;
+        return 2;
+      }
+    }
+    case ',': {
+      *tokenType = TK_COMMA;
+      return 1;
+    }
+    case '\'': case '"': {
+      int delim = z[0];
+      for(i=1; z[i]; i++){
+        if( z[i]==delim ){
+          if( z[i+1]==delim ){
+            i++;
+          }else{
+            break;
+          }
+        }
+      }
+      if( z[i] ) i++;
+      *tokenType = TK_STRING;
+      return i;
+    }
+    case '.': {
+      if( !isdigit(z[1]) ){
+        *tokenType = TK_DOT;
+        return 1;
+      }
+      /* Fall thru into the next case */
+    }
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9': {
+      for(i=1; z[i] && isdigit(z[i]); i++){}
+      if( z[i]=='.' ){
+        i++;
+        while( z[i] && isdigit(z[i]) ){ i++; }
+        if( (z[i]=='e' || z[i]=='E') &&
+           ( isdigit(z[i+1]) 
+            || ((z[i+1]=='+' || z[i+1]=='-') && isdigit(z[i+2]))
+           )
+        ){
+          i += 2;
+          while( z[i] && isdigit(z[i]) ){ i++; }
+        }
+        *tokenType = TK_FLOAT;
+      }else if( z[0]=='.' ){
+        *tokenType = TK_FLOAT;
+      }else{
+        *tokenType = TK_INTEGER;
+      }
+      return i;
+    }
+    case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+    case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
+    case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
+    case 's': case 't': case 'u': case 'v': case 'w': case 'x':
+    case 'y': case 'z': case '_':
+    case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+    case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
+    case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
+    case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
+    case 'Y': case 'Z': {
+      for(i=1; z[i] && (isalnum(z[i]) || z[i]=='_'); i++){}
+      *tokenType = sqliteKeywordCode(z, i);
+      return i;
+    }
+    default: {
+      break;
+    }
+  }
+  *tokenType = TK_ILLEGAL;
+  return 1;
+}
+
+/*
+** Run the parser on the given SQL string.  The parser structure is
+** passed in.  Return the number of errors.
+*/
+int sqliteRunParser(Parse *pParse, char *zSql, char **pzErrMsg){
+  int nErr = 0;
+  int i;
+  void *pEngine;
+  int once = 1;
+  static FILE *trace = 0;
+  extern void *sqliteParserAlloc(void*(*)(int));
+  extern void sqliteParserFree(void*, void(*)(void*));
+  extern int sqliteParser(void*, int, ...);
+  extern void sqliteParserTrace(FILE*, char *);
+
+  i = 0;
+  pEngine = sqliteParserAlloc(sqliteMalloc);
+  if( pEngine==0 ){
+    sqliteSetString(pzErrMsg, "out of memory", 0);
+    return 1;
+  }
+  sqliteParserTrace(trace, "parser: ");
+  while( nErr==0 && i>=0 && zSql[i]!=0 ){
+    int tokenType;
+    
+    pParse->sLastToken.z = &zSql[i];
+    pParse->sLastToken.n = sqliteGetToken(&zSql[i], &tokenType);
+    i += pParse->sLastToken.n;
+    if( once ){
+      pParse->sFirstToken = pParse->sLastToken;
+      once = 0;
+    }
+    switch( tokenType ){
+      case TK_SPACE:
+        break;
+      case TK_COMMENT: {
+        /* Various debugging modes can be turned on and off using
+        ** special SQL comments.  Check for the special comments
+        ** here and take approriate action if found.
+        */
+        char *z = pParse->sLastToken.z;
+        if( sqliteStrNICmp(z,"--parser-trace-on--",19)==0 ){
+          trace = stderr;
+          sqliteParserTrace(trace, "parser: ");
+        }else if( sqliteStrNICmp(z,"--parser-trace-off--", 20)==0 ){
+          trace = 0;
+          sqliteParserTrace(trace, "parser: ");
+        }else if( sqliteStrNICmp(z,"--vdbe-trace-on--",17)==0 ){
+          pParse->db->flags |= SQLITE_VdbeTrace;
+        }else if( sqliteStrNICmp(z,"--vdbe-trace-off--", 19)==0 ){
+          pParse->db->flags &= ~SQLITE_VdbeTrace;
+        }
+        break;
+      }
+      case TK_ILLEGAL:
+        sqliteSetNString(pzErrMsg, "illegal token: \"", -1, 
+           pParse->sLastToken.z, pParse->sLastToken.n, 0);
+        nErr++;
+        break;
+      default:
+        sqliteParser(pEngine, tokenType, pParse->sLastToken, pParse);
+        if( pParse->zErrMsg ){
+          sqliteSetNString(pzErrMsg, "near \"", -1, 
+             pParse->sErrToken.z, pParse->sErrToken.n,
+             "\": ", -1,
+             pParse->zErrMsg, -1,
+             0);
+          nErr++;
+        }
+        break;
+    }
+  }
+  if( nErr==0 ){
+    sqliteParser(pEngine, 0, pParse->sLastToken, pParse);
+    if( pParse->zErrMsg ){
+       sqliteSetNString(pzErrMsg, "near \"", -1, 
+          pParse->sErrToken.z, pParse->sErrToken.n,
+          "\": ", -1,
+          pParse->zErrMsg, -1,
+          0);
+       nErr++;
+    }
+  }
+  sqliteParserFree(pEngine, sqliteFree);
+  if( pParse->zErrMsg ){
+    if( pzErrMsg ){
+      *pzErrMsg = pParse->zErrMsg;
+    }else{
+      sqliteFree(pParse->zErrMsg);
+    }
+    if( !nErr ) nErr++;
+  }
+  if( pParse->pVdbe ){
+    sqliteVdbeDelete(pParse->pVdbe);
+    pParse->pVdbe = 0;
+  }
+  if( pParse->pNewTable ){
+    sqliteDeleteTable(pParse->db, pParse->pNewTable);
+    pParse->pNewTable = 0;
+  }
+  return nErr;
+}
diff --git a/src/util.c b/src/util.c
new file mode 100644 (file)
index 0000000..1306345
--- /dev/null
@@ -0,0 +1,445 @@
+/*
+** Copyright (c) 1999, 2000 D. Richard Hipp
+**
+** 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 library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*************************************************************************
+** Utility functions used throughout sqlite.
+**
+** This file contains functions for allocating memory, comparing
+** strings, and stuff like that.
+**
+** $Id: util.c,v 1.1 2000/05/29 14:26:02 drh Exp $
+*/
+#include "sqliteInt.h"
+#include <stdarg.h>
+#include <ctype.h>
+
+/*
+** Allocate new memory and set it to zero.  Return NULL if
+** no memory is available.
+*/
+void *sqliteMalloc(int n){
+  void *p = malloc(n);
+  if( p==0 ) return 0;
+  memset(p, 0, n);
+  return p;
+}
+
+/*
+** Free memory previously obtained from sqliteMalloc()
+*/
+void sqliteFree(void *p){
+  if( p ) free(p);
+}
+
+/*
+** Resize a prior allocation.  If p==0, then this routine
+** works just like sqliteMalloc().  If n==0, then this routine
+** works just like sqliteFree().
+*/
+void *sqliteRealloc(void *p, int n){
+  if( p==0 ){
+    return sqliteMalloc(n);
+  }
+  if( n==0 ){
+    sqliteFree(p);
+    return 0;
+  }
+  return realloc(p, n);
+}
+
+/*
+** Create a string from the 2nd and subsequent arguments (up to the
+** first NULL argument), store the string in memory obtained from
+** sqliteMalloc() and make the pointer indicated by the 1st argument
+** point to that string.
+*/
+void sqliteSetString(char **pz, const char *zFirst, ...){
+  va_list ap;
+  int nByte;
+  const char *z;
+  char *zResult;
+
+  if( pz==0 ) return;
+  nByte = strlen(zFirst) + 1;
+  va_start(ap, zFirst);
+  while( (z = va_arg(ap, const char*))!=0 ){
+    nByte += strlen(z);
+  }
+  va_end(ap);
+  sqliteFree(*pz);
+  *pz = zResult = sqliteMalloc( nByte );
+  if( zResult==0 ) return;
+  strcpy(zResult, zFirst);
+  zResult += strlen(zResult);
+  va_start(ap, zFirst);
+  while( (z = va_arg(ap, const char*))!=0 ){
+    strcpy(zResult, z);
+    zResult += strlen(zResult);
+  }
+  va_end(ap);
+}
+
+/*
+** Works like sqliteSetString, but each string is now followed by
+** a length integer.  -1 means use the whole string.
+*/
+void sqliteSetNString(char **pz, ...){
+  va_list ap;
+  int nByte;
+  const char *z;
+  char *zResult;
+  int n;
+
+  if( pz==0 ) return;
+  nByte = 0;
+  va_start(ap, pz);
+  while( (z = va_arg(ap, const char*))!=0 ){
+    n = va_arg(ap, int);
+    if( n<=0 ) n = strlen(z);
+    nByte += n;
+  }
+  va_end(ap);
+  sqliteFree(*pz);
+  *pz = zResult = sqliteMalloc( nByte + 1 );
+  if( zResult==0 ) return;
+  va_start(ap, pz);
+  while( (z = va_arg(ap, const char*))!=0 ){
+    n = va_arg(ap, int);
+    if( n<=0 ) n = strlen(z);
+    strncpy(zResult, z, n);
+    zResult += n;
+  }
+  *zResult = 0;
+  va_end(ap);
+}
+
+/* An array to map all upper-case characters into their corresponding
+** lower-case character. 
+*/
+static unsigned char UpperToLower[] = {
+      0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,
+     18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+     36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+     54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103,
+    104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,
+    122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,
+    108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,
+    126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
+    144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,
+    162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,
+    180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,
+    198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,
+    216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,
+    234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,
+    252,253,254,255
+};
+
+/*
+** This function computes a hash on the name of a keyword.
+** Case is not significant.
+*/
+int sqliteHashNoCase(const char *z, int n){
+  int h = 0;
+  int c;
+  if( n<=0 ) n = strlen(z);
+  while( n-- > 0 && (c = *z++)!=0 ){
+    h = h<<3 ^ h ^ UpperToLower[c];
+  }
+  if( h<0 ) h = -h;
+  return h;
+}
+
+/*
+** Some system shave stricmp().  Others have strcasecmp().  Because
+** there is no consistency, we will define our own.
+*/
+int sqliteStrICmp(const char *zLeft, const char *zRight){
+  register unsigned char *a, *b;
+  a = (unsigned char *)zLeft;
+  b = (unsigned char *)zRight;
+  while( *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
+  return *a - *b;
+}
+int sqliteStrNICmp(const char *zLeft, const char *zRight, int N){
+  register unsigned char *a, *b;
+  a = (unsigned char *)zLeft;
+  b = (unsigned char *)zRight;
+  while( N-- > 0 && *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
+  return N<=0 ? 0 : *a - *b;
+}
+
+/* Notes on string comparisions.
+**
+** We want the main string comparision function used for sorting to
+** sort both numbers and alphanumeric words into the correct sequence.
+** The same routine should do both without prior knowledge of which
+** type of text the input represents.  It should even work for strings
+** which are a mixture of text and numbers.
+**
+** To accomplish this, we keep track of a state number while scanning
+** the two strings.  The states are as follows:
+**
+**    1      Beginning of word
+**    2      Arbitrary text
+**    3      Integer
+**    4      Negative integer
+**    5      Real number
+**    6      Negative real
+**
+** The scan begins in state 1, beginning of word.  Transitions to other
+** states are determined by characters seen, as shown in the following
+** chart:
+**
+**      Current State         Character Seen  New State
+**      --------------------  --------------  -------------------
+**      0 Beginning of word   "-"             3 Negative integer
+**                            digit           2 Integer
+**                            space           0 Beginning of word
+**                            otherwise       1 Arbitrary text
+**
+**      1 Arbitrary text      space           0 Beginning of word
+**                            digit           2 Integer
+**                            otherwise       1 Arbitrary text
+**
+**      2 Integer             space           0 Beginning of word
+**                            "."             4 Real number
+**                            digit           2 Integer
+**                            otherwise       1 Arbitrary text
+**
+**      3 Negative integer    space           0 Beginning of word
+**                            "."             5 Negative Real num
+**                            digit           3 Negative integer
+**                            otherwise       1 Arbitrary text
+**
+**      4 Real number         space           0 Beginning of word
+**                            digit           4 Real number
+**                            otherwise       1 Arbitrary text
+**
+**      5 Negative real num   space           0 Beginning of word
+**                            digit           5 Negative real num
+**                            otherwise       1 Arbitrary text
+**
+** To implement this state machine, we first classify each character
+** into on of the following categories:
+**
+**      0  Text
+**      1  Space
+**      2  Digit
+**      3  "-"
+**      4  "."
+**
+** Given an arbitrary character, the array charClass[] maps that character
+** into one of the atove categories.
+*/
+static const unsigned char charClass[] = {
+        /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
+/* 0x */   0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0,
+/* 1x */   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* 2x */   1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 0,
+/* 3x */   2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0,
+/* 4x */   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* 5x */   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* 6x */   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* 7x */   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* 8x */   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* 9x */   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* Ax */   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* Bx */   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* Cx */   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* Dx */   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* Ex */   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* Fx */   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+#define N_CHAR_CLASS 5
+
+/*
+** Given the current state number (0 thru 5), this array figures
+** the new state number given the character class.
+*/
+static const unsigned char stateMachine[] = {
+ /* Text,  Space, Digit, "-", "." */
+      1,      0,    2,    3,   1,      /* State 0: Beginning of word */
+      1,      0,    2,    1,   1,      /* State 1: Arbitrary text */
+      1,      0,    2,    1,   4,      /* State 2: Integer */
+      1,      0,    3,    1,   5,      /* State 3: Negative integer */
+      1,      0,    4,    1,   1,      /* State 4: Real number */
+      1,      0,    5,    1,   1,      /* State 5: Negative real num */
+};
+
+/* This routine does a comparison of two strings.  Case is used only
+** if useCase!=0.  Numbers compare in numerical order.
+*/
+static int privateStrCmp(const char *atext, const char *btext, int useCase){
+  register unsigned char *a, *b, *map, ca, cb;
+  int result;
+  register int cclass = 0;
+
+  a = (unsigned char *)atext;
+  b = (unsigned char *)btext;
+  if( useCase ){
+    do{
+      if( (ca= *a++)!=(cb= *b++) ) break;
+      cclass = stateMachine[cclass*N_CHAR_CLASS + charClass[ca]];
+    }while( ca!=0 );
+  }else{
+    map = UpperToLower;
+    do{
+      if( (ca=map[*a++])!=(cb=map[*b++]) ) break;
+      cclass = stateMachine[cclass*N_CHAR_CLASS + charClass[ca]];
+    }while( ca!=0 );
+  }
+  switch( cclass ){
+    case 0:
+    case 1: {
+      if( isdigit(ca) && isdigit(cb) ){
+        cclass = 2;
+      }
+      break;
+    }
+    default: {
+      break;
+    }
+  }
+  switch( cclass ){
+    case 2:
+    case 3: {
+      if( isdigit(ca) ){
+        if( isdigit(cb) ){
+          int acnt, bcnt;
+          acnt = bcnt = 0;
+          while( isdigit(*a++) ) acnt++;
+          while( isdigit(*b++) ) bcnt++;
+          result = acnt - bcnt;
+          if( result==0 ) result = ca-cb;
+        }else{
+          result = 1;
+        }
+      }else if( isdigit(cb) ){
+        result = -1;
+      }else if( ca=='.' ){
+        result = 1;
+      }else if( cb=='.' ){
+        result = -1;
+      }else{
+        result = ca - cb;
+        cclass = 2;
+      }
+      if( cclass==3 ) result = -result;
+      break;
+    }
+    case 0:
+    case 1:
+    case 4: {
+      result = ca - cb;
+      break;
+    }
+    case 5: {
+      result = cb - ca;
+    };
+  }
+  return result;
+}
+
+/* This comparison routine is what we use for comparison operations
+** in an SQL expression.  (Ex:  name<'Hello' or value<5).  Compare two
+** strings.  Use case only as a tie-breaker.  Numbers compare in
+** numerical order.
+*/
+int sqliteCompare(const char *atext, const char *btext){
+  int result;
+  result = privateStrCmp(atext, btext, 0);
+  if( result==0 ) result = privateStrCmp(atext, btext, 1);
+  return result;
+}
+
+/*
+** If you compile just this one file with the -DTEST_COMPARE=1 option,
+** it generates a program to test the comparisons routines.  
+*/
+#ifdef TEST_COMPARE
+#include <stdlib.h>
+#include <stdio.h>
+int sortCmp(const char **a, const char **b){
+  return sqliteCompare(*a, *b);
+}
+int main(int argc, char **argv){
+  int i, j, k, n;
+  static char *azStr[] = {
+     "abc", "aBc", "abcd", "aBcd", 
+     "123", "124", "1234", "-123", "-124", "-1234", 
+     "123.45", "123.456", "123.46", "-123.45", "-123.46", "-123.456", 
+     "x9", "x10", "x-9", "x-10", "X9", "X10",
+  };
+  n = sizeof(azStr)/sizeof(azStr[0]);
+  qsort(azStr, n, sizeof(azStr[0]), sortCmp);
+  for(i=0; i<n; i++){
+    printf("%s\n", azStr[i]);
+  }
+  printf("Sanity1...");
+  fflush(stdout);
+  for(i=0; i<n-1; i++){
+    char *a = azStr[i];
+    for(j=i+1; j<n; j++){
+      char *b = azStr[j];
+      if( sqliteCompare(a,b) != -sqliteCompare(b,a) ){
+        printf("Failed!  \"%s\" vs \"%s\"\n", a, b);
+        i = j = n;
+      }
+    }
+  }
+  if( i<n ){
+    printf(" OK\n");
+  }
+  return 0;
+}
+#endif
+
+/*
+** This routine is used for sorting.  Each key is a list one or more
+** null-terminated strings.  The list is terminated by two null in
+** a row.  For example, the following text is strings:
+**
+**            +one\000-two\000+three\000\000
+**
+** Both arguments will have the same number of strings.  This routine
+** returns negative, zero, or positive if the first argument is less
+** than, equal to, or greater than the first.  (Result is a-b).
+**
+** Every string begins with either a "+" or "-" character.  If the
+** character is "-" then the return value is negated.  This is done
+** to implement a sort in descending order.
+*/
+int sqliteSortCompare(const char *a, const char *b){
+  int len;
+  int res = 0;
+
+  while( res==0 && *a && *b ){
+    res = sqliteCompare(&a[1], &b[1]);
+    if( res==0 ){
+      len = strlen(a) + 1;
+      a += len;
+      b += len;
+    }
+  }
+  if( *a=='-' ) res = -res;
+  return res;
+}
diff --git a/src/vdbe.c b/src/vdbe.c
new file mode 100644 (file)
index 0000000..a93c237
--- /dev/null
@@ -0,0 +1,1973 @@
+/*
+** Copyright (c) 1999, 2000 D. Richard Hipp
+**
+** 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 library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*************************************************************************
+** The code in this file implements the Virtual Database Engine (VDBE)
+**
+** The SQL parser generates a program which is then executed by
+** the VDBE to do the work of the SQL statement.  VDBE programs are 
+** similar in form to assembly language.  The program consists of
+** a linear sequence of operations.  Each operation has an opcode 
+** and 3 operands.  Operands P1 and P2 are integers.  Operand P3 
+** is a null-terminated string.   The P2 operand must be non-negative.
+** Opcodes will typically ignore one or more operands.  Many opcodes
+** ignore all three operands.
+**
+** Computation results are stored on a stack.  Each entry on the
+** stack is either an integer or a null-terminated string.  An
+** inplicit conversion from one type to the other occurs as necessary.
+** 
+** Most of the code in this file is taken up by the sqliteVdbeExec()
+** function which does the work of interpreting a VDBE program.
+** But other routines are also provided to help in building up
+** a program instruction by instruction.
+**
+** $Id: vdbe.c,v 1.1 2000/05/29 14:26:02 drh Exp $
+*/
+#include "sqliteInt.h"
+
+/*
+** SQL is translated into a sequence of instructions to be
+** executed by a virtual machine.  Each instruction is an instance
+** of the following structure.
+*/
+typedef struct VdbeOp Op;
+
+/*
+** Every table that the virtual machine has open is represented by an
+** instance of the following structure.
+*/
+struct VdbeTable {
+  DbbeTable *pTable;    /* The table structure of the backend */
+  int index;            /* The next index to extract */
+};
+typedef struct VdbeTable VdbeTable;
+
+/*
+** A sorter builds a list of elements to be sorted.  Each element of
+** the list is an instance of the following structure.
+*/
+typedef struct Sorter Sorter;
+struct Sorter {
+  int nKey;           /* Number of bytes in the key */
+  char *zKey;         /* The key by which we will sort */
+  int nData;          /* Number of bytes in the data */
+  char *pData;        /* The data associated with this key */
+  Sorter *pNext;      /* Next in the list */
+};
+
+/* 
+** Number of buckets used for merge-sort.  
+*/
+#define NSORT 30
+
+/*
+** An instance of the virtual machine
+*/
+struct Vdbe {
+  Dbbe *pBe;          /* Opaque context structure used by DB backend */
+  FILE *trace;        /* Write an execution trace here, if not NULL */
+  int nOp;            /* Number of instructions in the program */
+  int nOpAlloc;       /* Number of slots allocated for aOp[] */
+  Op *aOp;            /* Space to hold the virtual machine's program */
+  int nLabel;         /* Number of labels used */
+  int nLabelAlloc;    /* Number of slots allocated in aLabel[] */
+  int *aLabel;        /* Space to hold the labels */
+  int tos;            /* Index of top of stack */
+  int nStackAlloc;    /* Size of the stack */
+  int *iStack;        /* Integer values of the stack */
+  char **zStack;      /* Text or binary values of the stack */
+  char **azColName;   /* Becomes the 4th parameter to callbacks */
+  int nTable;         /* Number of slots in aTab[] */
+  VdbeTable *aTab;    /* On element of this array for each open table */
+  int nList;          /* Number of slots in apList[] */
+  FILE **apList;      /* An open file for each list */
+  int nSort;          /* Number of slots in apSort[] */
+  Sorter **apSort;    /* An open sorter list */
+};
+
+/*
+** Create a new virtual database engine.
+*/
+Vdbe *sqliteVdbeCreate(Dbbe *pBe){
+  Vdbe *p;
+
+  p = sqliteMalloc( sizeof(Vdbe) );
+  p->pBe = pBe;
+  return p;
+}
+
+/*
+** Turn tracing on or off
+*/
+void sqliteVdbeTrace(Vdbe *p, FILE *trace){
+  p->trace = trace;
+}
+
+/*
+** Add a new instruction to the list of instructions current in the
+** VDBE.  Return the address of the new instruction.
+**
+** Parameters:
+**
+**    p               Pointer to the VDBE
+**
+**    op              The opcode for this instruction
+**
+**    p1, p2, p3      Three operands.
+**
+**    lbl             A symbolic label for this instruction.
+**
+** Symbolic labels are negative numbers that stand for the address
+** of instructions that have yet to be coded.  When the instruction
+** is coded, its real address is substituted in the p2 field of
+** prior and subsequent instructions that have the lbl value in
+** their p2 fields.
+*/
+int sqliteVdbeAddOp(Vdbe *p, int op, int p1, int p2, const char *p3, int lbl){
+  int i, j;
+
+  i = p->nOp;
+  p->nOp++;
+  if( i>=p->nOpAlloc ){
+    int oldSize = p->nOpAlloc;
+    p->nOpAlloc = p->nOpAlloc*2 + 10;
+    p->aOp = sqliteRealloc(p->aOp, p->nOpAlloc*sizeof(Op));
+    if( p->aOp==0 ){
+      p->nOp = 0;
+      p->nOpAlloc = 0;
+      return 0;
+    }
+    memset(&p->aOp[oldSize], 0, (p->nOpAlloc-oldSize)*sizeof(Op));
+  }
+  p->aOp[i].opcode = op;
+  p->aOp[i].p1 = p1;
+  if( p2<0 && (-1-p2)<p->nLabel && p->aLabel[-1-p2]>=0 ){
+    p2 = p->aLabel[-1-p2];
+  }
+  p->aOp[i].p2 = p2;
+  if( p3 && p3[0] ){
+    sqliteSetString(&p->aOp[i].p3, p3, 0);
+  }else{
+    p->aOp[i].p3 = 0;
+  }
+  if( lbl<0 && (-lbl)<=p->nLabel ){
+    p->aLabel[-1-lbl] = i;
+    for(j=0; j<i; j++){
+      if( p->aOp[j].p2==lbl ) p->aOp[j].p2 = i;
+    }
+  }
+  return i;
+}
+
+/*
+** Resolve label "x" to be the address of the next instruction to
+** be inserted.
+*/
+void sqliteVdbeResolveLabel(Vdbe *p, int x){
+  int j;
+  if( x<0 && (-x)<=p->nLabel ){
+    p->aLabel[-1-x] = p->nOp;
+    for(j=0; j<p->nOp; j++){
+      if( p->aOp[j].p2==x ) p->aOp[j].p2 = p->nOp;
+    }
+  }
+}
+
+/*
+** Return the address of the next instruction to be inserted.
+*/
+int sqliteVdbeCurrentAddr(Vdbe *p){
+  return p->nOp;
+}
+
+/*
+** Add a whole list of operations to the operation stack.  Return the
+** address of the first operation added.
+*/
+int sqliteVdbeAddOpList(Vdbe *p, int nOp, VdbeOp const *aOp){
+  int addr;
+  if( p->nOp + nOp >= p->nOpAlloc ){
+    int oldSize = p->nOpAlloc;
+    p->nOpAlloc = p->nOpAlloc*2 + nOp + 10;
+    p->aOp = sqliteRealloc(p->aOp, p->nOpAlloc*sizeof(Op));
+    if( p->aOp==0 ){
+      p->nOp = 0;
+      p->nOpAlloc = 0;
+      return 0;
+    }
+    memset(&p->aOp[oldSize], 0, (p->nOpAlloc-oldSize)*sizeof(Op));
+  }
+  addr = p->nOp;
+  if( nOp>0 ){
+    int i;
+    for(i=0; i<nOp; i++){
+      int p2 = aOp[i].p2;
+      if( p2<0 ) p2 = addr + ADDR(p2);
+      sqliteVdbeAddOp(p, aOp[i].opcode, aOp[i].p1, p2, aOp[i].p3, 0);
+    }
+  }
+  return addr;
+}
+
+/*
+** Change the value of the P3 operand for a specific instruction.
+** This routine is useful when a large program is loaded from a
+** static array using sqliteVdbeAddOpList but we want to make a
+** few minor changes to the program.
+*/
+void sqliteVdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
+  if( p && addr>=0 && p->nOp>addr && zP3 ){
+    sqliteSetNString(&p->aOp[addr].p3, zP3, n, 0);
+  }
+}
+
+/*
+** If the P3 operand to the specified instruction appears
+** to be a quoted string token, then this procedure removes 
+** the quotes.
+**
+** The quoting operator can be either a grave ascent (ASCII 0x27)
+** or a double quote character (ASCII 0x22).  Two quotes in a row
+** resolve to be a single actual quote character within the string.
+*/
+void sqliteVdbeDequoteP3(Vdbe *p, int addr){
+  int quote;
+  int i, j;
+  char *z;
+  if( addr<0 || addr>=p->nOp ) return;
+  z = p->aOp[addr].p3;
+  quote = z[0];
+  if( quote!='\'' && quote!='"' ) return;
+  for(i=1, j=0; z[i]; i++){
+    if( z[i]==quote ){
+      if( z[i+1]==quote ){
+        z[j++] = quote;
+        i++;
+      }else{
+        z[j++] = 0;
+        break;
+      }
+    }else{
+      z[j++] = z[i];
+    }
+  }
+}
+
+/*
+** Create a new symbolic label for an instruction that has yet to be
+** coded.  The symbolic label is really just a negative number.  The
+** label can be used as the P2 value of an operation.  Later, when
+** the label is resolved to a specific address, the VDBE will scan
+** through its operation list and change all values of P2 which match
+** the label into the resolved address.
+**
+** The VDBE knows that a P2 value is a label because labels are
+** always negative and P2 values are suppose to be non-negative.
+** Hence, a negative P2 value is a label that has yet to be resolved.
+*/
+int sqliteVdbeMakeLabel(Vdbe *p){
+  int i;
+  i = p->nLabel++;
+  if( i>=p->nLabelAlloc ){
+    p->nLabelAlloc = p->nLabelAlloc*2 + 10;
+    p->aLabel = sqliteRealloc( p->aLabel, p->nLabelAlloc*sizeof(int));
+  }
+  if( p->aLabel==0 ){
+    p->nLabel = 0;
+    p->nLabelAlloc = 0;
+    return 0;
+  }
+  p->aLabel[i] = -1;
+  return -1-i;
+}
+
+/*
+** Pop the stack N times.  Free any memory associated with the
+** popped stack elements.
+*/
+static void PopStack(Vdbe *p, int N){
+  if( p->zStack==0 ) return;
+  while( p->tos>=0 && N-->0 ){
+    int i = p->tos--;
+    sqliteFree(p->zStack[i]);
+    p->zStack[i] = 0;
+  }    
+}
+
+/*
+** Clean up the VM after execution.
+**
+** This routine will automatically close any tables, list, and/or
+** sorters that were left open.
+*/
+static void Cleanup(Vdbe *p){
+  int i;
+  PopStack(p, p->tos+1);
+  sqliteFree(p->azColName);
+  p->azColName = 0;
+  for(i=0; i<p->nTable; i++){
+    if( p->aTab[i].pTable ){
+      sqliteDbbeCloseTable(p->aTab[i].pTable);
+      p->aTab[i].pTable = 0;
+    }
+  }
+  sqliteFree(p->aTab);
+  p->aTab = 0;
+  p->nTable = 0;
+  for(i=0; i<p->nList; i++){
+    if( p->apList[i] ){
+      sqliteDbbeCloseTempFile(p->pBe, p->apList[i]);
+      p->apList[i] = 0;
+    }
+  }
+  sqliteFree(p->apList);
+  p->apList = 0;
+  p->nList = 0;
+  for(i=0; i<p->nSort; i++){
+    Sorter *pSorter;
+    while( (pSorter = p->apSort[i])!=0 ){
+      p->apSort[i] = pSorter->pNext;
+      sqliteFree(pSorter->zKey);
+      sqliteFree(pSorter->pData);
+      sqliteFree(pSorter);
+    }
+  }
+  sqliteFree(p->apSort);
+  p->apSort = 0;
+  p->nSort = 0;
+}
+
+/*
+** Delete an entire VDBE.
+*/
+void sqliteVdbeDelete(Vdbe *p){
+  int i;
+  if( p==0 ) return;
+  Cleanup(p);
+  if( p->nOpAlloc==0 ){
+    p->aOp = 0;
+    p->nOp = 0;
+  }
+  for(i=0; i<p->nOp; i++){
+    sqliteFree(p->aOp[i].p3);
+  }
+  sqliteFree(p->aOp);
+  sqliteFree(p->aLabel);
+  sqliteFree(p->iStack);
+  sqliteFree(p->zStack);
+  sqliteFree(p);
+}
+
+/*
+** A translation from opcode numbers to opcode names.  Used for testing
+** and debugging only.
+**
+** If any of the numeric OP_ values for opcodes defined in sqliteVdbe.h
+** change, be sure to change this array to match.  You can use the
+** "opNames.awk" awk script which is part of the source tree to regenerate
+** this array, then copy and paste it into this file, if you want.
+*/
+static char *zOpName[] = { 0,
+  "Open",           "Close",          "Destroy",        "Fetch",
+  "New",            "Put",            "Delete",         "Field",
+  "Key",            "Rewind",         "Next",           "ResetIdx",
+  "NextIdx",        "PutIdx",         "DeleteIdx",      "ListOpen",
+  "ListWrite",      "ListRewind",     "ListRead",       "ListClose",
+  "SortOpen",       "SortPut",        "SortMakeRec",    "SortMakeKey",
+  "Sort",           "SortNext",       "SortKey",        "SortCallback",
+  "SortClose",      "MakeRecord",     "MakeKey",        "Goto",
+  "If",             "Halt",           "ColumnCount",    "ColumnName",
+  "Callback",       "Integer",        "String",         "Pop",
+  "Dup",            "Pull",           "Add",            "AddImm",
+  "Subtract",       "Multiply",       "Divide",         "Min",
+  "Max",            "Eq",             "Ne",             "Lt",
+  "Le",             "Gt",             "Ge",             "IsNull",
+  "NotNull",        "Negative",       "And",            "Or",
+  "Not",            "Concat",         "Noop",         
+};
+
+/*
+** Given the name of an opcode, return its number.  Return 0 if
+** there is no match.
+**
+** This routine is used for testing and debugging.
+*/
+int sqliteVdbeOpcode(const char *zName){
+  int i;
+  for(i=1; i<=OP_MAX; i++){
+    if( sqliteStrICmp(zName, zOpName[i])==0 ) return i;
+  }
+  return 0;
+}
+
+/*
+** Give a listing of the program in the virtual machine.
+**
+** The interface is the same as sqliteVdbeExec().  But instead of
+** running the code, it invokes the callback once for each instruction.
+** This feature is used to implement "EXPLAIN".
+*/
+int sqliteVdbeList(
+  Vdbe *p,                   /* The VDBE */
+  sqlite_callback xCallback, /* The callback */
+  void *pArg,                /* 1st argument to callback */
+  char **pzErrMsg            /* Error msg written here */
+){
+  int i, rc;
+  char *azField[6];
+  char zAddr[20];
+  char zP1[20];
+  char zP2[20];
+  static char *azColumnNames[] = {
+     "addr", "opcode", "p1", "p2", "p3", 0
+  };
+
+  if( xCallback==0 ) return 0;
+  azField[0] = zAddr;
+  azField[2] = zP1;
+  azField[3] = zP2;
+  azField[5] = 0;
+  rc = 0;
+  if( pzErrMsg ){ *pzErrMsg = 0; }
+  for(i=0; rc==0 && i<p->nOp; i++){
+    sprintf(zAddr,"%d",i);
+    sprintf(zP1,"%d", p->aOp[i].p1);
+    sprintf(zP2,"%d", p->aOp[i].p2);
+    azField[4] = p->aOp[i].p3;
+    if( azField[4]==0 ) azField[4] = "";
+    azField[1] = zOpName[p->aOp[i].opcode];
+    rc = xCallback(pArg, 5, azField, azColumnNames);
+  }
+  return rc;
+}
+
+/*
+** Make sure space has been allocated to hold at least N
+** stack elements.  Allocate additional stack space if
+** necessary.
+**
+** Return 0 on success and non-zero if there are memory
+** allocation errors.
+*/
+static int NeedStack(Vdbe *p, int N){
+  int oldAlloc;
+  int i;
+  if( N>=p->nStackAlloc ){
+    oldAlloc = p->nStackAlloc;
+    p->nStackAlloc = N + 20;
+    p->iStack = sqliteRealloc(p->iStack, p->nStackAlloc*sizeof(int));
+    p->zStack = sqliteRealloc(p->zStack, p->nStackAlloc*sizeof(char*));
+    if( p->iStack==0 || p->zStack==0 ){
+      sqliteFree(p->iStack);
+      sqliteFree(p->zStack);
+      p->iStack = 0;
+      p->zStack = 0;
+      p->nStackAlloc = 0;
+      return 1;
+    }
+    for(i=oldAlloc; i<p->nStackAlloc; i++){
+      p->zStack[i] = 0;
+    }
+  }
+  return 0;
+}
+
+/*
+** Convert the given stack entity into a string if it isn't one
+** already.  Return non-zero if we run out of memory.
+*/
+static int Stringify(Vdbe *p, int i){
+  if( p->zStack[i]==0 ){
+    char zBuf[30];
+    sprintf(zBuf,"%d",p->iStack[i]);
+    sqliteSetString(&p->zStack[i], zBuf, 0);
+    if( p->zStack[i]==0 ) return 1;
+    p->iStack[i] = strlen(p->zStack[i])+1;
+  }
+  return 0;
+}
+
+/*
+** Convert the given stack entity into a integer if it isn't one
+** already.
+*/
+static int Integerify(Vdbe *p, int i){
+  if( p->zStack[i]!=0 ){
+    p->iStack[i] = atoi(p->zStack[i]);
+    sqliteFree(p->zStack[i]);
+    p->zStack[i] = 0;
+  }
+  return p->iStack[i];
+}
+
+/*
+** The parameters are pointers to the head of two sorted lists
+** of Sorter structures.  Merge these two lists together and return
+** a single sorted list.  This routine forms the core of the merge-sort
+** algorithm.
+**
+** In the case of a tie, left sorts in front of right.
+*/
+static Sorter *Merge(Sorter *pLeft, Sorter *pRight){
+  Sorter sHead;
+  Sorter *pTail;
+  pTail = &sHead;
+  pTail->pNext = 0;
+  while( pLeft && pRight ){
+    int c = sqliteSortCompare(pLeft->zKey, pRight->zKey);
+    if( c<=0 ){
+      pTail->pNext = pLeft;
+      pLeft = pLeft->pNext;
+    }else{
+      pTail->pNext = pRight;
+      pRight = pRight->pNext;
+    }
+    pTail = pTail->pNext;
+  }
+  if( pLeft ){
+    pTail->pNext = pLeft;
+  }else if( pRight ){
+    pTail->pNext = pRight;
+  }
+  return sHead.pNext;
+}
+
+
+/*
+** Execute the program in the VDBE.
+**
+** If an error occurs, an error message is written to memory obtained
+** from sqliteMalloc() and *pzErrMsg is made to point to that memory.
+** The return parameter is the number of errors.
+**
+** If the callback every returns non-zero, then the program exits
+** immediately.  No error message is written but the return value
+** from the callback because the return value of this routine.
+*/
+int sqliteVdbeExec(
+  Vdbe *p,                   /* The VDBE */
+  sqlite_callback xCallback, /* The callback */
+  void *pArg,                /* 1st argument to callback */
+  char **pzErrMsg            /* Error msg written here */
+){
+  int pc;                    /* The program counter */
+  Op *pOp;                   /* Current operation */
+  int rc;                    /* Value to return */
+  char zBuf[100];            /* Space to sprintf() and integer */
+
+  p->tos = -1;
+  rc = 0;
+  if( pzErrMsg ){ *pzErrMsg = 0; }
+  for(pc=0; rc==0 && pc<p->nOp && pc>=0; pc++){
+    pOp = &p->aOp[pc];
+    if( p->trace ){
+      fprintf(p->trace,"%4d %-12s %4d %4d %s\n",
+        pc, zOpName[pOp->opcode], pOp->p1, pOp->p2,
+           pOp->p3 ? pOp->p3 : "");
+    }
+    switch( pOp->opcode ){
+      /* Opcode:  Goto P2 * *
+      **
+      ** An unconditional jump to address P2.
+      ** The next instruction executed will be 
+      ** the one at index P2 from the beginning of
+      ** the program.
+      */
+      case OP_Goto: {
+        pc = pOp->p2;
+        if( pc<0 || pc>p->nOp ){
+          sqliteSetString(pzErrMsg, "jump destination out of range", 0);
+          rc = 1;
+        }
+        pc--;
+        break;
+      }
+
+      /* Opcode:  Halt * * *
+      **
+      ** Exit immediately.  All open DBs, Lists, Sorts, etc are closed
+      ** automatically.
+      */
+      case OP_Halt: {
+        pc = p->nOp-1;
+        break;
+      }
+
+      /* Opcode: Integer P1 * *
+      **
+      ** The integer value P1 is pushed onto the stack.
+      */
+      case OP_Integer: {
+        int i = ++p->tos;
+        if( NeedStack(p, p->tos) ) goto no_mem;
+        p->iStack[i] = pOp->p1;
+        p->zStack[i] = 0;
+        break;
+      }
+
+      /* Opcode: String * * P3
+      **
+      ** The string value P3 is pushed onto the stack.
+      */
+      case OP_String: {
+        int i = ++p->tos;
+        char *z;
+        if( NeedStack(p, p->tos) ) goto no_mem;
+        z = pOp->p3;
+        if( z==0 ) z = "";
+        p->iStack[i] = strlen(z) + 1;
+        sqliteSetString(&p->zStack[i], z, 0);
+        break;
+      }
+
+      /* Opcode: Pop P1 * *
+      **
+      ** P1 elements are popped off of the top of stack and discarded.
+      */
+      case OP_Pop: {
+        PopStack(p, pOp->p1);
+        break;
+      }
+
+      /* Opcode: Dup P1 * *
+      **
+      ** A copy of the P1-th element of the stack 
+      ** is made and pushed onto the top of the stack.
+      ** The top of the stack is element 0.  So the
+      ** instruction "Dup 0 0 0" will make a copy of the
+      ** top of the stack.
+      */
+      case OP_Dup: {
+        int i = p->tos - pOp->p1;
+        int j = ++p->tos;
+        if( i<0 ) goto not_enough_stack;
+        if( NeedStack(p, p->tos) ) goto no_mem;
+        p->iStack[j] = p->iStack[i];
+        if( p->zStack[i] ){
+          p->zStack[j] = sqliteMalloc( p->iStack[j] );
+          if( p->zStack[j] ) memcpy(p->zStack[j], p->zStack[i], p->iStack[j]);
+        }else{
+          p->zStack[j] = 0;
+        }
+        break;
+      }
+
+      /* Opcode: Pull P1 * *
+      **
+      ** The P1-th element is removed its current location on 
+      ** the stack and pushed back on top of the stack.  The
+      ** top of the stack is element 0, so "Pull 0 0 0" is
+      ** a no-op.
+      */
+      case OP_Pull: {
+        int from = p->tos - pOp->p1;
+        int to = p->tos;
+        int i;
+        int ti;
+        char *tz;
+        if( from<0 ) goto not_enough_stack;
+        ti = p->iStack[from];
+        tz = p->zStack[from];
+        for(i=from; i<to; i++){
+          p->iStack[i] = p->iStack[i+1];
+          p->zStack[i] = p->zStack[i+1];
+        }
+        p->iStack[to] = ti;
+        p->zStack[to] = tz;
+        break;
+      }
+
+      /* Opcode: ColumnCount P1 * *
+      **
+      ** Specify the number of column values that will appear in the
+      ** array passed as the 4th parameter to the callback.  No checking
+      ** is done.  If this value is wrong, a coredump can result.
+      */
+      case OP_ColumnCount: {
+        p->azColName = sqliteRealloc(p->azColName, (pOp->p1+1)*sizeof(char*));
+        if( p->azColName==0 ) goto no_mem;
+        p->azColName[pOp->p1] = 0;
+        break;
+      }
+
+      /* Opcode: ColumnName P1 * P3
+      **
+      ** P3 becomes the P1-th column name (first is 0).  An array of pointers
+      ** to all column names is passed as the 4th parameter to the callback.
+      ** The ColumnCount opcode must be executed first to allocate space to
+      ** hold the column names.  Failure to do this will likely result in
+      ** a coredump.
+      */
+      case OP_ColumnName: {
+        p->azColName[pOp->p1] = pOp->p3 ? pOp->p3 : "";
+        break;
+      }
+
+      /* Opcode: Callback P1 * *
+      **
+      ** Pop P1 values off the stack and form them into an array.  Then
+      ** invoke the callback function using the newly formed array as the
+      ** 3rd parameter.
+      */
+      case OP_Callback: {
+        int i = p->tos - pOp->p1 + 1;
+        int j;
+        if( i<0 ) goto not_enough_stack;
+        if( NeedStack(p, p->tos+2) ) goto no_mem;
+        for(j=i; j<=p->tos; j++){
+          if( Stringify(p, j) ) goto no_mem;
+        }
+        p->zStack[p->tos+1] = 0;
+        rc = xCallback(pArg, pOp->p1, &p->zStack[i], p->azColName);
+        PopStack(p, pOp->p1);
+        break;
+      }
+
+      /* Opcode: Concat * * *
+      **
+      ** Pop two elements from the stack.  Append the first (what used
+      ** to be the top of stack) to the second (the next on stack) to 
+      ** form a new string.  Push the new string back onto the stack.
+      */
+      case OP_Concat: {
+        int tos = p->tos;
+        int nos = tos - 1;
+        char *z;
+        if( nos<0 ) goto not_enough_stack;
+        Stringify(p, tos);
+        Stringify(p, nos);
+        z = 0;
+        sqliteSetString(&z, p->zStack[nos], p->zStack[tos], 0);
+        PopStack(p, 1);
+        sqliteFree(p->zStack[nos]);
+        p->zStack[nos] = z;
+        p->iStack[nos] = strlen(p->zStack[nos])+1;
+        break;
+      }
+
+      /* Opcode: Add * * *
+      **
+      ** Pop the top two elements from the stack, add them together,
+      ** and push the result back onto the stack.  If either element
+      ** is a string then it is converted to a double using the atof()
+      ** function before the addition.
+      */
+      /* Opcode: Multiply * * *
+      **
+      ** Pop the top two elements from the stack, multiply them together,
+      ** and push the result back onto the stack.  If either element
+      ** is a string then it is converted to a double using the atof()
+      ** function before the multiplication.
+      */
+      /* Opcode: Subtract * * *
+      **
+      ** Pop the top two elements from the stack, subtract the
+      ** first (what was on top of the stack) from the second (the
+      ** next on stack)
+      ** and push the result back onto the stack.  If either element
+      ** is a string then it is converted to a double using the atof()
+      ** function before the subtraction.
+      */
+      /* Opcode: Divide * * *
+      **
+      ** Pop the top two elements from the stack, divide the
+      ** first (what was on top of the stack) from the second (the
+      ** next on stack)
+      ** and push the result back onto the stack.  If either element
+      ** is a string then it is converted to a double using the atof()
+      ** function before the division.  Division by zero causes the
+      ** program to abort with an error.
+      */
+      case OP_Add:
+      case OP_Subtract:
+      case OP_Multiply:
+      case OP_Divide: {
+        int tos = p->tos;
+        int nos = tos - 1;
+        if( nos<0 ) goto not_enough_stack;
+        if( p->zStack[tos]==0 && p->zStack[nos]==0 ){
+          int a, b;
+          a = p->iStack[tos];
+          b = p->iStack[nos];
+          switch( pOp->opcode ){
+            case OP_Add:         b += a;       break;
+            case OP_Subtract:    b -= a;       break;
+            case OP_Multiply:    b *= a;       break;
+            default: {
+              if( a==0 ){ 
+                sqliteSetString(pzErrMsg, "division by zero", 0);
+                rc = 1;
+                goto cleanup;
+              }
+              b /= a;
+              break;
+            }
+          }
+          PopStack(p, 1);
+          p->iStack[nos] = b;
+        }else{
+          double a, b;
+          Stringify(p, tos);
+          Stringify(p, nos);
+          a = atof(p->zStack[tos]);
+          b = atof(p->zStack[nos]);
+          switch( pOp->opcode ){
+            case OP_Add:         b += a;       break;
+            case OP_Subtract:    b -= a;       break;
+            case OP_Multiply:    b *= a;       break;
+            default: {
+              if( a==0.0 ){ 
+                sqliteSetString(pzErrMsg, "division by zero", 0);
+                rc = 1;
+                goto cleanup;
+              }
+              b /= a;
+              break;
+            }
+          }
+          sprintf(zBuf,"%g",b);
+          PopStack(p, 1);
+          sqliteSetString(&p->zStack[nos], zBuf, 0);
+          if( p->zStack[nos]==0 ) goto no_mem;
+          p->iStack[nos] = strlen(p->zStack[nos]) + 1;
+        }
+        break;
+      }
+
+      /* Opcode: Max * * *
+      **
+      ** Pop the top two elements from the stack then push back the
+      ** largest of the two.
+      */
+      case OP_Max: {
+        int tos = p->tos;
+        int nos = tos - 1;
+        if( nos<0 ) goto not_enough_stack;
+        if( p->zStack[tos]==0 && p->zStack[nos]==0 ){
+          if( p->iStack[nos]<p->iStack[tos] ){
+            p->iStack[nos] = p->iStack[tos];
+          }
+        }else{
+          Stringify(p, tos);
+          Stringify(p, nos);
+          if( sqliteCompare(p->zStack[nos], p->zStack[tos])<0 ){
+            sqliteFree(p->zStack[nos]);
+            p->zStack[nos] = p->zStack[tos];
+            p->iStack[nos] = p->iStack[tos];
+          }
+        }
+        p->tos--;
+        break;
+      }
+
+      /* Opcode: Min * * *
+      **
+      ** Pop the top two elements from the stack then push back the
+      ** smaller of the two.
+      */
+      case OP_Min: {
+        int tos = p->tos;
+        int nos = tos - 1;
+        if( nos<0 ) goto not_enough_stack;
+        if( p->zStack[tos]==0 && p->zStack[nos]==0 ){
+          if( p->iStack[nos]>p->iStack[tos] ){
+            p->iStack[nos] = p->iStack[tos];
+          }
+        }else{
+          Stringify(p, tos);
+          Stringify(p, nos);
+          if( sqliteCompare(p->zStack[nos], p->zStack[tos])>0 ){
+            sqliteFree(p->zStack[nos]);
+            p->zStack[nos] = p->zStack[tos];
+            p->iStack[nos] = p->iStack[tos];
+          }
+        }
+        p->tos--;
+        break;
+      }
+
+      /* Opcode: AddImm  P1 * *
+      ** 
+      ** Add the value P1 to whatever is on top of the stack.
+      */
+      case OP_AddImm: {
+        int tos = p->tos;
+        if( tos<0 ) goto not_enough_stack;
+        Integerify(p, tos);
+        p->iStack[tos] += pOp->p1;
+        break;
+      }
+
+      /* Opcode: Eq * P2 *
+      **
+      ** Pop the top two elements from the stack.  If they are equal, then
+      ** jump to instruction P2.  Otherwise, continue to the next instruction.
+      */
+      /* Opcode: Ne * P2 *
+      **
+      ** Pop the top two elements from the stack.  If they are not equal, then
+      ** jump to instruction P2.  Otherwise, continue to the next instruction.
+      */
+      /* Opcode: Lt * P2 *
+      **
+      ** Pop the top two elements from the stack.  If second element (the
+      ** next on stack) is less than the first (the top of stack), then
+      ** jump to instruction P2.  Otherwise, continue to the next instruction.
+      ** In other words, jump if NOS<TOS.
+      */
+      /* Opcode: Le * P2 *
+      **
+      ** Pop the top two elements from the stack.  If second element (the
+      ** next on stack) is less than or equal to the first (the top of stack),
+      ** then jump to instruction P2. In other words, jump if NOS<=TOS.
+      */
+      /* Opcode: Gt * P2 *
+      **
+      ** Pop the top two elements from the stack.  If second element (the
+      ** next on stack) is greater than the first (the top of stack),
+      ** then jump to instruction P2. In other words, jump if NOS>TOS.
+      */
+      /* Opcode: Ge * P2 *
+      **
+      ** Pop the top two elements from the stack.  If second element (the next
+      ** on stack) is greater than or equal to the first (the top of stack),
+      ** then jump to instruction P2. In other words, jump if NOS>=TOS.
+      */
+      case OP_Eq:
+      case OP_Ne:
+      case OP_Lt:
+      case OP_Le:
+      case OP_Gt:
+      case OP_Ge: {
+        int tos = p->tos;
+        int nos = tos - 1;
+        int c;
+        if( nos<0 ) goto not_enough_stack;
+        if( p->zStack[tos]==0 && p->zStack[nos]==0 ){
+          int a, b;
+          a = p->iStack[tos];
+          b = p->iStack[nos];
+          switch( pOp->opcode ){
+            case OP_Eq:    c = b==a;     break;
+            case OP_Ne:    c = b!=a;     break;
+            case OP_Lt:    c = b<a;      break;
+            case OP_Le:    c = b<=a;     break;
+            case OP_Gt:    c = b>a;      break;
+            default:       c = b>=a;     break;
+          }
+        }else{
+          Stringify(p, tos);
+          Stringify(p, nos);
+          c = sqliteCompare(p->zStack[nos], p->zStack[tos]);
+          switch( pOp->opcode ){
+            case OP_Eq:    c = c==0;     break;
+            case OP_Ne:    c = c!=0;     break;
+            case OP_Lt:    c = c<0;      break;
+            case OP_Le:    c = c<=0;     break;
+            case OP_Gt:    c = c>0;      break;
+            default:       c = c>=0;     break;
+          }
+        }
+        PopStack(p, 2);
+        if( c ) pc = pOp->p2-1;
+        break;
+      }
+
+      /* Opcode: And * * *
+      **
+      ** Pop two values off the stack.  Take the logical AND of the
+      ** two values and push the resulting boolean value back onto the
+      ** stack.  Integers are considered false if zero and true otherwise.
+      ** Strings are considered false if their length is zero and true
+      ** otherwise.
+      */
+      /* Opcode: Or * * *
+      **
+      ** Pop two values off the stack.  Take the logical OR of the
+      ** two values and push the resulting boolean value back onto the
+      ** stack.  Integers are considered false if zero and true otherwise.
+      ** Strings are considered false if their length is zero and true
+      ** otherwise.
+      */
+      case OP_And:
+      case OP_Or: {
+        int tos = p->tos;
+        int nos = tos - 1;
+        int x, y, c;
+        if( nos<0 ) goto not_enough_stack;
+        x = p->zStack[nos] ? p->zStack[nos][0] : p->iStack[nos];
+        y = p->zStack[tos] ? p->zStack[tos][0] : p->iStack[tos];
+        if( pOp->opcode==OP_And ){
+          c = x && y;
+        }else{
+          c = x || y;
+        }
+        PopStack(p, 2);
+        p->tos++;
+        p->iStack[nos] = c;
+        break;
+      }
+
+      /* Opcode: Negative * * *
+      **
+      ** Treat the top of the stack as a numeric quantity.  Replace it
+      ** with its additive inverse.  If the top of stack is a string,
+      ** then it is converted into a number using atof().
+      */
+      case OP_Negative: {
+        int tos;
+        if( (tos = p->tos)<0 ) goto not_enough_stack;
+        if( p->zStack[tos] ){
+          double r = atof(p->zStack[tos]);
+          sprintf(zBuf, "%g", -r);
+          sqliteSetString(&p->zStack[tos], zBuf, 0);
+          p->iStack[tos] = strlen(zBuf) + 1;
+        }else{
+          p->iStack[tos] = -p->iStack[tos];
+        }
+        break;
+      }
+
+      /* Opcode: Not * * *
+      **
+      ** Treat the top of the stack as a boolean value.  Replace it
+      ** with its complement.  Integers are false if zero and true
+      ** otherwise.  Strings are false if zero-length and true otherwise.
+      */
+      case OP_Not: {
+        int c;
+        if( p->tos<0 ) goto not_enough_stack;
+        c = p->zStack[p->tos] ? p->zStack[p->tos][0] : p->iStack[p->tos];
+        PopStack(p, 1);
+        p->tos++;
+        p->iStack[p->tos] = !c;
+        break;
+      }
+
+      /* Opcode: Noop * * *
+      **
+      ** Do nothing.  This instruction is often useful as a jump
+      ** destination.
+      */
+      case OP_Noop: {
+        break;
+      }
+
+      /* Opcode: If * P2 *
+      **
+      ** Pop a single boolean from the stack.  If the boolean popped is
+      ** true, then jump to p2.  Otherwise continue to the next instruction.
+      ** An integer is false if zero and true otherwise.  A string is
+      ** false if it has zero length and true otherwise.
+      */
+      case OP_If: {
+        int c;
+        if( p->tos<0 ) goto not_enough_stack;
+        c = p->zStack[p->tos] ? p->zStack[p->tos][0] : p->iStack[p->tos];
+        PopStack(p, 1);
+        if( c ) pc = pOp->p2-1;
+        break;
+      }
+
+      /* Opcode: IsNull * P2 *
+      **
+      ** Pop a single value from the stack.  If the value popped is the
+      ** empty string, then jump to p2.  Otherwise continue to the next 
+      ** instruction.
+      */
+      case OP_IsNull: {
+        int c;
+        if( p->tos<0 ) goto not_enough_stack;
+        c = p->zStack[p->tos]!=0 && p->zStack[p->tos][0]==0;
+        PopStack(p, 1);
+        if( c ) pc = pOp->p2-1;
+        break;
+      }
+
+      /* Opcode: NotNull * P2 *
+      **
+      ** Pop a single value from the stack.  If the value popped is not an
+      ** empty string, then jump to p2.  Otherwise continue to the next 
+      ** instruction.
+      */
+      case OP_NotNull: {
+        int c;
+        if( p->tos<0 ) goto not_enough_stack;
+        c = p->zStack[p->tos]==0 || p->zStack[p->tos][0]!=0;
+        PopStack(p, 1);
+        if( c ) pc = pOp->p2-1;
+        break;
+      }
+
+      /* Opcode: MakeRecord P1 * *
+      **
+      ** Convert the top P1 entries of the stack into a single entry
+      ** suitable for use as a data record in the database.  To do this
+      ** each entry is converted to a string and all the strings are
+      ** concatenated.  The null-terminators are preserved by the concatation
+      ** and serve as a boundry marker between fields.  The lowest entry
+      ** on the stack is the first in the concatenation and the top of
+      ** the stack is the last.  After all fields are concatenated, an
+      ** index header is added.  The index header consists of P1 integers
+      ** which hold the offset of the beginning of each field from the
+      ** beginning of the completed record including the header.
+      */
+      case OP_MakeRecord: {
+        char *zNewRecord;
+        int nByte;
+        int nField;
+        int i, j;
+        int addr;
+
+        nField = pOp->p1;
+        if( p->tos+1<nField ) goto not_enough_stack;
+        nByte = 0;
+        for(i=p->tos-nField+1; i<=p->tos; i++){
+          if( Stringify(p, i) ) goto no_mem;
+          nByte += p->iStack[i];
+        }
+        nByte += sizeof(int)*nField;
+        zNewRecord = sqliteMalloc( nByte );
+        if( zNewRecord==0 ) goto no_mem;
+        j = 0;
+        addr = sizeof(int)*nField;
+        for(i=p->tos-nField+1; i<p->tos; i++){
+          memcpy(&zNewRecord[j], (char*)&addr, sizeof(int));
+          addr += p->iStack[i];
+          j += sizeof(int);
+        }
+        memcpy(&zNewRecord[j], (char*)&addr, sizeof(int));
+        j += sizeof(int);
+        for(i=p->tos-nField+1; i<=p->tos; i++){
+          memcpy(&zNewRecord[j], p->zStack[i], p->iStack[i]);
+          j += p->iStack[i];
+        }
+        PopStack(p, nField);
+        NeedStack(p, p->tos+1);
+        p->tos++;
+        p->iStack[p->tos] = nByte;
+        p->zStack[p->tos] = zNewRecord;
+        break;
+      }
+
+      /* Opcode: MakeKey P1 * *
+      **
+      ** Convert the top P1 entries of the stack into a single entry suitable
+      ** for use as the key in an index or a sort.  The top P1 records are
+      ** concatenated with a tab character (ASCII 0x09) used as a record
+      ** separator.  The entire concatenation is null-terminated.  The
+      ** lowest entry in the stack is the first field and the top of the
+      ** stack becomes the last.
+      **
+      ** See also the SortMakeKey opcode.
+      */
+      case OP_MakeKey: {
+        char *zNewKey;
+        int nByte;
+        int nField;
+        int i, j;
+
+        nField = pOp->p1;
+        if( p->tos+1<nField ) goto not_enough_stack;
+        nByte = 0;
+        for(i=p->tos-nField+1; i<=p->tos; i++){
+          if( Stringify(p, i) ) goto no_mem;
+          nByte += p->iStack[i]+1;
+        }
+        zNewKey = sqliteMalloc( nByte );
+        if( zNewKey==0 ) goto no_mem;
+        j = 0;
+        for(i=p->tos-nField+1; i<=p->tos; i++){
+          memcpy(&zNewKey[j], p->zStack[i], p->iStack[i]-1);
+          j += p->iStack[i]-1;
+          if( i<p->tos ) zNewKey[j++] = '\t';
+        }
+        zNewKey[j] = 0;
+        PopStack(p, nField);
+        NeedStack(p, p->tos+1);
+        p->tos++;
+        p->iStack[p->tos] = nByte;
+        p->zStack[p->tos] = zNewKey;
+        break;
+      }
+
+      /*  Open P1 P3 P2
+      **
+      ** Open a new database table named P3.  Give it an identifier P1.
+      ** Open readonly if P2==0 and for reading and writing if P2!=0.
+      ** The table is created if it does not already exist and P2!=0.
+      ** If there is already another table opened on P1, then the old
+      ** table is closed first.  All tables are automatically closed when
+      ** the VDBE finishes execution.  The P1 values need not be
+      ** contiguous but all P1 values should be small integers.  It is
+      ** an error for P1 to be negative.
+      */
+      case OP_Open: {
+        int i = pOp->p1;
+        if( i<0 ) goto bad_instruction;
+        if( i>=p->nTable ){
+          int j;
+          p->aTab = sqliteRealloc( p->aTab, (i+1)*sizeof(VdbeTable) );
+          if( p->aTab==0 ){ p->nTable = 0; goto no_mem; }
+          for(j=p->nTable; j<=i; j++) p->aTab[j].pTable = 0;
+          p->nTable = i+1;
+        }else if( p->aTab[i].pTable ){
+          sqliteDbbeCloseTable(p->aTab[i].pTable);
+        }
+        p->aTab[i].pTable = sqliteDbbeOpenTable(p->pBe, pOp->p3, pOp->p2);
+        p->aTab[i].index = 0;
+        break;
+      }
+
+      /* Opcode: Close P1 * *
+      **
+      ** Close a database table previously opened as P1.  If P1 is not
+      ** currently open, this instruction is a no-op.
+      */
+      case OP_Close: {
+        int i = pOp->p1;
+        if( i>=0 && i<p->nTable && p->aTab[i].pTable ){
+          sqliteDbbeCloseTable(p->aTab[i].pTable);
+          p->aTab[i].pTable = 0;
+        }
+        break;
+      }
+
+      /* Opcode: Fetch P1 * *
+      **
+      ** Pop the top of the stack and use its value as a key to fetch
+      ** a record from database table or index P1.  The data is held
+      ** in the P1 cursor until needed.  The data is not pushed onto the
+      ** stack or anything like that.
+      */
+      case OP_Fetch: {
+        int i = pOp->p1;
+        int tos = p->tos;
+        if( tos<0 ) goto not_enough_stack;
+        if( i>=0 && i<p->nTable && p->aTab[i].pTable ){
+          if( p->zStack[tos]==0 ){
+            sqliteDbbeFetch(p->aTab[i].pTable, sizeof(int), 
+                           (char*)&p->iStack[tos]);
+          }else{
+            sqliteDbbeFetch(p->aTab[i].pTable, p->iStack[tos], p->zStack[tos]);
+          }
+        }
+        PopStack(p, 1);
+        break;
+      }
+
+      /* Opcode: New P1 * *
+      **
+      ** Get a new integer key not previous used by table P1 and
+      ** push it onto the stack.
+      */
+      case OP_New: {
+        int i = pOp->p1;
+        int v;
+        if( i<0 || i>=p->nTable || p->aTab[i].pTable==0 ){
+          v = 0;
+        }else{
+          v = sqliteDbbeNew(p->aTab[i].pTable);
+        }
+        NeedStack(p, p->tos+1);
+        p->tos++;
+        p->iStack[p->tos] = v;
+        break;
+      }
+
+      /* Opcode: Put P1 * *
+      **
+      ** Write an entry into the database table P1.  A new entry is
+      ** created if it doesn't already exist, or the data for an existing
+      ** entry is overwritten.  The data is the value on the top of the
+      ** stack.  The key is the next value down on the stack.  The stack
+      ** is popped twice by this instruction.
+      */
+      case OP_Put: {
+        int tos = p->tos;
+        int nos = p->tos-1;
+        int i = pOp->p1;
+        if( nos<0 ) goto not_enough_stack;
+        if( i>=0 && i<p->nTable && p->aTab[i].pTable!=0 ){
+          char *zKey;
+          int nKey;
+          Stringify(p, tos);
+          if( p->zStack[nos]!=0 ){
+            nKey = p->iStack[nos];
+            zKey = p->zStack[nos];
+          }else{
+            nKey = sizeof(int);
+            zKey = (char*)&p->iStack[nos];
+          }
+          sqliteDbbePut(p->aTab[i].pTable, nKey, zKey,
+                        p->iStack[tos], p->zStack[tos]);
+        }
+        PopStack(p, 2);
+        break;
+      }
+
+      /* Opcode: Delete P1 * *
+      **
+      ** The top of the stack is a key.  Remove this key and its data
+      ** from database table P1.  Then pop the stack to discard the key.
+      */
+      case OP_Delete: {
+        int tos = p->tos;
+        int i = pOp->p1;
+        if( tos<0 ) goto not_enough_stack;
+        if( i>=0 && i<p->nTable && p->aTab[i].pTable!=0 ){
+          char *zKey;
+          int nKey;
+          if( p->zStack[tos]!=0 ){
+            nKey = p->iStack[tos];
+            zKey = p->zStack[tos];
+          }else{
+            nKey = sizeof(int);
+            zKey = (char*)&p->iStack[tos];
+          }
+          sqliteDbbeDelete(p->aTab[i].pTable, nKey, zKey);
+        }
+        PopStack(p, 1);
+        break;
+      }
+
+      /* Opcode: Field P1 P2 *
+      **
+      ** Push onto the stack the value of the P2-th field from the
+      ** most recent Fetch from table P1.
+      */
+      case OP_Field: {
+        int *pAddr;
+        int amt;
+        int i = pOp->p1;
+        int p2 = pOp->p2;
+        int tos = ++p->tos;
+        DbbeTable *pTab;
+        char *z;
+
+        if( NeedStack(p, p->tos) ) goto no_mem;
+        if( i>=0 && i<p->nTable && (pTab = p->aTab[i].pTable)!=0 ){
+          amt = sqliteDbbeDataLength(pTab);
+          if( amt<=sizeof(int)*(p2+1) ){
+            sqliteSetString(&p->zStack[tos], "", 0);
+            break;
+          }
+          pAddr = (int*)sqliteDbbeReadData(pTab, sizeof(int)*p2);
+          z = sqliteDbbeReadData(pTab, *pAddr);
+          sqliteSetString(&p->zStack[tos], z, 0);
+          p->iStack[tos] = strlen(z)+1;
+        }
+        break;
+      }
+
+      /* Opcode: Key P1 * *
+      **
+      ** Push onto the stack an integer which is the first 4 bytes of the
+      ** the key to the current entry in a sequential scan of the table P1.
+      ** A sequential scan is started using the Next opcode.
+      */
+      case OP_Key: {
+        int i = pOp->p1;
+        int tos = ++p->tos;
+        DbbeTable *pTab;
+
+        if( NeedStack(p, p->tos) ) goto no_mem;
+        if( i>=0 && i<p->nTable && (pTab = p->aTab[i].pTable)!=0 ){
+          char *z = sqliteDbbeReadKey(pTab, 0);
+          memcpy(&p->iStack[tos], z, sizeof(int));
+          p->zStack[tos] = 0;
+        }
+        break;
+      }
+
+      /* Opcode: Rewind P1 * *
+      **
+      ** The next use of the Key or Field or Next instruction for P1 
+      ** will refer to the first entry in the table.
+      */
+      case OP_Rewind: {
+        int i = pOp->p1;
+        if( i>=0 && i<p->nTable && p->aTab[i].pTable!=0 ){
+          sqliteDbbeRewind(p->aTab[i].pTable);
+        }
+        break;
+      }
+
+      /* Opcode: Next P1 P2 *
+      **
+      ** Advance P1 to the next entry in the table.  Or, if there are no
+      ** more entries, rewind P1 and jump to location P2.
+      */
+      case OP_Next: {
+        int i = pOp->p1;
+        if( i>=0 && i<p->nTable && p->aTab[i].pTable!=0 ){
+          if( sqliteDbbeNextKey(p->aTab[i].pTable)==0 ){
+            pc = pOp->p2;
+            if( pc<0 || pc>p->nOp ){
+              sqliteSetString(pzErrMsg, "jump destination out of range", 0);
+              rc = 1;
+            }
+            pc--;
+          }
+        }
+        break;
+      }
+
+      /* Opcode: ResetIdx P1 * *
+      **
+      ** Begin treating the current row of table P1 as an index.  The next
+      ** NextIdx instruction will refer to the first index in the table.
+      */
+      case OP_ResetIdx: {
+        int i = pOp->p1;
+        if( i>=0 && i<p->nTable ){
+          p->aTab[i].index = 0;
+        }
+        break;
+      }
+
+      /* Opcode: NextIdx P1 P2 *
+      **
+      ** Push the next index from the current entry of table P1 onto the
+      ** stack and advance the pointer.  If there are no more indices, then
+      ** reset the table entry and jump to P2
+      */
+      case OP_NextIdx: {
+        int i = pOp->p1;
+        int tos = ++p->tos;
+        DbbeTable *pTab;
+
+        if( NeedStack(p, p->tos) ) goto no_mem;
+        p->zStack[tos] = 0;
+        if( i>=0 && i<p->nTable && (pTab = p->aTab[i].pTable)!=0 ){
+          int *aIdx;
+          int nIdx;
+          int j;
+          nIdx = sqliteDbbeDataLength(pTab)/sizeof(int);
+          aIdx = (int*)sqliteDbbeReadData(pTab, 0);
+          for(j=p->aTab[i].index; j<nIdx; j++){
+            if( aIdx[j]!=0 ){
+              p->iStack[tos] = aIdx[j];
+              break;
+            }
+          }
+          if( j>=nIdx ){
+            j = -1;
+            pc = pOp->p2;
+            if( pc<0 || pc>p->nOp ){
+              sqliteSetString(pzErrMsg, "jump destination out of range", 0);
+              rc = 1;
+            }
+            pc--;
+          }
+          p->aTab[i].index = j+1;
+        }
+        break;
+      }
+
+      /* Opcode: PutIdx P1 * *
+      **
+      ** The top of the stack hold an index key (proably made using the
+      ** MakeKey instruction) and next on stack holds an index value for
+      ** a table.  Locate the record in the index P1 that has the key 
+      ** and insert the index value into its
+      ** data.  Write the results back to the index.
+      ** If the key doesn't exist it is created.
+      */
+      case OP_PutIdx: {
+        int i = pOp->p1;
+        int tos = p->tos;
+        int nos = tos - 1;
+        DbbeTable *pTab;
+        if( nos<0 ) goto not_enough_stack;
+        if( i>=0 && i<p->nTable && (pTab = p->aTab[i].pTable)!=0 ){
+          int r;
+          int newVal = Integerify(p, nos);
+          Stringify(p, tos);
+          r = sqliteDbbeFetch(pTab, p->iStack[tos], p->zStack[tos]);
+          if( r==0 ){
+            /* Create a new record for this index */
+            sqliteDbbePut(pTab, p->iStack[tos], p->zStack[tos],
+                          sizeof(int), (char*)&newVal);
+          }else{
+            /* Extend the existing record */
+            int nIdx;
+            int *aIdx;
+            nIdx = sqliteDbbeDataLength(pTab)/sizeof(int);
+            aIdx = sqliteMalloc( sizeof(int)*(nIdx+1) );
+            if( aIdx==0 ) goto no_mem;
+            sqliteDbbeCopyData(pTab, 0, nIdx*sizeof(int), (char*)aIdx);
+            aIdx[nIdx] = newVal;
+            sqliteDbbePut(pTab, p->iStack[tos], p->zStack[tos],
+                          sizeof(int)*(nIdx+1), (char*)aIdx);
+            sqliteFree(aIdx);
+          }
+        }
+        PopStack(p, 2);
+        break;
+      }
+
+      /* Opcode: DeleteIdx P1 * *
+      **
+      ** The top of the stack is a key and next on stack is an index value.
+      ** Locate the record
+      ** in index P1 that has the key and remove the index value from its
+      ** data.  Write the results back to the table.  If after removing
+      ** the index value no more indices remain in the record, then the
+      ** record is removed from the table.
+      */
+      case OP_DeleteIdx: {
+        int i = pOp->p1;
+        int tos = p->tos;
+        int nos = tos - 1;
+        DbbeTable *pTab;
+        if( nos<0 ) goto not_enough_stack;
+        if( i>=0 && i<p->nTable && (pTab = p->aTab[i].pTable)!=0 ){
+          int *aIdx;
+          int nIdx;
+          int j;
+          int r;
+          int oldVal = Integerify(p, nos);
+          Stringify(p, tos);
+          r = sqliteDbbeFetch(pTab, p->iStack[tos], p->zStack[tos]);
+          if( r==0 ) break;
+          nIdx = sqliteDbbeDataLength(pTab)/sizeof(int);
+          aIdx = (int*)sqliteDbbeReadData(pTab, 0);
+          for(j=0; j<nIdx && aIdx[j]!=oldVal; j++){}
+          if( j>=nIdx ) break;
+          aIdx[j] = aIdx[nIdx-1];
+          if( nIdx==1 ){
+            sqliteDbbeDelete(pTab, p->iStack[tos], p->zStack[tos]);
+          }else{
+            sqliteDbbePut(pTab, p->iStack[tos], p->zStack[tos], 
+                          sizeof(int)*(nIdx-1), (char*)aIdx);
+          }
+        }
+        PopStack(p, 2);
+        break;
+      }
+
+      /* Opcode: Destroy * * P3
+      **
+      ** Drop the table whose name is P3.  The file that holds this table
+      ** is removed from the disk drive.
+      */
+      case OP_Destroy: {
+        sqliteDbbeDropTable(p->pBe, pOp->p3);
+        break;
+      }
+
+      /* Opcode: ListOpen P1 * *
+      **
+      ** Open a file used for temporary storage of index numbers.  P1
+      ** will server as a handle to this temporary file for future
+      ** interactions.  If another temporary file with the P1 handle is
+      ** already opened, the prior file is closed and a new one opened
+      ** in its place.
+      */
+      case OP_ListOpen: {
+        int i = pOp->p1;
+        if( i<0 ) goto bad_instruction;
+        if( i>=p->nList ){
+          int j;
+          p->apList = sqliteRealloc( p->apList, (i+1)*sizeof(FILE*) );
+          if( p->apList==0 ){ p->nList = 0; goto no_mem; }
+          for(j=p->nList; j<=i; j++) p->apList[j] = 0;
+          p->nList = i+1;
+        }else if( p->apList[i] ){
+          sqliteDbbeCloseTempFile(p->pBe, p->apList[i]);
+        }
+        p->apList[i] = sqliteDbbeOpenTempFile(p->pBe);
+        break;
+      }
+
+      /* Opcode: ListWrite P1 * *
+      **
+      ** Write the integer on the top of the stack
+      ** into the temporary storage file P1.
+      */
+      case OP_ListWrite: {
+        int i = pOp->p1;
+        if( i<0 ) goto bad_instruction;
+        if( p->tos<0 ) goto not_enough_stack;
+        if( i<p->nList && p->apList[i]!=0 ){
+          int val = Integerify(p, p->tos);
+          PopStack(p, 1);
+          fwrite(&val, sizeof(int), 1, p->apList[i]);
+        }
+        break;
+      }
+
+      /* Opcode: ListRewind P1 * *
+      **
+      ** Rewind the temporary buffer P1 back to the beginning.
+      */
+      case OP_ListRewind: {
+        int i = pOp->p1;
+        if( i<0 ) goto bad_instruction;
+        if( i<p->nList && p->apList[i]!=0 ){
+          rewind(p->apList[i]);
+        }
+        break;
+      }
+
+      /* Opcode: ListRead P1 P2 *
+      **
+      ** Attempt to read an integer from temporary storage buffer P1
+      ** and push it onto the stack.  If the storage buffer is empty
+      ** push nothing but instead jump to P2.
+      */
+      case OP_ListRead: {
+        int i = pOp->p1;
+        int val, amt;
+        if( i<0 || i>=p->nList || p->apList[i]==0 ) goto bad_instruction;
+        amt = fread(&val, sizeof(int), 1, p->apList[i]);
+        if( amt==1 ){
+          p->tos++;
+          if( NeedStack(p, p->tos) ) goto no_mem;
+          p->iStack[p->tos] = val;
+          p->zStack[p->tos] = 0;
+        }else{
+          pc = pOp->p2;
+          if( pc<0 || pc>p->nOp ){
+            sqliteSetString(pzErrMsg, "jump destination out of range", 0);
+            rc = 1;
+          }
+          pc--;
+        }
+        break;
+      }
+
+      /* Opcode: ListClose P1 * *
+      **
+      ** Close the temporary storage buffer and discard its contents.
+      */
+      case OP_ListClose: {
+        int i = pOp->p1;
+        if( i<0 ) goto bad_instruction;
+        if( i<p->nList && p->apList[i]!=0 ){
+          sqliteDbbeCloseTempFile(p->pBe, p->apList[i]);
+          p->apList[i] = 0;
+        }
+        break;
+      }
+
+      /* Opcode: SortOpen P1 * *
+      **
+      ** Create a new sorter with index P1
+      */
+      case OP_SortOpen: {
+        int i = pOp->p1;
+        if( i<0 ) goto bad_instruction;
+        if( i>=p->nSort ){
+          int j;
+          p->apSort = sqliteRealloc( p->apSort, (i+1)*sizeof(Sorter*) );
+          if( p->apSort==0 ){ p->nSort = 0; goto no_mem; }
+          for(j=p->nSort; j<=i; j++) p->apSort[j] = 0;
+          p->nSort = i+1;
+        }
+        break;
+      }
+
+      /* Opcode: SortPut P1 * *
+      **
+      ** The TOS is the key and the NOS is the data.  Pop both from the stack
+      ** and put them on the sorter.
+      */
+      case OP_SortPut: {
+        int i = pOp->p1;
+        Sorter *pSorter;
+        if( i<0 || i>=p->nSort ) goto bad_instruction;
+        if( p->tos<1 ) goto not_enough_stack;
+        Stringify(p, p->tos);
+        Stringify(p, p->tos-1);
+        pSorter = sqliteMalloc( sizeof(Sorter) );
+        if( pSorter==0 ) goto no_mem;
+        pSorter->pNext = p->apSort[i];
+        p->apSort[i] = pSorter;
+        pSorter->nKey = p->iStack[p->tos];
+        pSorter->zKey = p->zStack[p->tos];
+        pSorter->nData = p->iStack[p->tos-1];
+        pSorter->pData = p->zStack[p->tos-1];
+        p->zStack[p->tos] = p->zStack[p->tos-1] = 0;
+        PopStack(p, 2);
+        break;
+      }
+
+      /* Opcode: SortMakeRec P1 * *
+      **
+      ** The top P1 elements are the arguments to a callback.  Form these
+      ** elements into a single data entry that can be stored on a sorter
+      ** using SortPut and later fed to a callback using SortCallback.
+      */
+      case OP_SortMakeRec: {
+        char *z;
+        char **azArg;
+        int nByte;
+        int nField;
+        int i, j;
+
+        nField = pOp->p1;
+        if( p->tos+1<nField ) goto not_enough_stack;
+        nByte = 0;
+        for(i=p->tos-nField+1; i<=p->tos; i++){
+          if( Stringify(p, i) ) goto no_mem;
+          nByte += p->iStack[i];
+        }
+        nByte += sizeof(char*)*(nField+1);
+        azArg = sqliteMalloc( nByte );
+        if( azArg==0 ) goto no_mem;
+        z = (char*)&azArg[nField+1];
+        for(j=0, i=p->tos-nField+1; i<=p->tos; i++, j++){
+          azArg[j] = z;
+          strcpy(z, p->zStack[i]);
+          z += p->iStack[i];
+        }
+        PopStack(p, nField);
+        NeedStack(p, p->tos+1);
+        p->tos++;
+        p->iStack[p->tos] = nByte;
+        p->zStack[p->tos] = (char*)azArg;
+        break;
+      }
+
+      /* Opcode: SortMakeKey P1 * P3
+      **
+      ** Convert the top few entries of the stack into a sort key.  The
+      ** number of stack entries consumed is the number of characters in 
+      ** the string P3.  One character from P3 is prepended to each entry.
+      ** The first character of P3 is prepended to the element lowest in
+      ** the stack and the last character of P3 is appended to the top of
+      ** the stack.  All stack entries are separated by a \000 character
+      ** in the result.  The whole key is terminated by two \000 characters
+      ** in a row.
+      **
+      ** See also the MakeKey opcode.
+      */
+      case OP_SortMakeKey: {
+        char *zNewKey;
+        int nByte;
+        int nField;
+        int i, j, k;
+
+        nField = strlen(pOp->p3);
+        if( p->tos+1<nField ) goto not_enough_stack;
+        nByte = 1;
+        for(i=p->tos-nField+1; i<=p->tos; i++){
+          if( Stringify(p, i) ) goto no_mem;
+          nByte += p->iStack[i]+2;
+        }
+        zNewKey = sqliteMalloc( nByte );
+        if( zNewKey==0 ) goto no_mem;
+        j = 0;
+        k = nField-1;
+        for(i=p->tos-nField+1; i<=p->tos; i++){
+          zNewKey[j++] = pOp->p3[k--];
+          memcpy(&zNewKey[j], p->zStack[i], p->iStack[i]-1);
+          j += p->iStack[i]-1;
+          zNewKey[j++] = 0;
+        }
+        zNewKey[j] = 0;
+        PopStack(p, nField);
+        NeedStack(p, p->tos+1);
+        p->tos++;
+        p->iStack[p->tos] = nByte;
+        p->zStack[p->tos] = zNewKey;
+        break;
+      }
+
+      /* Opcode: Sort P1 * *
+      **
+      ** Sort all elements on the given sorter.  The algorithm is a
+      ** mergesort.
+      */
+      case OP_Sort: {
+        int j;
+        j = pOp->p1;
+        if( j<0 ) goto bad_instruction;
+        if( j<p->nSort ){
+          int i;
+          Sorter *pElem;
+          Sorter *apSorter[NSORT];
+          for(i=0; i<NSORT; i++){
+            apSorter[i] = 0;
+          }
+          while( p->apSort[j] ){
+            pElem = p->apSort[j];
+            p->apSort[j] = pElem->pNext;
+            pElem->pNext = 0;
+            for(i=0; i<NSORT-1; i++){
+              if( apSorter[i]==0 ){
+                apSorter[i] = pElem;
+                break;
+              }else{
+                pElem = Merge(apSorter[i], pElem);
+                apSorter[i] = 0;
+              }
+            }
+            if( i>=NSORT-1 ){
+              apSorter[NSORT-1] = Merge(apSorter[NSORT-1],pElem);
+            }
+          }
+          pElem = 0;
+          for(i=0; i<NSORT; i++){
+            pElem = Merge(apSorter[i], pElem);
+          }
+          p->apSort[j] = pElem;
+        }
+        break;
+      }
+
+      /* Opcode: SortNext P1 P2 *
+      **
+      ** Push the data for the topmost element in the given sorter onto the
+      ** stack, then remove the element from the sorter.
+      */
+      case OP_SortNext: {
+        int i = pOp->p1;
+        if( i<0 ) goto bad_instruction;
+        if( i<p->nSort && p->apSort[i]!=0 ){
+          Sorter *pSorter = p->apSort[i];
+          p->apSort[i] = pSorter->pNext;
+          p->tos++;
+          NeedStack(p, p->tos);
+          p->zStack[p->tos] = pSorter->pData;
+          p->iStack[p->tos] = pSorter->nData;
+          sqliteFree(pSorter->zKey);
+          sqliteFree(pSorter);
+        }else{
+          pc = pOp->p2;
+          if( pc<0 || pc>p->nOp ){
+            sqliteSetString(pzErrMsg, "jump destination out of range", 0);
+            rc = 1;
+          }
+          pc--;
+        }
+        break;
+      }
+
+      /* Opcode: SortKey P1 * *
+      **
+      ** Push the key for the topmost element of the sorter onto the stack.
+      ** But don't change the sorter an any other way.
+      */
+      case OP_SortKey: {
+        int i = pOp->p1;
+        if( i<0 ) goto bad_instruction;
+        if( i<p->nSort && p->apSort[i]!=0 ){
+          Sorter *pSorter = p->apSort[i];
+          p->tos++;
+          NeedStack(p, p->tos);
+          sqliteSetString(&p->zStack[p->tos], pSorter->zKey, 0);
+          p->iStack[p->tos] = pSorter->nKey;
+        }
+        break;
+      }
+
+      /* Opcode: SortCallback P1 P2 *
+      **
+      ** The top of the stack contains a callback record built using
+      ** the SortMakeRec operation with the same P1 value as this
+      ** instruction.  Pop this record from the stack and invoke the
+      ** callback on it.
+      */
+      case OP_SortCallback: {
+        int i = p->tos;
+        if( i<0 ) goto not_enough_stack;
+        rc = xCallback(pArg, pOp->p1, (char**)p->zStack[i], p->azColName);
+        PopStack(p, 1);
+        break;
+      }
+
+      /* Opcode: SortClose P1 * *
+      **
+      ** Close the given sorter and remove all its elements.
+      */
+      case OP_SortClose: {
+        Sorter *pSorter;
+        int i = pOp->p1;
+        if( i<0 ) goto bad_instruction;
+        if( i<p->nSort ){
+           while( (pSorter = p->apSort[i])!=0 ){
+             p->apSort[i] = pSorter->pNext;
+             sqliteFree(pSorter->zKey);
+             sqliteFree(pSorter->pData);
+             sqliteFree(pSorter);
+           }
+        }
+        break;
+      }
+
+      /* An other opcode is illegal...
+      */
+      default: {
+        sprintf(zBuf,"%d",pOp->opcode);
+        sqliteSetString(pzErrMsg, "unknown opcode ", zBuf, 0);
+        rc = 1;
+        break;
+      }
+    }
+    if( p->trace && p->tos>=0 ){
+      int i;
+      fprintf(p->trace, "Stack:");
+      for(i=p->tos; i>=0 && i>p->tos-5; i--){
+        if( p->zStack[i] ){
+          fprintf(p->trace, " [%.11s]", p->zStack[i]);
+        }else{
+          fprintf(p->trace, " [%d]", p->iStack[i]);
+        }
+      }
+      fprintf(p->trace,"\n");
+    }
+  }
+
+cleanup:
+  Cleanup(p);
+  return rc;
+
+  /* Jump to here if a malloc() fails.  It's hard to get a malloc()
+  ** to fail on a modern VM computer, so this code is untested.
+  */
+no_mem:
+  Cleanup(p);
+  sqliteSetString(pzErrMsg, "out or memory", 0);
+  return 1;
+
+  /* Jump to here if a operator is encountered that requires more stack
+  ** operands than are currently available on the stack.
+  */
+not_enough_stack:
+  sprintf(zBuf,"%d",pc);
+  sqliteSetString(pzErrMsg, "too few operands on stack at ", zBuf, 0);
+  rc = 1;
+  goto cleanup;
+
+  /* Jump here if an illegal or illformed instruction is executed.
+  */
+bad_instruction:
+  sprintf(zBuf,"%d",pc);
+  sqliteSetString(pzErrMsg, "illegal operation at ", zBuf, 0);
+  rc = 1;
+  goto cleanup;
+
+}
diff --git a/src/vdbe.h b/src/vdbe.h
new file mode 100644 (file)
index 0000000..5bafa99
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+** Copyright (c) 1999, 2000 D. Richard Hipp
+**
+** 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 library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*************************************************************************
+** Header file for the Virtual DataBase Engine (VDBE)
+**
+** This header defines the interface to the virtual database engine
+** or VDBE.  The VDBE implements an abstract machine that runs a
+** simple program to access and modify the underlying database.
+**
+** $Id: vdbe.h,v 1.1 2000/05/29 14:26:02 drh Exp $
+*/
+#ifndef _SQLITE_VDBE_H_
+#define _SQLITE_VDBE_H_
+#include <stdio.h>
+
+/*
+** A single VDBE is an opaque structure named "Vdbe".  Only routines
+** in the source file sqliteVdbe.c are allowed to see the insides
+** of this structure.
+*/
+typedef struct Vdbe Vdbe;
+
+/*
+** A single instruction of the virtual machine has an opcode
+** and as many as three operands.  The instruction is recorded
+** as an instance of the following structure:
+*/
+struct VdbeOp {
+  int opcode;         /* What operation to perform */
+  int p1;             /* First operand */
+  int p2;             /* Second parameter (often the jump destination) */
+  char *p3;           /* Third parameter */
+};
+typedef struct VdbeOp VdbeOp;
+
+/*
+** The following macro converts a relative address in the p2 field
+** of a VdbeOp structure into a negative number so that 
+** sqliteVdbeAddOpList() knows that the address is relative.  Calling
+** the macro again restores the address.
+*/
+#define ADDR(X)  (-1-(X))
+
+/*
+** These are the available opcodes.
+**
+** If any of the values changes or if opcodes are added or removed,
+** be sure to also update the zOpName[] array in sqliteVdbe.c to
+** mirror the change.
+**
+** The source tree contains an AWK script named renumberOps.awk that
+** can be used to renumber these opcodes when new opcodes are inserted.
+*/
+#define OP_Open                1
+#define OP_Close               2
+#define OP_Destroy             3
+#define OP_Fetch               4
+#define OP_New                 5
+#define OP_Put                 6
+#define OP_Delete              7
+#define OP_Field               8
+#define OP_Key                 9
+#define OP_Rewind             10
+#define OP_Next               11
+#define OP_ResetIdx           12
+#define OP_NextIdx            13
+#define OP_PutIdx             14
+#define OP_DeleteIdx          15
+
+#define OP_ListOpen           16
+#define OP_ListWrite          17
+#define OP_ListRewind         18
+#define OP_ListRead           19
+#define OP_ListClose          20
+
+#define OP_SortOpen           21
+#define OP_SortPut            22
+#define OP_SortMakeRec        23
+#define OP_SortMakeKey        24
+#define OP_Sort               25
+#define OP_SortNext           26
+#define OP_SortKey            27
+#define OP_SortCallback       28
+#define OP_SortClose          29
+
+#define OP_MakeRecord         30
+#define OP_MakeKey            31
+
+#define OP_Goto               32
+#define OP_If                 33
+#define OP_Halt               34
+
+#define OP_ColumnCount        35
+#define OP_ColumnName         36
+#define OP_Callback           37
+
+#define OP_Integer            38
+#define OP_String             39
+#define OP_Pop                40
+#define OP_Dup                41
+#define OP_Pull               42
+
+#define OP_Add                43
+#define OP_AddImm             44
+#define OP_Subtract           45
+#define OP_Multiply           46
+#define OP_Divide             47
+#define OP_Min                48
+#define OP_Max                49
+#define OP_Eq                 50
+#define OP_Ne                 51
+#define OP_Lt                 52
+#define OP_Le                 53
+#define OP_Gt                 54
+#define OP_Ge                 55
+#define OP_IsNull             56
+#define OP_NotNull            57
+#define OP_Negative           58
+#define OP_And                59
+#define OP_Or                 60
+#define OP_Not                61
+#define OP_Concat             62
+#define OP_Noop               63
+
+#define OP_MAX                63
+
+/*
+** Prototypes for the VDBE interface.  See comments on the implementation
+** for a description of what each of these routines does.
+*/
+Vdbe *sqliteVdbeCreate(Dbbe*);
+int sqliteVdbeAddOp(Vdbe*,int,int,int,const char*,int);
+int sqliteVdbeAddOpList(Vdbe*, int nOp, VdbeOp const *aOp);
+void sqliteVdbeChangeP3(Vdbe*, int addr, const char *zP1, int N);
+void sqliteVdbeDequoteP3(Vdbe*, int addr);
+int sqliteVdbeMakeLabel(Vdbe*);
+void sqliteVdbeDelete(Vdbe*);
+int sqliteVdbeOpcode(const char *zName);
+int sqliteVdbeExec(Vdbe*,sqlite_callback,void*,char**);
+int sqliteVdbeList(Vdbe*,sqlite_callback,void*,char**);
+void sqliteVdbeResolveLabel(Vdbe*, int);
+int sqliteVdbeCurrentAddr(Vdbe*);
+void sqliteVdbeTrace(Vdbe*,FILE*);
+
+
+#endif
diff --git a/src/where.c b/src/where.c
new file mode 100644 (file)
index 0000000..ea15a5e
--- /dev/null
@@ -0,0 +1,566 @@
+/*
+** Copyright (c) 1999, 2000 D. Richard Hipp
+**
+** 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 library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*************************************************************************
+** This module contains C code that generates VDBE code used to process
+** the WHERE clause of SQL statements.  Also found here are subroutines
+** to generate VDBE code to evaluate expressions.
+**
+** $Id: where.c,v 1.1 2000/05/29 14:26:02 drh Exp $
+*/
+#include "sqliteInt.h"
+
+/*
+** The query generator uses an array of instances of this structure to
+** help it analyze the subexpressions of the WHERE clause.  Each WHERE
+** clause subexpression is separated from the others by an AND operator.
+*/
+typedef struct ExprInfo ExprInfo;
+struct ExprInfo {
+  Expr *p;                /* Pointer to the subexpression */
+  int indexable;          /* True if this subexprssion is usable by an index */
+  int idxLeft;            /* p->pLeft is a field in this table number. -1 if
+                          ** p->pLeft is not the field of any table */
+  int idxRight;           /* p->pRight is a field in this table number. -1 if
+                          ** p->pRight is not the field of any table */
+  unsigned prereqLeft;    /* Tables referenced by p->pLeft */
+  unsigned prereqRight;   /* Tables referenced by p->pRight */
+};
+
+/*
+** Determine the number of elements in an array.
+*/
+#define ARRAYSIZE(X)  (sizeof(X)/sizeof(X[0]))
+
+/*
+** This routine is used to divide the WHERE expression into subexpressions
+** separated by the AND operator.
+**
+** aSlot[] is an array of subexpressions structures.
+** There are nSlot spaces left in this array.  This routine attempts to
+** split pExpr into subexpressions and fills aSlot[] with those subexpressions.
+** The return value is the number of slots filled.
+*/
+static int exprSplit(int nSlot, ExprInfo *aSlot, Expr *pExpr){
+  int cnt = 0;
+  if( pExpr==0 || nSlot<1 ) return 0;
+  if( nSlot==1 || pExpr->op!=TK_AND ){
+    aSlot[0].p = pExpr;
+    return 1;
+  }
+  if( pExpr->pLeft->op!=TK_AND ){
+    aSlot[0].p = pExpr->pLeft;
+    cnt = 1 + exprSplit(nSlot-1, &aSlot[1], pExpr->pRight);
+  }else{
+    cnt = exprSplit(nSlot, aSlot, pExpr->pRight);
+    cnt += exprSplit(nSlot-cnt, &aSlot[cnt], pExpr->pLeft);
+  }
+  return cnt;
+}
+
+/*
+** This routine walks (recursively) an expression tree and generates
+** a bitmask indicating which tables are used in that expression
+** tree.  Bit 0 of the mask is set if table 0 is used.  But 1 is set
+** if table 1 is used.  And so forth.
+**
+** In order for this routine to work, the calling function must have
+** previously invoked sqliteExprResolveIds() on the expression.  See
+** the header comment on that routine for additional information.
+*/
+static int exprTableUsage(Expr *p){
+  unsigned int mask = 0;
+  if( p==0 ) return 0;
+  if( p->op==TK_FIELD ){
+    return 1<<p->iTable;
+  }
+  if( p->pRight ){
+    mask = exprTableUsage(p->pRight);
+  }
+  if( p->pLeft ){
+    mask |= exprTableUsage(p->pLeft);
+  }
+  return mask;
+}
+
+/*
+** The input to this routine is an ExprInfo structure with only the
+** "p" field filled in.  The job of this routine is to analyze the
+** subexpression and populate all the other fields of the ExprInfo
+** structure.
+*/
+static void exprAnalyze(ExprInfo *pInfo){
+  Expr *pExpr = pInfo->p;
+  pInfo->prereqLeft = exprTableUsage(pExpr->pLeft);
+  pInfo->prereqRight = exprTableUsage(pExpr->pRight);
+  pInfo->indexable = 0;
+  pInfo->idxLeft = -1;
+  pInfo->idxRight = -1;
+  if( pExpr->op==TK_EQ && (pInfo->prereqRight & pInfo->prereqLeft)==0 ){
+    if( pExpr->pRight->op==TK_FIELD ){
+      pInfo->idxRight = pExpr->pRight->iTable;
+      pInfo->indexable = 1;
+    }
+    if( pExpr->pLeft->op==TK_FIELD ){
+      pInfo->idxLeft = pExpr->pLeft->iTable;
+      pInfo->indexable = 1;
+    }
+  }
+}
+
+/*
+** Generating the beginning of the loop used for WHERE clause processing.
+** The return value is a pointer to an (opaque) structure that contains
+** information needed to terminate the loop.  Later, the calling routine
+** should invoke sqliteWhereEnd() with the return value of this function
+** in order to complete the WHERE clause processing.
+**
+** If an error occurs, this routine returns NULL.
+*/
+WhereInfo *sqliteWhereBegin(
+  Parse *pParse,       /* The parser context */
+  IdList *pTabList,    /* A list of all tables */
+  Expr *pWhere,        /* The WHERE clause */
+  int pushKey          /* If TRUE, leave the table key on the stack */
+){
+  int i;                     /* Loop counter */
+  WhereInfo *pWInfo;         /* Will become the return value of this function */
+  Vdbe *v = pParse->pVdbe;   /* The virtual database engine */
+  int brk, cont;             /* Addresses used during code generation */
+  int *aOrder;         /* Order in which pTabList entries are searched */
+  int nExpr;           /* Number of subexpressions in the WHERE clause */
+  int loopMask;        /* One bit set for each outer loop */
+  int haveKey;         /* True if KEY is on the stack */
+  Index *aIdx[32];     /* Index to use on each nested loop.  */
+  ExprInfo aExpr[50];  /* The WHERE clause is divided into these expressions */
+
+  /* Allocate space for aOrder[]. */
+  aOrder = sqliteMalloc( sizeof(int) * pTabList->nId );
+
+  /* Allocate and initialize the WhereInfo structure that will become the
+  ** return value.
+  */
+  pWInfo = sqliteMalloc( sizeof(WhereInfo) );
+  if( pWInfo==0 ){
+    sqliteFree(aOrder);
+    return 0;
+  }
+  pWInfo->pParse = pParse;
+  pWInfo->pTabList = pTabList;
+
+  /* Split the WHERE clause into as many as 32 separate subexpressions
+  ** where each subexpression is separated by an AND operator.  Any additional
+  ** subexpressions are attached in the aExpr[32] and will not enter
+  ** into the query optimizer computations.  32 is chosen as the cutoff
+  ** since that is the number of bits in an integer that we use for an
+  ** expression-used mask.  
+  */
+  memset(aExpr, 0, sizeof(aExpr));
+  nExpr = exprSplit(ARRAYSIZE(aExpr), aExpr, pWhere);
+
+  /* Analyze all of the subexpressions.
+  */
+  for(i=0; i<nExpr; i++){
+    exprAnalyze(&aExpr[i]);
+  }
+
+  /* Figure out a good nesting order for the tables.  aOrder[0] will
+  ** be the index in pTabList of the outermost table.  aOrder[1] will
+  ** be the first nested loop and so on.  aOrder[pTabList->nId-1] will
+  ** be the innermost loop.
+  **
+  ** Someday will put in a good algorithm here to reorder to the loops
+  ** for an effiecient query.  But for now, just use whatever order the
+  ** tables appear in in the pTabList.
+  */
+  for(i=0; i<pTabList->nId; i++){
+    aOrder[i] = i;
+  }
+
+  /* Figure out what index to use (if any) for each nested loop.
+  ** Make aIdx[i] point to the index to use for the i-th nested loop
+  ** where i==0 is the outer loop and i==pTabList->nId-1 is the inner
+  ** loop.
+  **
+  ** Actually, if there are more than 32 tables in the join, only the
+  ** first 32 tables are candidates for indices.
+  */
+  loopMask = 0;
+  for(i=0; i<pTabList->nId && i<ARRAYSIZE(aIdx); i++){
+    int idx = aOrder[i];
+    Table *pTab = pTabList->a[idx].pTab;
+    Index *pIdx;
+    Index *pBestIdx = 0;
+
+    /* Do a search for usable indices.  Leave pBestIdx pointing to
+    ** most specific usable index.
+    **
+    ** "Most specific" means that pBestIdx is the usable index that
+    ** has the largest value for nField.  A usable index is one for
+    ** which there are subexpressions to compute every field of the
+    ** index.
+    */
+    for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+      int j;
+      int fieldMask = 0;
+
+      if( pIdx->nField>32 ) continue;
+      for(j=0; j<nExpr; j++){
+        if( aExpr[j].idxLeft==idx 
+             && (aExpr[j].prereqRight & loopMask)==aExpr[j].prereqRight ){
+          int iField = aExpr[j].p->pLeft->iField;
+          int k;
+          for(k=0; k<pIdx->nField; k++){
+            if( pIdx->aiField[k]==iField ){
+              fieldMask |= 1<<k;
+              break;
+            }
+          }
+        }
+        if( aExpr[j].idxRight==idx 
+             && (aExpr[j].prereqLeft & loopMask)==aExpr[j].prereqLeft ){
+          int iField = aExpr[j].p->pRight->iField;
+          int k;
+          for(k=0; k<pIdx->nField; k++){
+            if( pIdx->aiField[k]==iField ){
+              fieldMask |= 1<<k;
+              break;
+            }
+          }
+        }
+      }
+      if( fieldMask + 1 == (1<<pIdx->nField) ){
+        if( pBestIdx==0 || pBestIdx->nField<pIdx->nField ){
+          pBestIdx = pIdx;
+        }
+      }
+    }
+    aIdx[i] = pBestIdx;
+  }
+
+  /* Open all tables in the pTabList and all indices in aIdx[].
+  */
+  for(i=0; i<pTabList->nId; i++){
+    sqliteVdbeAddOp(v, OP_Open, i, 0, pTabList->a[i].pTab->zName, 0);
+    if( i<ARRAYSIZE(aIdx) && aIdx[i]!=0 ){
+      sqliteVdbeAddOp(v, OP_Open, pTabList->nId+i, 0, aIdx[i]->zName, 0);
+    }
+  }
+
+  /* Generate the code to do the search
+  */
+  pWInfo->iBreak = brk = sqliteVdbeMakeLabel(v);
+  loopMask = 0;
+  for(i=0; i<pTabList->nId; i++){
+    int j, k;
+    int idx = aOrder[i];
+    Index *pIdx = i<ARRAYSIZE(aIdx) ? aIdx[i] : 0;
+
+    cont = sqliteVdbeMakeLabel(v);
+    if( pIdx==0 ){
+      /* Case 1:  There was no usable index.  We must do a complete
+      ** scan of the table.
+      */
+      sqliteVdbeAddOp(v, OP_Next, idx, brk, 0, cont);
+      haveKey = 0;
+    }else{
+      /* Case 2:  We do have a usable index in pIdx.
+      */
+      for(j=0; j<pIdx->nField; j++){
+        for(k=0; k<nExpr; k++){
+          if( aExpr[k].p==0 ) continue;
+          if( aExpr[k].idxLeft==idx 
+             && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight 
+             && aExpr[k].p->pLeft->iField==pIdx->aiField[j]
+          ){
+            sqliteExprCode(pParse, aExpr[k].p->pRight);
+            aExpr[k].p = 0;
+            break;
+          }
+          if( aExpr[k].idxRight==idx 
+             && (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft
+             && aExpr[k].p->pRight->iField==pIdx->aiField[j]
+          ){
+            sqliteExprCode(pParse, aExpr[k].p->pLeft);
+            aExpr[k].p = 0;
+            break;
+          }
+        }
+      }
+      sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0);
+      sqliteVdbeAddOp(v, OP_Fetch, pTabList->nId+i, 0, 0, 0);
+      sqliteVdbeAddOp(v, OP_NextIdx, pTabList->nId+i, brk, 0, cont);
+      if( i==pTabList->nId-1 && pushKey ){
+        haveKey = 1;
+      }else{
+        sqliteVdbeAddOp(v, OP_Fetch, idx, 0, 0, 0);
+        haveKey = 0;
+      }
+    }
+    loopMask |= 1<<idx;
+
+    /* Insert code to test every subexpression that can be completely
+    ** computed using the current set of tables.
+    */
+    for(j=0; j<nExpr; j++){
+      if( aExpr[j].p==0 ) continue;
+      if( (aExpr[j].prereqRight & loopMask)!=aExpr[j].prereqRight ) continue;
+      if( (aExpr[j].prereqLeft & loopMask)!=aExpr[j].prereqLeft ) continue;
+      if( haveKey ){
+        sqliteVdbeAddOp(v, OP_Fetch, idx, 0, 0, 0);
+        haveKey = 0;
+      }
+      sqliteExprIfFalse(pParse, aExpr[j].p, cont);
+      aExpr[j].p = 0;
+    }
+    brk = cont;
+  }
+  pWInfo->iContinue = cont;
+  if( pushKey && !haveKey ){
+    sqliteVdbeAddOp(v, OP_Key, 0, 0, 0, 0);
+  }
+  sqliteFree(aOrder);
+  return pWInfo;
+}
+
+/*
+** Generate the end of the WHERE loop.
+*/
+void sqliteWhereEnd(WhereInfo *pWInfo){
+  Vdbe *v = pWInfo->pParse->pVdbe;
+  sqliteVdbeAddOp(v, OP_Goto, 0, pWInfo->iContinue, 0, 0);
+  sqliteVdbeAddOp(v, OP_Noop, 0, 0, 0, pWInfo->iBreak);
+  sqliteFree(pWInfo);
+  return;
+}
+
+/*
+** Generate code into the current Vdbe to evaluate the given
+** expression and leave the result on the stack.
+*/
+void sqliteExprCode(Parse *pParse, Expr *pExpr){
+  Vdbe *v = pParse->pVdbe;
+  int op;
+  switch( pExpr->op ){
+    case TK_PLUS:     op = OP_Add;      break;
+    case TK_MINUS:    op = OP_Subtract; break;
+    case TK_STAR:     op = OP_Multiply; break;
+    case TK_SLASH:    op = OP_Divide;   break;
+    case TK_AND:      op = OP_And;      break;
+    case TK_OR:       op = OP_Or;       break;
+    case TK_LT:       op = OP_Lt;       break;
+    case TK_LE:       op = OP_Le;       break;
+    case TK_GT:       op = OP_Gt;       break;
+    case TK_GE:       op = OP_Ge;       break;
+    case TK_NE:       op = OP_Ne;       break;
+    case TK_EQ:       op = OP_Eq;       break;
+    case TK_ISNULL:   op = OP_IsNull;   break;
+    case TK_NOTNULL:  op = OP_NotNull;  break;
+    case TK_NOT:      op = OP_Not;      break;
+    case TK_UMINUS:   op = OP_Negative; break;
+    default: break;
+  }
+  switch( pExpr->op ){
+    case TK_FIELD: {
+      sqliteVdbeAddOp(v, OP_Field, pExpr->iTable, pExpr->iField, 0, 0);
+      break;
+    }
+    case TK_INTEGER: {
+      int i = atoi(pExpr->token.z);
+      sqliteVdbeAddOp(v, OP_Integer, i, 0, 0, 0);
+      break;
+    }
+    case TK_FLOAT: {
+      int addr = sqliteVdbeAddOp(v, OP_String, 0, 0, 0, 0);
+      sqliteVdbeChangeP3(v, addr, pExpr->token.z, pExpr->token.n);
+      break;
+    }
+    case TK_STRING: {
+      int addr = sqliteVdbeAddOp(v, OP_String, 0, 0, 0, 0);
+      sqliteVdbeChangeP3(v, addr, pExpr->token.z, pExpr->token.n);
+      sqliteVdbeDequoteP3(v, addr);
+      break;
+    }
+    case TK_NULL: {
+      sqliteVdbeAddOp(v, OP_String, 0, 0, "", 0);
+      break;
+    }
+    case TK_AND:
+    case TK_OR:
+    case TK_PLUS:
+    case TK_STAR:
+    case TK_MINUS:
+    case TK_SLASH: {
+      sqliteExprCode(pParse, pExpr->pLeft);
+      sqliteExprCode(pParse, pExpr->pRight);
+      sqliteVdbeAddOp(v, op, 0, 0, 0, 0);
+      break;
+    }
+    case TK_LT:
+    case TK_LE:
+    case TK_GT:
+    case TK_GE:
+    case TK_NE:
+    case TK_EQ: {
+      int dest;
+      sqliteVdbeAddOp(v, OP_Integer, 0, 0, 0, 0);
+      sqliteExprCode(pParse, pExpr->pLeft);
+      sqliteExprCode(pParse, pExpr->pRight);
+      dest = sqliteVdbeCurrentAddr(v) + 2;
+      sqliteVdbeAddOp(v, op, 0, dest, 0, 0);
+      sqliteVdbeAddOp(v, OP_AddImm, 1, 0, 0, 0);
+      break;
+    }
+    case TK_NOT:
+    case TK_UMINUS: {
+      sqliteExprCode(pParse, pExpr->pLeft);
+      sqliteVdbeAddOp(v, op, 0, 0, 0, 0);
+      break;
+    }
+    case TK_ISNULL:
+    case TK_NOTNULL: {
+      int dest;
+      sqliteVdbeAddOp(v, OP_Integer, 0, 0, 0, 0);
+      sqliteExprCode(pParse, pExpr->pLeft);
+      dest = sqliteVdbeCurrentAddr(v) + 2;
+      sqliteVdbeAddOp(v, op, 0, dest, 0, 0);
+      sqliteVdbeAddOp(v, OP_AddImm, 1, 0, 0, 0);
+      break;
+    }
+  }
+  return;
+}
+
+/*
+** Generate code for a boolean expression such that a jump is made
+** to the label "dest" if the expression is true but execution
+** continues straight thru if the expression is false.
+*/
+void sqliteExprIfTrue(Parse *pParse, Expr *pExpr, int dest){
+  Vdbe *v = pParse->pVdbe;
+  int op = 0;
+  switch( pExpr->op ){
+    case TK_LT:       op = OP_Lt;       break;
+    case TK_LE:       op = OP_Le;       break;
+    case TK_GT:       op = OP_Gt;       break;
+    case TK_GE:       op = OP_Ge;       break;
+    case TK_NE:       op = OP_Ne;       break;
+    case TK_EQ:       op = OP_Eq;       break;
+    case TK_ISNULL:   op = OP_IsNull;   break;
+    case TK_NOTNULL:  op = OP_NotNull;  break;
+    default:  break;
+  }
+  switch( pExpr->op ){
+    case TK_AND: {
+      int d2 = sqliteVdbeMakeLabel(v);
+      sqliteExprIfFalse(pParse, pExpr->pLeft, d2);
+      sqliteExprIfTrue(pParse, pExpr->pRight, dest);
+      sqliteVdbeResolveLabel(v, d2);
+      break;
+    }
+    case TK_OR: {
+      sqliteExprIfTrue(pParse, pExpr->pLeft, dest);
+      sqliteExprIfTrue(pParse, pExpr->pRight, dest);
+      break;
+    }
+    case TK_LT:
+    case TK_LE:
+    case TK_GT:
+    case TK_GE:
+    case TK_NE:
+    case TK_EQ: {
+      sqliteExprCode(pParse, pExpr->pLeft);
+      sqliteExprCode(pParse, pExpr->pRight);
+      sqliteVdbeAddOp(v, op, 0, dest, 0, 0);
+      break;
+    }
+    case TK_ISNULL:
+    case TK_NOTNULL: {
+      sqliteExprCode(pParse, pExpr->pLeft);
+      sqliteVdbeAddOp(v, op, 0, dest, 0, 0);
+      break;
+    }
+    default: {
+      sqliteExprCode(pParse, pExpr);
+      sqliteVdbeAddOp(v, OP_If, 0, dest, 0, 0);
+      break;
+    }
+  }
+}
+
+/*
+** Generate code for boolean expression such that a jump is made
+** to the label "dest" if the expression is false but execution
+** continues straight thru if the expression is true.
+*/
+void sqliteExprIfFalse(Parse *pParse, Expr *pExpr, int dest){
+  Vdbe *v = pParse->pVdbe;
+  int op = 0;
+  switch( pExpr->op ){
+    case TK_LT:       op = OP_Ge;       break;
+    case TK_LE:       op = OP_Gt;       break;
+    case TK_GT:       op = OP_Le;       break;
+    case TK_GE:       op = OP_Lt;       break;
+    case TK_NE:       op = OP_Eq;       break;
+    case TK_EQ:       op = OP_Ne;       break;
+    case TK_ISNULL:   op = OP_NotNull;  break;
+    case TK_NOTNULL:  op = OP_IsNull;   break;
+    default:  break;
+  }
+  switch( pExpr->op ){
+    case TK_AND: {
+      sqliteExprIfFalse(pParse, pExpr->pLeft, dest);
+      sqliteExprIfFalse(pParse, pExpr->pRight, dest);
+      break;
+    }
+    case TK_OR: {
+      int d2 = sqliteVdbeMakeLabel(v);
+      sqliteExprIfTrue(pParse, pExpr->pLeft, d2);
+      sqliteExprIfFalse(pParse, pExpr->pRight, dest);
+      sqliteVdbeResolveLabel(v, d2);
+      break;
+    }
+    case TK_LT:
+    case TK_LE:
+    case TK_GT:
+    case TK_GE:
+    case TK_NE:
+    case TK_EQ: {
+      sqliteExprCode(pParse, pExpr->pLeft);
+      sqliteExprCode(pParse, pExpr->pRight);
+      sqliteVdbeAddOp(v, op, 0, dest, 0, 0);
+      break;
+    }
+    case TK_ISNULL:
+    case TK_NOTNULL: {
+      sqliteExprCode(pParse, pExpr->pLeft);
+      sqliteVdbeAddOp(v, op, 0, dest, 0, 0);
+      break;
+    }
+    default: {
+      sqliteExprCode(pParse, pExpr);
+      sqliteVdbeAddOp(v, OP_Not, 0, 0, 0, 0);
+      sqliteVdbeAddOp(v, OP_If, 0, dest, 0, 0);
+      break;
+    }
+  }
+}
diff --git a/tool/gdbmdump.c b/tool/gdbmdump.c
new file mode 100644 (file)
index 0000000..4385355
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+** Copyright (c) 1999, 2000 D. Richard Hipp
+**
+** 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 library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*************************************************************************
+** A utility to dump the entire contents of a GDBM table in a 
+** readable format.
+*/
+#include <stdio.h>
+#include <ctype.h>
+#include <gdbm.h>
+#include <stdlib.h>
+
+static void print_data(char *zPrefix, datum p){
+  int i, j;
+
+  printf("%-5s: ", zPrefix);
+  for(i=0; i<p.dsize; i+=20){
+    for(j=i; j<p.dsize && j<i+20; j++){
+      printf("%02x", 0xff & p.dptr[j]);
+      if( (j&3)==3 ) printf(" ");
+    }
+    while( j<i+20 ){
+      printf("  ");
+      if( (j&3)==3 ) printf(" ");
+      j++;
+    }
+    printf(" ");
+    for(j=i; j<p.dsize && j<i+20; j++){
+      int c = p.dptr[j];
+      if( !isprint(c) ){ c = '.'; }
+      putchar(c);
+    }
+    printf("\n");
+    if( i+20<p.dsize ) printf("       ");
+  }
+}
+
+static int gdbm_dump(char *zFilename){
+  GDBM_FILE p;
+  datum data, key, next;
+
+  p = gdbm_open(zFilename, 0, GDBM_READER, 0, 0);
+  if( p==0 ){
+    fprintf(stderr,"can't open file \"%s\"\n", zFilename);
+    return 1;
+  }
+  key = gdbm_firstkey(p);
+  while( key.dptr ){
+    print_data("key",key);
+    data = gdbm_fetch(p, key);
+    if( data.dptr ){
+      print_data("data",data);
+      free( data.dptr );
+    }
+    next = gdbm_nextkey(p, key);
+    free( key.dptr );
+    key = next;
+    printf("\n");
+  }
+  gdbm_close(p);
+  return 0;
+}
+
+int main(int argc, char **argv){
+  int i;
+  int nErr = 0;
+  for(i=1; i<argc; i++){
+    nErr += gdbm_dump(argv[i]);
+  }
+  return nErr;
+}
diff --git a/tool/lemon.c b/tool/lemon.c
new file mode 100644 (file)
index 0000000..ce52242
--- /dev/null
@@ -0,0 +1,4021 @@
+/*
+** Copyright (c) 1991, 1994, 1997, 1998 D. Richard Hipp
+**
+** 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 as part of another
+** program.
+**
+** 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 library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@acm.org
+**   http://www.hwaci.com/drh/
+*/
+#include <stdio.h>
+#include <varargs.h>
+#include <string.h>
+#include <ctype.h>
+
+extern void qsort();
+extern double strtod();
+extern long strtol();
+extern void free();
+extern int access();
+extern int atoi();
+
+#ifndef __WIN32__
+#   if defined(_WIN32) || defined(WIN32)
+#      define __WIN32__
+#   endif
+#endif
+
+/* #define PRIVATE static */
+#define PRIVATE
+
+#ifdef TEST
+#define MAXRHS 5       /* Set low to exercise exception code */
+#else
+#define MAXRHS 1000
+#endif
+
+char *msort();
+extern void *malloc();
+
+/******** From the file "action.h" *************************************/
+struct action *Action_new();
+struct action *Action_sort();
+void Action_add();
+
+/********* From the file "assert.h" ************************************/
+void myassert();
+#ifndef NDEBUG
+#  define assert(X) if(!(X))myassert(__FILE__,__LINE__)
+#else
+#  define assert(X)
+#endif
+
+/********** 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( /* char *, int, 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 * */);
+
+/********** 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 {FALSE=0, 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
+  } type;                  /* Symbols are all either TERMINALS or NTs */
+  struct rule *rule;       /* Linked list of rules of this (if an NT) */
+  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 */
+  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 */
+};
+
+/* 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 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,
+    CONFLICT,                /* 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 index;               /* Sequencial number for this state */
+  struct action *ap;       /* Array of actions for this state */
+  int naction;             /* Number of actions for this state */
+  int tabstart;            /* First index of the action table */
+  int tabdfltact;          /* Default action */
+};
+
+/* 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 */
+  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 *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 *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 */
+  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 */
+struct action *Action_new(){
+  static struct action *freelist = 0;
+  struct action *new;
+
+  if( freelist==0 ){
+    int i;
+    int amt = 100;
+    freelist = (struct action *)malloc( sizeof(struct action)*amt );
+    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 */
+static int actioncmp(ap1,ap2)
+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 ){
+    assert( ap1->type==REDUCE && ap2->type==REDUCE );
+    rc = ap1->x.rp->index - ap2->x.rp->index;
+  }
+  return rc;
+}
+
+/* Sort parser actions */
+struct action *Action_sort(ap)
+struct action *ap;
+{
+  ap = (struct action *)msort(ap,&ap->next,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;
+  }
+}
+/********************** From the file "assert.c" ****************************/
+/*
+** A more efficient way of handling assertions.
+*/
+void myassert(file,line)
+char *file;
+int line;
+{
+  fprintf(stderr,"Assertion failed on line %d of file \"%s\"\n",line,file);
+  exit(1);
+}
+/********************** 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;
+      for(i=0; i<rp->nrhs; i++){
+        if( rp->rhs[i]->prec>=0 ){
+          rp->precsym = rp->rhs[i];
+          break;
+       }
+      }
+    }
+  }
+  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;
+  struct rule *rp;
+  int progress;
+
+  for(i=0; i<lemp->nsymbol; i++){
+    lemp->symbols[i]->lambda = 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++){
+         if( rp->rhs[i]->lambda==FALSE ) break;
+      }
+      if( i==rp->nrhs ){
+        rp->lhs->lambda = 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( s1==s2 ){
+          if( s1->lambda==FALSE ) break;
+       }else{
+          progress += SetUnion(s1->firstset,s2->firstset);
+          if( s2->lambda==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 ){
+        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;
+    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->index = 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;
+}
+
+/* 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( 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" */
+    Action_add(&stp->ap,SHIFT,sp,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],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=nap){
+      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 = 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 = 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==REDUCE ){
+    spx = apx->sp;
+    spy = apy->x.rp->precsym;
+    if( spy==0 || spx->prec<0 || spy->prec<0 ){
+      /* Not enough precedence information. */
+      apy->type = CONFLICT;
+      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 = CONFLICT;
+      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 = CONFLICT;
+      errcnt++;
+    }else if( spx->prec>spy->prec ){
+      apy->type = RD_RESOLVED;
+    }else if( spx->prec<spy->prec ){
+      apx->type = RD_RESOLVED;
+    }
+  }else{
+    /* Can't happen.  Shifts have to come before Reduces on the
+    ** list because the reduces were added last.  Hence, if apx->type==REDUCE
+    ** then it is impossible for apy->type==SHIFT */
+  }
+  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 *)malloc( sizeof(struct config)*amt );
+    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 = &current;
+  basis = 0;
+  basisend = &basis;
+  Configtable_init();
+  return;
+}
+
+/* Initialized the configuration list builder */
+void Configlist_reset(){
+  current = 0;
+  currentend = &current;
+  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{
+            SetUnion(newcfp->fws,xsp->firstset);
+            if( xsp->lambda==FALSE ) break;
+         }
+       }
+        if( i==rp->nrhs ) Plink_add(&cfp->fplp,newcfp);
+      }
+    }
+  }
+  return;
+}
+
+/* Sort the configuration list */
+void Configlist_sort(){
+  current = (struct config *)msort(current,&(current->next),Configcmp);
+  currentend = 0;
+  return;
+}
+
+/* Sort the basis configuration list */
+void Configlist_sortbasis(){
+  basis = (struct config *)msort(current,&(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(va_alist)
+va_dcl
+{
+  char *filename;
+  int lineno;
+  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);
+  filename = va_arg(ap,char*);
+  lineno = va_arg(ap,int);
+  format = va_arg(ap,char*);
+  /* 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);
+}
+
+
+/* The main program.  Parse the command line and do it... */
+int main(argc,argv)
+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_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"
+       "Copyright 1991-1997 by D. Richard Hipp\n"
+       "Freely distributable under the GNU Public License.\n"
+     );
+     exit(0); 
+  }
+  if( optnargs()!=1 ){
+    fprintf(stderr,"Exactly one filename argument is required.\n");
+    exit(1);
+  }
+  lem.errorcnt = 0;
+
+  /* Initialize the machine */
+  Strsafe_init();
+  Symbol_init();
+  State_init();
+  lem.argv0 = argv[0];
+  lem.filename = optarg(0);
+  lem.basisflag = basisflag;
+  lem.nconflict = 0;
+  lem.name = lem.include = lem.arg = lem.tokentype = lem.start = 0;
+  lem.stacksize = 0;
+  lem.error = lem.overflow = lem.failure = lem.accept = lem.tokendest =
+     lem.tokenprefix = lem.outname = lem.extracode = 0;
+  lem.tablesize = 0;
+  Symbol_new("$");
+  lem.errsym = Symbol_new("error");
+
+  /* Parse the input file */
+  Parse(&lem);
+  if( lem.errorcnt ) exit(lem.errorcnt);
+  if( lem.rule==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();
+  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);
+
+    /* 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);
+
+    /* 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);
+}
+/******************** 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**)(((int)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(a,b,cmp,offset)
+char *a;
+char *b;
+int (*cmp)();
+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
+char *msort(list,next,cmp)
+char *list;
+char **next;
+int (*cmp)();
+{
+  int offset;
+  char *ep;
+  char *set[LISTSIZE];
+  int i;
+  offset = (int)next - (int)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;
+  spcnt = 0;
+  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( strcmp(&argv[i][1],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( 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],'=');
+  *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,((int)end)-(int)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,((int)end)-(int)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,
+          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,
+          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,
+          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
+  } state;                   /* The state of the parser */
+  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 *)malloc( sizeof(struct rule) + 
+             sizeof(struct symbol*)*psp->nrhs + sizeof(char*)*psp->nrhs );
+        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 symbol on RHS or 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]=='(' && 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,"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,"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{
+          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 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;
+  }
+}
+
+/* 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;
+
+  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;
+
+  /* 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,startline,
+"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{                          /* 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 *)malloc( sizeof(struct plink)*amt );
+    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);
+  fp = fopen(lemp->outname,mode);
+  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++){
+      printf(" %s",rp->rhs[i]->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;
+  int i;
+  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;
+    fprintf(fp," %s",rp->rhs[i]->name);
+  }
+}
+
+/* #define TEST */
+#ifdef TEST
+/* 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->index);
+    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->index);
+      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 CONFLICT:
+      fprintf(fp,"%*s reduce %-3d ** Parsing conflict **",
+        indent,ap->sp->name,ap->x.rp->index);
+      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","w");
+  if( fp==0 ) return;
+  fprintf(fp," \b");
+  for(i=0; i<lemp->nstate; i++){
+    stp = lemp->sorted[i];
+    fprintf(fp,"State %d:\n",stp->index);
+    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");
+#ifdef TEST
+      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");
+  }
+  fclose(fp);
+  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;
+  extern int access();
+
+#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->index;               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-(int)lemp->filename,lemp->filename);
+  }else{
+    sprintf(buf,"%s.lt",lemp->filename);
+  }
+  if( access(buf,004)==0 ){
+    tpltname = buf;
+  }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,"r");
+  if( in==0 ){
+    fprintf(stderr,"Can't open the template file \"%s\".\n",templatename);
+    lemp->errorcnt++;
+    return 0;
+  }
+  return in;
+}
+
+/* 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;
+  fprintf(out,"#line %d \"%s\"\n",strln,lemp->filename); (*lineno)++;
+  while( *str ){
+    if( *str=='\n' ) (*lineno)++;
+    putc(*str,out);
+    str++;
+  }
+  fprintf(out,"\n#line %d \"%s\"\n",*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;
+
+ int linecnt = 0;
+ if( sp->type==TERMINAL ){
+   cp = lemp->tokendest;
+   if( cp==0 ) return;
+   fprintf(out,"#line %d \"%s\"\n{",lemp->tokendestln,lemp->filename);
+ }else{
+   cp = sp->destructor;
+   if( cp==0 ) return;
+   fprintf(out,"#line %d \"%s\"\n{",sp->destructorln,lemp->filename);
+ }
+ 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#line %d \"%s\"\n",*lineno,lemp->outname);
+ return;
+}
+
+/*
+** Return TRUE (non-zero) if the given symbol has a distructor.
+*/
+int has_destructor(sp, lemp)
+struct symbol *sp;
+struct lemon *lemp;
+{
+  int ret;
+  if( sp->type==TERMINAL ){
+    ret = lemp->tokendest!=0;
+  }else{
+    ret = sp->destructor!=0;
+  }
+  return ret;
+}
+
+/* 
+** 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, *xp;
+ int linecnt = 0;
+ 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;
+
+ /* Generate code to do the reduce action */
+ if( rp->code ){
+   fprintf(out,"#line %d \"%s\"\n{",rp->line,lemp->filename);
+   for(cp=rp->code; *cp; cp++){
+     if( isalpha(*cp) && (cp==rp->code || !isalnum(cp[-1])) ){
+       char saved;
+       for(xp= &cp[1]; isalnum(*xp); xp++);
+       saved = *xp;
+       *xp = 0;
+       if( rp->lhsalias && strcmp(cp,rp->lhsalias)==0 ){
+         fprintf(out,"yygotominor.yy%d",rp->lhs->dtnum);
+         cp = xp;
+         lhsused = 1;
+       }else{
+         for(i=0; i<rp->nrhs; i++){
+           if( rp->rhsalias[i] && strcmp(cp,rp->rhsalias[i])==0 ){
+             fprintf(out,"yymsp[%d].minor.yy%d",i-rp->nrhs+1,rp->rhs[i]->dtnum);
+             cp = xp;
+             used[i] = 1;
+             break;
+           }
+         }
+       }
+       *xp = saved;
+     }
+     if( *cp=='\n' ) linecnt++;
+     fputc(*cp,out);
+   } /* End loop */
+   (*lineno) += 3 + linecnt;
+   fprintf(out,"}\n#line %d \"%s\"\n",*lineno,lemp->outname);
+ } /* End if( rp->code ) */
+
+ /* 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) ){
+       fprintf(out,"  yy_destructor(%d,&yymsp[%d].minor);\n",
+          rp->rhs[i]->index,i-rp->nrhs+1); (*lineno)++;
+     }else{
+       fprintf(out,"        /* No destructor defined for %s */\n",
+        rp->rhs[i]->name);
+        (*lineno)++;
+     }
+   }
+ }
+ 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**)malloc( arraysize * sizeof(char*) );
+  for(i=0; i<arraysize; i++) types[i] = 0;
+  maxdtlength = 0;
+  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 and for nonterminals which don't 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 ){
+      sp->dtnum = 0;
+      continue;
+    }
+    cp = sp->datatype;
+    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];
+    }
+    if( hash<0 ) hash = -hash;
+    hash = hash%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]);
+  }
+  fprintf(out,"  int yy%d;\n",lemp->errsym->dtnum); lineno++;
+  free(stddt);
+  free(types);
+  fprintf(out,"} YYMINORTYPE;\n"); lineno++;
+  *plineno = lineno;
+}
+
+/* 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;
+  int i;
+  int tablecnt;
+  char *name;
+
+  in = tplt_open(lemp);
+  if( in==0 ) return;
+  out = file_open(lemp,".c","w");
+  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,"/* \001 */\n");
+  fprintf(out,"#define YYCODETYPE %s\n",
+    lemp->nsymbol>250?"int":"unsigned char");  lineno++;
+  fprintf(out,"#define YYNOCODE %d\n",lemp->nsymbol+1);  lineno++;
+  fprintf(out,"#define YYACTIONTYPE %s\n",
+    lemp->nstate+lemp->nrule>250?"int":"unsigned char");  lineno++;
+  print_stack_union(out,lemp,&lineno,mhflag);
+  if( lemp->stacksize ){
+    if( atoi(lemp->stacksize)<=0 ){
+      ErrorMsg(lemp->filename,0,
+"Illegal stack size: [%s].  The stack size should be an integer constant.",
+        lemp->stacksize);
+      lemp->errorcnt++;
+      lemp->stacksize = "100";
+    }
+    fprintf(out,"#define YYSTACKDEPTH %s\n",lemp->stacksize);  lineno++;
+  }else{
+    fprintf(out,"#define YYSTACKDEPTH 100\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 && isalnum(lemp->arg[i-1]) ) i--;
+    fprintf(out,"#define %sARGDECL ,%s\n",name,&lemp->arg[i]);  lineno++;
+    fprintf(out,"#define %sXARGDECL %s;\n",name,lemp->arg);  lineno++;
+    fprintf(out,"#define %sANSIARGDECL ,%s\n",name,lemp->arg);  lineno++;
+  }else{
+    fprintf(out,"#define %sARGDECL\n",name);  lineno++;
+    fprintf(out,"#define %sXARGDECL\n",name);  lineno++;
+    fprintf(out,"#define %sANSIARGDECL\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++;
+  fprintf(out,"#define YYERRORSYMBOL %d\n",lemp->errsym->index);  lineno++;
+  fprintf(out,"#define YYERRSYMDT yy%d\n",lemp->errsym->dtnum);  lineno++;
+  tplt_xfer(lemp->name,in,out,&lineno);
+
+  /* Generate the action table.
+  **
+  ** Each entry in the action table is an element of the following 
+  ** structure:
+  **   struct yyActionEntry {
+  **       YYCODETYPE            lookahead;
+  **       YYACTIONTYPE          action;
+  **       struct yyActionEntry *next;
+  **   }
+  **
+  ** The entries are grouped into hash tables, one hash table for each
+  ** parser state.  The hash table has a size which is the smallest
+  ** power of two needed to hold all entries.
+  */
+  tablecnt = 0;
+
+  /* Loop over parser states */
+  for(i=0; i<lemp->nstate; i++){
+    int tablesize;              /* size of the hash table */
+    int j,k;                    /* Loop counter */
+    int collide[2048];          /* The collision chain for the table */
+    struct action *table[2048]; /* Build the hash table here */
+
+    /* Find the number of actions and initialize the hash table */
+    stp = lemp->sorted[i];
+    stp->tabstart = tablecnt;
+    stp->naction = 0;
+    for(ap=stp->ap; ap; ap=ap->next){
+      if( ap->sp->index!=lemp->nsymbol && compute_action(lemp,ap)>=0 ){
+        stp->naction++;
+      }
+    }
+    tablesize = 1;
+    while( tablesize<stp->naction ) tablesize += tablesize;
+    assert( tablesize<= sizeof(table)/sizeof(table[0]) );
+    for(j=0; j<tablesize; j++){
+      table[j] = 0;
+      collide[j] = -1;
+    }
+
+    /* Hash the actions into the hash table */
+    stp->tabdfltact = lemp->nstate + lemp->nrule;
+    for(ap=stp->ap; ap; ap=ap->next){
+      int action = compute_action(lemp,ap);
+      int h;
+      if( ap->sp->index==lemp->nsymbol ){
+        stp->tabdfltact = action;
+      }else if( action>=0 ){
+        h = ap->sp->index & (tablesize-1);
+        ap->collide = table[h];
+        table[h] = ap;
+      }
+    }
+
+    /* Resolve collisions */
+    for(j=k=0; j<tablesize; j++){
+      if( table[j] && table[j]->collide ){
+        while( table[k] ) k++;
+        table[k] = table[j]->collide;
+        collide[j] = k;
+        table[j]->collide = 0;
+        if( k<j ) j = k-1;
+      }
+    }
+
+    /* Print the hash table */
+    fprintf(out,"/* State %d */\n",stp->index); lineno++;
+    for(j=0; j<tablesize; j++){
+      if( table[j]==0 ){
+        fprintf(out,
+          "  {YYNOCODE,0,0}, /* Unused */\n");
+      }else{
+        fprintf(out,"  {%4d,%4d, ",
+          table[j]->sp->index,
+          compute_action(lemp,table[j]));
+        if( collide[j]>=0 ){
+          fprintf(out,"&yyActionTable[%4d] }, /* ",
+            collide[j] + tablecnt);
+        }else{
+          fprintf(out,"0                    }, /* ");
+        }
+        PrintAction(table[j],out,22);
+        fprintf(out," */\n"); 
+      }
+      lineno++;
+    }
+
+    /* Update the table count */
+    tablecnt += tablesize;
+  }
+  tplt_xfer(lemp->name,in,out,&lineno);
+  lemp->tablesize = tablecnt;
+
+  /* Generate the state table
+  **
+  ** Each entry is an element of the following structure:
+  **    struct yyStateEntry {
+  **      struct yyActionEntry *hashtbl;
+  **      int mask;
+  **      YYACTIONTYPE actionDefault;
+  **    }
+  */
+  for(i=0; i<lemp->nstate; i++){
+    int tablesize;
+    stp = lemp->sorted[i];
+    tablesize = 1;
+    while( tablesize<stp->naction ) tablesize += tablesize;
+    fprintf(out,"  { &yyActionTable[%d], %d, %d},\n",
+      stp->tabstart,
+      tablesize - 1,
+      stp->tabdfltact); 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 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:\n",sp->index); 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++;
+    }
+  }
+  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:\n",sp->index); lineno++;
+    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){
+    fprintf(out,"      case %d:\n",rp->index); lineno++;
+    fprintf(out,"        YYTRACE(\"%s ::=",rp->lhs->name);
+    for(i=0; i<rp->nrhs; i++) fprintf(out," %s",rp->rhs[i]->name);
+    fprintf(out,"\")\n"); lineno++;
+    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);
+  fclose(out);
+  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","r");
+  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","w");
+  if( out ){
+    for(i=1; i<lemp->nterminal; i++){
+      fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i);
+    }
+    fclose(out);  
+  }
+  return;
+}
+
+/* Reduce the size of the action tables, if possible, by making use
+** of defaults.
+**
+** In this version, if all REDUCE actions use the same rule, make
+** them the default.  Only default them if there are more than one.
+*/
+void CompressTables(lemp)
+struct lemon *lemp;
+{
+  struct state *stp;
+  struct action *ap;
+  struct rule *rp;
+  int i;
+  int cnt;
+
+  for(i=0; i<lemp->nstate; i++){
+    stp = lemp->sorted[i];
+
+    /* Find the first REDUCE action */
+    for(ap=stp->ap; ap && ap->type!=REDUCE; ap=ap->next);
+    if( ap==0 ) continue;
+
+    /* Remember the rule used */
+    rp = ap->x.rp;
+
+    /* See if all other REDUCE acitons use the same rule */
+    cnt = 1;
+    for(ap=ap->next; ap; ap=ap->next){
+      if( ap->type==REDUCE ){
+        if( ap->x.rp!=rp ) break;
+        cnt++;
+      }
+    }
+    if( ap || cnt==1 ) continue;
+
+    /* Combine all REDUCE actions into a single default */
+    for(ap=stp->ap; ap && ap->type!=REDUCE; ap=ap->next);
+    assert( ap );
+    ap->sp = Symbol_new("{default}");
+    for(ap=ap->next; ap; ap=ap->next){
+      if( ap->type==REDUCE ) ap->type = NOT_USED;
+    }
+    stp->ap = Action_sort(stp->ap);
+  }
+}
+/***************** 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;
+  int i;
+  s = (char*)malloc( size );
+  if( s==0 ){
+    extern void memory_error();
+    memory_error();
+  }
+  for(i=0; i<size; i++) s[i] = 0;
+  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;
+  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;
+
+  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 *)malloc( sizeof(struct symbol) );
+    MemoryCheck(sp);
+    sp->name = Strsafe(x);
+    sp->type = isupper(*x) ? TERMINAL : NONTERMINAL;
+    sp->rule = 0;
+    sp->prec = -1;
+    sp->assoc = UNK;
+    sp->firstset = 0;
+    sp->lambda = FALSE;
+    sp->destructor = 0;
+    sp->datatype = 0;
+    Symbol_insert(sp,sp->name);
+  }
+  return sp;
+}
+
+/* Compare two symbols */
+int Symbolcmpp(a,b)
+struct symbol **a;
+struct symbol **b;
+{
+  return strcmp((**a).name,(**b).name);
+}
+
+/* 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 **)malloc( sizeof(struct symbol *)*size );
+  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 *)malloc( 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;
+}
diff --git a/tool/lempar.c b/tool/lempar.c
new file mode 100644 (file)
index 0000000..e5293b1
--- /dev/null
@@ -0,0 +1,606 @@
+/* Driver template for the LEMON parser generator.
+** Copyright 1991-1995 by D. Richard Hipp.
+*
+* This version is specially modified for use with sqlite.
+* @(#) $Id: lempar.c,v 1.1 2000/05/29 14:26:02 drh Exp $
+*
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+** 
+** This library 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
+** Library General Public License for more details.
+** 
+** You should have received a copy of the GNU Library General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Modified 1997 to make it suitable for use with makeheaders.
+*/
+/* 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.
+**    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.
+**    ParseARGDECL       is a declaration of a 3rd argument to the
+**                       parser, or null if there is no extra argument.
+**    ParseKRARGDECL     A version of ParseARGDECL for K&R C.
+**    ParseANSIARGDECL   A version of ParseARGDECL for ANSI C.
+**    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 is the action table.  Each entry in this table contains
+**
+**  +  An integer which is the number representing the look-ahead
+**     token
+**
+**  +  An integer indicating what action to take.  Number (N) between
+**     0 and YYNSTATE-1 mean shift the look-ahead and go to state N.
+**     Numbers between YYNSTATE and YYNSTATE+YYNRULE-1 mean reduce by
+**     rule N-YYNSTATE.  Number YYNSTATE+YYNRULE means that a syntax
+**     error has occurred.  Number YYNSTATE+YYNRULE+1 means the parser
+**     accepts its input.
+**
+**  +  A pointer to the next entry with the same hash value.
+**
+** The action table is really a series of hash tables.  Each hash
+** table contains a number of entries which is a power of two.  The
+** "state" table (which follows) contains information about the starting
+** point and size of each hash table.
+*/
+struct yyActionEntry {
+  YYCODETYPE   lookahead;   /* The value of the look-ahead token */
+  YYACTIONTYPE action;      /* Action to take for this look-ahead */
+  struct yyActionEntry *next; /* Next look-ahead with the same hash, or NULL */
+};
+static struct yyActionEntry yyActionTable[] = {
+%%
+};
+
+/* The state table contains information needed to look up the correct
+** action in the action table, given the current state of the parser.
+** Information needed includes:
+**
+**  +  A pointer to the start of the action hash table in yyActionTable.
+**
+**  +  A mask used to hash the look-ahead token.  The mask is an integer
+**     which is one less than the size of the hash table.  
+**
+**  +  The default action.  This is the action to take if no entry for
+**     the given look-ahead is found in the action hash table.
+*/
+struct yyStateEntry {
+  struct yyActionEntry *hashtbl; /* Start of the hash table in yyActionTable */
+  int mask;                      /* Mask used for hashing the look-ahead */
+  YYACTIONTYPE actionDefault;    /* Default action if look-ahead not found */
+};
+static struct yyStateEntry yyStateTable[] = {
+%%
+};
+
+/* 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  */
+};
+
+/* The state of the parser is completely contained in an instance of
+** the following structure */
+struct yyParser {
+  int idx;                            /* Index of top element in stack */
+  int errcnt;                         /* Shifts left before out of the error */
+  struct yyStackEntry *top;           /* Pointer to the top stack element */
+  struct yyStackEntry stack[YYSTACKDEPTH];  /* The parser's stack */
+};
+typedef struct yyParser yyParser;
+
+#ifndef NDEBUG
+#include <stdio.h>
+static FILE *yyTraceFILE = 0;
+static char *yyTracePrompt = 0;
+
+/* 
+** 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.
+*/
+/* SQLITE MODIFICATION: Give the function file scope */
+void ParseTrace(FILE *TraceFILE, char *zTracePrompt){
+  yyTraceFILE = TraceFILE;
+  yyTracePrompt = zTracePrompt;
+  if( yyTraceFILE==0 ) yyTracePrompt = 0;
+  else if( yyTracePrompt==0 ) yyTraceFILE = 0;
+}
+
+/* For tracing shifts, the names of all terminals and nonterminals
+** are required.  The following table supplies these names */
+static char *yyTokenName[] = { 
+%%
+};
+#define YYTRACE(X) if( yyTraceFILE ) fprintf(yyTraceFILE,"%sReduce [%s].\n",yyTracePrompt,X);
+#else
+#define YYTRACE(X)
+#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.
+*/
+/* SQLITE MODIFICATION: Give the function file scope */
+void *ParseAlloc(void *(*mallocProc)()){
+  yyParser *pParser;
+  pParser = (yyParser*)(*mallocProc)( sizeof(yyParser), __FILE__, __LINE__ );
+  if( pParser ){
+    pParser->idx = -1;
+  }
+  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;
+
+  if( pParser->idx<0 ) return 0;
+#ifndef NDEBUG
+  if( yyTraceFILE && pParser->idx>=0 ){
+    fprintf(yyTraceFILE,"%sPopping %s\n",
+      yyTracePrompt,
+      yyTokenName[pParser->top->major]);
+  }
+#endif
+  yymajor = pParser->top->major;
+  yy_destructor( yymajor, &pParser->top->minor);
+  pParser->idx--;
+  pParser->top--;
+  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>
+*/
+/* SQLITE MODIFICATION: Give the function file scope */
+void ParseFree(
+  void *p,               /* The parser to be deleted */
+  void (*freeProc)()     /* Function used to reclaim memory */
+){
+  yyParser *pParser = (yyParser*)p;
+  if( pParser==0 ) return;
+  while( pParser->idx>=0 ) yy_pop_parser_stack(pParser);
+  (*freeProc)(pParser, __FILE__, __LINE__);
+}
+
+/*
+** Find the appropriate action for a parser given the look-ahead token.
+**
+** 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_parser_action(
+  yyParser *pParser,        /* The parser */
+  int iLookAhead             /* The look-ahead token */
+){
+  struct yyStateEntry *pState;   /* Appropriate entry in the state table */
+  struct yyActionEntry *pAction; /* Action appropriate for the look-ahead */
+  /* if( pParser->idx<0 ) return YY_NO_ACTION;  */
+  pState = &yyStateTable[pParser->top->stateno];
+  if( iLookAhead!=YYNOCODE ){
+    pAction = &pState->hashtbl[iLookAhead & pState->mask];
+    while( pAction ){
+      if( pAction->lookahead==iLookAhead ) return pAction->action;
+      pAction = pAction->next;
+    }
+  }else if( pState->mask!=0 || pState->hashtbl->lookahead!=YYNOCODE ){
+    return YY_NO_ACTION;
+  }
+  return pState->actionDefault;
+}
+
+/*
+** 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 */
+){
+  yypParser->idx++;
+  yypParser->top++;
+  if( yypParser->idx>=YYSTACKDEPTH ){
+     yypParser->idx--;
+     yypParser->top--;
+#ifndef NDEBUG
+     if( yyTraceFILE ){
+       fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
+     }
+#endif
+     while( yypParser->idx>=0 ) yy_pop_parser_stack(yypParser);
+     /* Here code is inserted which will execute if the parser
+     ** stack every overflows */
+%%
+     return;
+  }
+  yypParser->top->stateno = yyNewState;
+  yypParser->top->major = yyMajor;
+  yypParser->top->minor = *yypMinor;
+#ifndef NDEBUG
+  if( yyTraceFILE && yypParser->idx>0 ){
+    int i;
+    fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
+    fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
+    for(i=1; i<=yypParser->idx; i++)
+      fprintf(yyTraceFILE," %s",yyTokenName[yypParser->stack[i].major]);
+    fprintf(yyTraceFILE,"\n");
+  }
+#endif
+}
+
+/* The following table contains information about every rule that
+** is used during the reduce.
+*/
+static 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();  /* 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 */
+  ParseANSIARGDECL
+){
+  int yygoto;                     /* The next state */
+  int yyact;                      /* The next action */
+  YYMINORTYPE yygotominor;        /* The LHS of the rule reduced */
+  struct yyStackEntry *yymsp;     /* The top of the parser's stack */
+  int yysize;                     /* Amount to pop the stack */
+  yymsp = yypParser->top;
+  switch( yyruleno ){
+  /* Beginning here are the reduction cases.  A typical example
+  ** follows:
+  **   case 0:
+  **     YYTRACE("<text of the rule>");
+  **  #line <lineno> <grammarfile>
+  **     { ... }           // User supplied code
+  **  #line <lineno> <thisfile>
+  **     break;
+  */
+%%
+  };
+  yygoto = yyRuleInfo[yyruleno].lhs;
+  yysize = yyRuleInfo[yyruleno].nrhs;
+  yypParser->idx -= yysize;
+  yypParser->top -= yysize;
+  yyact = yy_find_parser_action(yypParser,yygoto);
+  if( yyact < YYNSTATE ){
+    yy_shift(yypParser,yyact,yygoto,&yygotominor);
+  }else if( yyact == YYNSTATE + YYNRULE + 1 ){
+    yy_accept(yypParser ParseARGDECL);
+  }
+}
+
+/*
+** The following code executes when the parse fails
+*/
+static void yy_parse_failed(
+  yyParser *yypParser           /* The parser */
+  ParseANSIARGDECL              /* Extra arguments (if any) */
+){
+#ifndef NDEBUG
+  if( yyTraceFILE ){
+    fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
+  }
+#endif
+  while( yypParser->idx>=0 ) yy_pop_parser_stack(yypParser);
+  /* Here code is inserted which will be executed whenever the
+  ** parser fails */
+%%
+}
+
+/*
+** 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 */
+  ParseANSIARGDECL               /* Extra arguments (if any) */
+){
+#define TOKEN (yyminor.yy0)
+%%
+}
+
+/*
+** The following is executed when the parser accepts
+*/
+static void yy_accept(
+  yyParser *yypParser           /* The parser */
+  ParseANSIARGDECL              /* Extra arguments (if any) */
+){
+#ifndef NDEBUG
+  if( yyTraceFILE ){
+    fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
+  }
+#endif
+  while( yypParser->idx>=0 ) yy_pop_parser_stack(yypParser);
+  /* Here code is inserted which will be executed whenever the
+  ** parser accepts */
+%%
+}
+
+/* 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.
+*/
+/* SQLITE MODIFICATION: Give the function file scope */
+void Parse(
+  void *yyp,                   /* The parser */
+  int yymajor,                 /* The major token code number */
+  ParseTOKENTYPE yyminor       /* The value for the token */
+  ParseANSIARGDECL
+){
+  YYMINORTYPE yyminorunion;
+  int yyact;            /* The parser action. */
+  int yyendofinput;     /* True if we are at the end of input */
+  int yyerrorhit = 0;   /* True if yymajor has invoked an error */
+  yyParser *yypParser;  /* The parser */
+
+  /* (re)initialize the parser, if necessary */
+  yypParser = (yyParser*)yyp;
+  if( yypParser->idx<0 ){
+    if( yymajor==0 ) return;
+    yypParser->idx = 0;
+    yypParser->errcnt = -1;
+    yypParser->top = &yypParser->stack[0];
+    yypParser->top->stateno = 0;
+    yypParser->top->major = 0;
+  }
+  yyminorunion.yy0 = yyminor;
+  yyendofinput = (yymajor==0);
+
+#ifndef NDEBUG
+  if( yyTraceFILE ){
+    fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]);
+  }
+#endif
+
+  do{
+    yyact = yy_find_parser_action(yypParser,yymajor);
+    if( yyact<YYNSTATE ){
+      yy_shift(yypParser,yyact,yymajor,&yyminorunion);
+      yypParser->errcnt--;
+      if( yyendofinput && yypParser->idx>=0 ){
+        yymajor = 0;
+      }else{
+        yymajor = YYNOCODE;
+      }
+    }else if( yyact < YYNSTATE + YYNRULE ){
+      yy_reduce(yypParser,yyact-YYNSTATE ParseARGDECL);
+    }else if( yyact == YY_ERROR_ACTION ){
+#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->errcnt<0 ){
+        yy_syntax_error(yypParser,yymajor,yyminorunion ParseARGDECL);
+      }
+      if( yypParser->top->major==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->idx >= 0 &&
+          yypParser->top->major != YYERRORSYMBOL &&
+          (yyact = yy_find_parser_action(yypParser,YYERRORSYMBOL)) >= YYNSTATE
+        ){
+          yy_pop_parser_stack(yypParser);
+        }
+        if( yypParser->idx < 0 || yymajor==0 ){
+          yy_destructor(yymajor,&yyminorunion);
+          yy_parse_failed(yypParser ParseARGDECL);
+          yymajor = YYNOCODE;
+        }else if( yypParser->top->major!=YYERRORSYMBOL ){
+          YYMINORTYPE u2;
+          u2.YYERRSYMDT = 0;
+          yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
+        }
+      }
+      yypParser->errcnt = 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->errcnt<=0 ){
+        yy_syntax_error(yypParser,yymajor,yyminorunion ParseARGDECL);
+      }
+      yypParser->errcnt = 3;
+      yy_destructor(yymajor,&yyminorunion);
+      if( yyendofinput ){
+        yy_parse_failed(yypParser ParseARGDECL);
+      }
+      yymajor = YYNOCODE;
+#endif
+    }else{
+      yy_accept(yypParser ParseARGDECL);
+      yymajor = YYNOCODE;
+    }
+  }while( yymajor!=YYNOCODE && yypParser->idx>=0 );
+  return;
+}
diff --git a/tool/opNames.awk b/tool/opNames.awk
new file mode 100644 (file)
index 0000000..1150c5a
--- /dev/null
@@ -0,0 +1,23 @@
+# Read the sqliteVdbe.h file and generate a table of opcode names.
+#
+BEGIN {
+  printf "static char *zOpName[] = { 0,\n"
+  n = 0
+}
+/^#define OP_MAX/ {
+  next
+}
+/^#define OP_/ {
+  name = "\"" substr($2,4) "\","
+  if( n<3 ){
+    printf "  %-16s", name
+    n++
+  } else {
+    printf "  %s\n", name
+    n = 0
+  }
+}
+END {
+  if( n ){ printf "\n" }
+  printf "};\n"
+}
diff --git a/tool/opcodeDoc.awk b/tool/opcodeDoc.awk
new file mode 100644 (file)
index 0000000..4920106
--- /dev/null
@@ -0,0 +1,23 @@
+#
+# Extract opcode documentation for sqliteVdbe.c and generate HTML
+#
+BEGIN {
+  print "<html><body bgcolor=white>"
+  print "<h1>SQLite Virtual Database Engine Opcodes</h1>"
+  print "<table>"
+}
+/ Opcode: /,/\*\// {
+  if( $2=="Opcode:" ){
+    printf "<tr><td>%s&nbsp;%s&nbsp;%s&nbsp;%s</td>\n<td>\n", $3, $4, $5, $6
+  }else if( $1=="*/" ){
+    printf "</td></tr>\n"
+  }else if( NF>1 ){
+    sub(/^ *\*\* /,"")
+    gsub(/</,"&lt;")
+    gsub(/&/,"&amp;")
+    print
+  }
+}
+END {
+  print "</table></body></html>"
+}
diff --git a/tool/renumberOps.awk b/tool/renumberOps.awk
new file mode 100644 (file)
index 0000000..098c4d8
--- /dev/null
@@ -0,0 +1,12 @@
+# Run this script on sqliteVdbe.h to renumber the opcodes sequentially.
+#
+BEGIN { cnt = 1 }
+/^#define OP_MAX/ {
+  printf "#define %-20s %3d\n",$2, cnt-1
+  next
+}
+/^#define OP_/ {
+  printf "#define %-20s %3d\n",$2, cnt++
+  next
+}
+{ print }